HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
IMX_VDB.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: IMX_VDB.h
7  *
8  * COMMENTS:
9  * Holder for NanoVDBs, either on GPU or CPU
10  */
11 
12 #ifndef __IMX_VDB_h__
13 #define __IMX_VDB_h__
14 
15 #include "IMX_API.h"
16 #include "IMX_Types.h"
17 
18 #include <CE/CE_HotSwapPoolEntry.h>
19 #include <CE/CE_BufferHost.h>
20 
21 #include <GA/GA_PrimVolumeXform.h>
22 #include <CE/CE_VDBGrid.h>
23 #include <UT/UT_Lock.h>
24 #include <UT/UT_SharedPtr.h>
25 #include <UT/UT_UniquePtr.h>
26 #include <UT/UT_Options.h>
27 #include <SYS/SYS_AtomicInt.h>
28 
29 #include <openvdb/Platform.h>
30 #include <openvdb/openvdb.h>
31 
32 
33 class IMX_VDB;
36 
38 {
39 public:
40  /// An un-allocated null-VDB, but with default meta data.
41  IMX_VDB();
42 
43  IMX_VDB(const IMX_VDB &other) { copy(other); }
44  IMX_VDB(IMX_VDB && other) noexcept { swap(other); }
45 
46  ~IMX_VDB() override;
47 
48  EntryType poolTypeID() const override { return EntryType::VDB; }
49 
50  /// Assignment operators
51  void copy(const IMX_VDB &other);
52  IMX_VDB &operator=(const IMX_VDB &other) { copy(other); return *this; }
53 
54  void swap(IMX_VDB &other);
55  IMX_VDB &operator=(IMX_VDB &&other) { swap(other); return *this; }
56 
57  /// Conversion to/from openvdb.
58  /// Can throw CE exceptions.
59  openvdb::GridBase::Ptr createVDB() const;
60 
61  /// Returns true for successful save.
62  bool save(std::ostream &os) const;
63  bool saveJSON(UT_JSONWriter &w) const;
64 
65  /// Returns a newly created VDB loaded from the stream, or null
66  /// if load failure.
67  static IMX_VDBPtr load(UT_IStream &is);
68  static IMX_VDBPtr loadJSON(UT_JSONParser &p);
69 
70  /// Write our fields into the provided options:
71  /// THis does not include properties.
72  void copyMetadataToOptions(UT_Options &opt) const;
73  /// Load ourselves from the options, ignoring fields we don't know
74  void updateMetadataFromOptions(const UT_Options &opt);
75 
76  /// Copies a VDB into ourselves, creating both CPU and GPU buffers
77  /// by default.
78  /// Can throw CE exceptions.
79  void copyFromVDB(const openvdb::GridBase &vdb,
80  const UT_Vector3 &voxelsize,
81  const GA_PrimVolumeXform &indexspace,
82  bool ontocpu=true, bool ontogppu=true);
83  void cpuCopyFromVDB(const openvdb::GridBase &vdb,
84  const UT_Vector3 &voxelsize,
85  const GA_PrimVolumeXform &indexspace)
86  { copyFromVDB(vdb, voxelsize, indexspace, true, false); }
87  void gpuCopyFromVDB(const openvdb::GridBase &vdb,
88  const UT_Vector3 &voxelsize,
89  const GA_PrimVolumeXform &indexspace)
90  { copyFromVDB(vdb, voxelsize, indexspace, false, true); }
91 
92  /// Replaces self with a vdb using the provided source's
93  /// topology.
94  /// If same type this is just a copy(). Otherewise it is zeroed.
95  /// Copies transform & metadata options.
96  void buildFromTopology(UT_VDBType storage,
97  const IMX_VDB *refvdb);
98 
99  /// Returns this vdb's GPU storage object. If read is true, isDirty must
100  /// be false. If write is true then it turns off isDirty by setting
101  /// isOnGPU() and turning off isOnCPU() (it is assuming caller will actually
102  /// write the buffer)
103  /// When using one of these methods, this buffer must be guarded with the
104  /// in-use GPU flag. See setInUseGPUFlag() documentation for more
105  /// information.
106  /// Can throw CE exceptions.
107  CE_VDBGrid *getGPUBuffer(bool read, bool write);
108  const CE_VDBGrid *getGPUBufferR() const;
109  CE_VDBGrid *getGPUBufferW() { return getGPUBuffer(false, true); }
110 
111  UT_VDBType storageType() const { return myStorageType; }
112  int getChannels() const;
113  bool storesIntegers() const;
114  static const char *cnanovdbStorageDefine(UT_VDBType storagetype);
115 
116  void setTypeInfo(IMX_TypeInfo typeinfo) { myTypeInfo = typeinfo; }
117  IMX_TypeInfo typeInfo() const { return myTypeInfo; }
118 
119 
120  UT_Vector3 voxelSize() const { return myVoxelSize; }
121  UT_Vector3 origin() const { return myIndexSpace.myCenter; }
122  GA_PrimVolumeXform indexSpace() const { return myIndexSpace; }
123 
124  /// True if the two vdbs map the same indices to the same positions.
125  bool isAligned(const IMX_VDB *vdb) const
126  { return indexSpace() == vdb->indexSpace(); }
127 
128  /// Transform the vdb, this REQUIRES updating the nanovdb
129  /// structure so will run OpenCL.
130  void transform(const UT_Matrix4D& m);
131 
132  /// Sets the underlying GPU buffer to provided grid, taking
133  /// ownership of it.
134  void adoptGrid(UT_UniquePtr<CE_VDBGrid> grid,
135  cl::Buffer tilestarts,
136  exint leafcount,
137  exint lowercount,
138  exint uppercount,
139  const UT_Vector3 &voxelsize,
140  const GA_PrimVolumeXform &indexspace);
141 
142  /// If onCPU, returns a shared pointer to the cpu buffer
143  /// If onGPU, copy to CPU and return the shared pointer, keeping
144  /// GPU copy.
145  /// If dirty, return null.
146  /// Can throw CE exceptions.
147  UT_SharedPtr<CE_BufferHostByte> getCPUBufferR() const;
148 
149  /// If onCPU, ensure unique and return the raw pointer that is
150  /// our own buffer.
151  /// If onGPU, copies to the CPU and returns that, resetting onGPU to false
152  /// If dirty, return null.
153  CE_BufferHostByte *getCPUBufferRW();
154 
155  /// Replace VDB with raw NanoVDB buffer.
156  /// Can throw CE exceptions for malformed or unhandled data.
157  void setFromRawNanoVDB(const void *data, exint size);
158 
159  /// Returns true if this vdb's data is currently on the GPU.
160  bool isOnGPU() const
161  {
162  return myOnGPU;
163  }
164 
165  /// Returns true if this vdb's data is currently on the CPU (this is not
166  /// necessarily !isOnGPU()).
167  bool isOnCPU() const
168  {
169  return myOnCPU;
170  }
171 
172  /// True if data in this buffer may be stolen from (or changed) by the verbs
173  /// even if it's an input.
174  bool stealable() const { return myStealable; }
175 
176  /// Can be used to control what stealable() subsequently returns. If set to
177  /// true, indicates to the verbs that this buffer may be stolen from.
178  void setStealable(bool v) const { myStealable = v; }
179 
180  bool hasTopology() const; // No topology is an incomplete vdb
181  exint leafCount() const
182  { return myTopology ? myTopology->leafCount() : 0; }
183  exint lowerCount() const
184  { return myTopology ? myTopology->lowerCount() : 0; }
185  exint upperCount() const
186  { return myTopology ? myTopology->upperCount() : 0; }
187 
188  /// Half-inclusive bounds of the volume in voxels; using only the leaf
189  /// information. Requires possibly copying back tilestarts and running
190  /// over, so not fast. Voxels are in [lower, upper)
192  {
193  lower = upper = 0;
194  if (myTopology) myTopology->voxelBounds(lower, upper);
195  }
196 
197  /// Build topology from provided grid. These are built onto
198  /// the GPU & CPU. This could be delayed since we share
199  /// the topology pointer so would only upload once.
200  void buildTopology(const openvdb::GridBase &grid);
201 
202  /// Build topology from our own cpu buffer.
203  void buildTopologyFromCPU(bool denseleaves);
204 
205  /// Return a gpu version
207  { if (myTopology) return myTopology->getGPUTileStarts(tilecount);
208  tilecount = 0; return {}; }
210  { if (myTopology) return myTopology->getCPUTileStarts();
211  return {}; }
212 
213  /// If we know all leaves are fully activated, we can avoid
214  /// doing activation tests per voxel. This can be set at build
215  /// time and then cleared if any topology change op occurs.
216  bool denseLeaves() const
217  { return myTopology ? myTopology->denseLeaves() : true; }
218  void setDenseLeaves(bool dense)
219  { UT_ASSERT(myTopology); if (myTopology) myTopology->setDenseLeaves(dense); }
220 
221  /// NOTE: These only set leaf values.
222  void setConstantV3(UT_Vector3 v);
223  void setConstantF(fpreal32 f = 0.0f) { setConstantV3(UT_Vector3(f,f,f)); }
224  void setConstantI(int32 i = 0);
225 
226  /// True if there are no VDB grids on GPU or CPU
227  bool isDirty() const { return !myOnGPU && !myOnCPU; }
228 
229  /// Flag all grids as dirty without freeing them.
230  void setDirty() { myOnGPU = myOnCPU = false; }
231 
232  /// Frees all buffers and marks dirty.
233  void freeBuffers();
234 
235  /// Frees all the memory
236  void destroy();
237 
238  /// True if there are any CPU or GPU buffers, they may not have
239  /// valid data - use isDirty() to see that.
240  bool allocated() const { return myCPUBuffer || myGPUBuffer; }
241 
242  int64 getMemoryUsage() const;
243  int64 getDeviceMemoryUsage() const;
244 
246  { myProperties = props; }
248  { return myProperties; }
249 
250  /// Updates the contents of the properties, first making sure it is
251  /// unique. The provided operator should take a reference to
252  /// a UT_Options that it will update.
253  /// this->update([](UT_Options &opt) { opt.setOptionS("test", "bar"); });
254  template <typename OP>
255  void updateProperties(const OP &op)
256  { myProperties.update(op); }
257 
258  /// VDB registration to allow vdbs to be converted
259  /// to integers across HOM boundaries.
260 
261  /// Registers & returns the handle, adding the handle to the registered
262  /// list
263  static int registerVDB(IMX_VDBConstPtr vdb, UT_IntArray &registered);
264  /// Unregister all vdbs corresponding to the provided list,
265  /// erase the list afterwards. Assertion if handle wasn't regsitered
266  static void unregisterVDBs(UT_IntArray &registered);
267  /// Look up a registered vdb by handle.
268  static IMX_VDBConstPtr lookupVDB(int handle);
269 
270  class Topology
271  {
272  public:
273  Topology() = default;
274  Topology(cl::Buffer tilestarts,
275  exint leafcount, exint lowercount, exint uppercount)
276  {
277  myGPUTileStarts = tilestarts;
278  myGPUTileStartsCount = leafcount;
279  myLeafCount = leafcount;
280  myLowerCount = lowercount;
281  myUpperCount = uppercount;
282  }
283  Topology(const openvdb::GridBase &grid);
284  Topology(const CE_BufferHostByte *cpugrid);
285  ~Topology();
286 
287  /// Return a gpu version
288  cl::Buffer getGPUTileStarts(exint &tilecount) const;
289  UT_SharedPtr<UT_Array<UT_Vector3i>> getCPUTileStarts() const;;
290 
291  void setDenseLeaves(bool isdense) { myDenseLeaves = isdense; }
292  bool denseLeaves() const { return myDenseLeaves; }
293 
294  exint leafCount() const { return myLeafCount; }
295  exint lowerCount() const { return myLowerCount; }
296  exint upperCount() const { return myUpperCount; }
297 
298  void voxelBounds(UT_Vector3i &lower, UT_Vector3i &upper) const;
299 
300  int64 getMemoryUsage() const;
301  int64 getDeviceMemoryUsage() const;
302 
303  protected:
305  /// Tile starts is a shared buffer, so isn't re-written to
307  exint myGPUTileStartsCount = -1;
308 
309  /// Required to rebuild:
310  exint myLeafCount = 0;
311  exint myLowerCount = 0;
312  exint myUpperCount = 0;
313 
314  // True if all the leaves are dense.
315  bool myDenseLeaves = false;
316  };
317 
318  /// Compute useful aggregate properties of the layer.
319  /// For integer vdb, use computeMinI() and computeMaxI().
320  fpreal64 computeMin(int channel = 0) const;
321  fpreal64 computeMax(int channel = 0) const;
322  fpreal64 computeAverage(int channel = 0) const;
323  fpreal64 computeMinLength() const;
324  fpreal64 computeMaxLength() const;
325 
326 protected:
327  /// These implement methods required by the pool.
328  /// Resets the GPU Buffer pointer.
329  void poolResetGPUBuffer() override
330  {
331  myGPUBuffer.reset();
332  }
333  /// Update OnGPU
334  void poolSetOnGPU(bool ongpu) override
335  {
336  myOnGPU = ongpu;
337  }
338  /// True if the gpu buffer is null.
339  bool poolIsGPUBufferEmpty() const override
340  {
341  return myGPUBuffer.get() == nullptr;
342  }
343  /// True if the gpu buffer is not null and valid.
344  bool poolIsGPUBufferValid() const override
345  {
346  return myGPUBuffer.get() && myGPUBuffer->isValid();
347  }
348  /// True if the swap does something
349  bool poolSwapGPUBuffer(CE_HotSwapPoolEntry *otherbase) override
350  {
351  IMX_VDB *other = UTverify_cast<IMX_VDB *>(otherbase);
352 
353  if (myGPUBuffer == other->myGPUBuffer)
354  return false;
355 
356  myGPUBuffer.swap(other->myGPUBuffer);
357  return true;
358  }
359  /// Shallow copy
360  void poolShallowCopyGPUBuffer(const CE_HotSwapPoolEntry *srcbase) override
361  {
362  const IMX_VDB *src = UTverify_cast<const IMX_VDB *>(srcbase);
363 
364  myGPUBuffer = src->myGPUBuffer;
365  }
366  /// Queues up commands that transfer this buffer's GPU storage to main
367  /// memory.
368  void unloadFromGPU() override;
369 
370  UT_SharedPtr<CE_BufferHostByte> getCPUBufferRInternal();
371 
373 
374  /// Tracks the leaf starts & node counts. Stores GPU and CPU
375  /// versions of these.
377 
378  /// Because the nanovdb buffers are somewhat opaque, we store
379  /// some meta data locally.
382 
383  /// All changes to this member (the shared pointer) must be done by the
384  /// memory pool!!!
386 
389 
390  /// The type of the grid so we can avoid unpacking it to find out.
391  /// Note this is ALSO on the CE_VDBGrid, but that might not exist
392  /// for CPU buffers so it is duplicated here.
393  UT_VDBType myStorageType = UT_VDB_INVALID;
394 
395  /// This pair of flags hold the state of data that lives in the two storage
396  /// spots.
397  bool myOnCPU = false;
398  bool myOnGPU = false;
399 
400  /// Can data of this buffer be stolen by the verbs? TODO: who should reset
401  /// this and when?
402  mutable bool myStealable = true;
403 
404  friend IMX_API size_t
405  UTformatBuffer(char *buffer, size_t buffer_size, const IMX_VDB &v);
406 };
407 
409 
410 IMX_API size_t
411 UTformatBuffer(char *buffer, size_t buffer_size, const IMX_VDB &v);
412 
413 #endif
414 
bool poolIsGPUBufferEmpty() const override
True if the gpu buffer is null.
Definition: IMX_VDB.h:339
void setDenseLeaves(bool dense)
Definition: IMX_VDB.h:218
std::string upper(string_view a)
Return an all-upper case version of a (locale-independent).
Definition: strutil.h:500
int int32
Definition: SYS_Types.h:39
UT_SharedPtr< Topology > myTopology
Definition: IMX_VDB.h:376
void setDenseLeaves(bool isdense)
Definition: IMX_VDB.h:291
void cpuCopyFromVDB(const openvdb::GridBase &vdb, const UT_Vector3 &voxelsize, const GA_PrimVolumeXform &indexspace)
Definition: IMX_VDB.h:83
void poolResetGPUBuffer() override
Definition: IMX_VDB.h:329
GA_PrimVolumeXform indexSpace() const
Definition: IMX_VDB.h:122
getFileOption("OpenEXR:storage") storage
Definition: HDK_Image.dox:276
bool isDirty() const
True if there are no VDB grids on GPU or CPU.
Definition: IMX_VDB.h:227
const GLdouble * v
Definition: glcorearb.h:837
void gpuCopyFromVDB(const openvdb::GridBase &vdb, const UT_Vector3 &voxelsize, const GA_PrimVolumeXform &indexspace)
Definition: IMX_VDB.h:87
void setConstantF(fpreal32 f=0.0f)
Definition: IMX_VDB.h:223
UT_SharedPtr< CE_BufferHostByte > myCPUBuffer
Definition: IMX_VDB.h:372
UT_Vector3T< float > UT_Vector3
exint leafCount() const
Definition: IMX_VDB.h:294
IMX_VDB & operator=(IMX_VDB &&other)
Definition: IMX_VDB.h:55
IMX_API size_t UTformatBuffer(char *buffer, size_t buffer_size, const IMX_VDB &v)
IMX_TypeInfo
Definition: IMX_Types.h:36
Topology(cl::Buffer tilestarts, exint leafcount, exint lowercount, exint uppercount)
Definition: IMX_VDB.h:274
int64 exint
Definition: SYS_Types.h:125
bool poolIsGPUBufferValid() const override
True if the gpu buffer is not null and valid.
Definition: IMX_VDB.h:344
void swap(T &lhs, T &rhs)
Definition: pugixml.cpp:7440
JSON reader class which handles parsing of JSON or bJSON files.
Definition: UT_JSONParser.h:87
Class which writes ASCII or binary JSON streams.
Definition: UT_JSONWriter.h:39
bool denseLeaves() const
Definition: IMX_VDB.h:292
SYS_FORCE_INLINE TO_T UTverify_cast(FROM_T from)
Definition: UT_Assert.h:242
UT_VDBType
Definition: UT_VDBUtils.h:25
bool isOnGPU() const
Returns true if this vdb's data is currently on the GPU.
Definition: IMX_VDB.h:160
bool poolSwapGPUBuffer(CE_HotSwapPoolEntry *otherbase) override
True if the swap does something.
Definition: IMX_VDB.h:349
float fpreal32
Definition: SYS_Types.h:200
bool stealable() const
Definition: IMX_VDB.h:174
GLuint buffer
Definition: glcorearb.h:660
IMX_TypeInfo typeInfo() const
Definition: IMX_VDB.h:117
UT_SharedPtr< CE_VDBGrid > myGPUBuffer
Definition: IMX_VDB.h:385
void poolShallowCopyGPUBuffer(const CE_HotSwapPoolEntry *srcbase) override
Shallow copy.
Definition: IMX_VDB.h:360
std::unique_ptr< T, Deleter > UT_UniquePtr
A smart pointer for unique ownership of dynamically allocated objects.
Definition: UT_UniquePtr.h:39
double fpreal64
Definition: SYS_Types.h:201
void setStealable(bool v) const
Definition: IMX_VDB.h:178
exint upperCount() const
Definition: IMX_VDB.h:296
GLfloat f
Definition: glcorearb.h:1926
void poolSetOnGPU(bool ongpu) override
Update OnGPU.
Definition: IMX_VDB.h:334
std::shared_ptr< T > UT_SharedPtr
Wrapper around std::shared_ptr.
Definition: UT_SharedPtr.h:36
UT_VDBType storageType() const
Definition: IMX_VDB.h:111
IMX_VDB(IMX_VDB &&other) noexcept
Definition: IMX_VDB.h:44
UT_SharedPtr< const IMX_VDB > IMX_VDBConstPtr
Definition: IMX_VDB.h:35
EntryType
To avoid the need for dynamic casts:
IMX_VDB(const IMX_VDB &other)
Definition: IMX_VDB.h:43
UT_SharedPtr< UT_Array< UT_Vector3i > > myCPUTileStarts
Definition: IMX_VDB.h:304
long long int64
Definition: SYS_Types.h:116
exint leafCount() const
Definition: IMX_VDB.h:181
IMX_VDB & operator=(const IMX_VDB &other)
Definition: IMX_VDB.h:52
GA_API const UT_StringHolder transform
GA_PrimVolumeXform myIndexSpace
Definition: IMX_VDB.h:381
exint upperCount() const
Definition: IMX_VDB.h:185
UT_Vector3 origin() const
Definition: IMX_VDB.h:121
GLsizeiptr size
Definition: glcorearb.h:664
A map of string to various well defined value types.
Definition: UT_Options.h:87
EntryType poolTypeID() const override
Definition: IMX_VDB.h:48
bool isOnCPU() const
Definition: IMX_VDB.h:167
void setDirty()
Flag all grids as dirty without freeing them.
Definition: IMX_VDB.h:230
exint lowerCount() const
Definition: IMX_VDB.h:295
std::string lower(string_view a)
Return an all-upper case version of a (locale-independent).
Definition: strutil.h:493
UT_Vector3 myVoxelSize
Definition: IMX_VDB.h:380
UT_OptionsHolder properties() const
Definition: IMX_VDB.h:247
UT_OptionsHolder myProperties
Definition: IMX_VDB.h:387
Memory buffer interface.
Definition: cl.hpp:1867
cl::Buffer getGPUTileStarts(exint &tilecount) const
Return a gpu version.
Definition: IMX_VDB.h:206
#define IMX_API
Definition: IMX_API.h:8
cl::Buffer myGPUTileStarts
Tile starts is a shared buffer, so isn't re-written to.
Definition: IMX_VDB.h:306
bool denseLeaves() const
Definition: IMX_VDB.h:216
GLubyte GLubyte GLubyte GLubyte w
Definition: glcorearb.h:857
#define UT_ASSERT(ZZ)
Definition: UT_Assert.h:165
CE_VDBGrid * getGPUBufferW()
Definition: IMX_VDB.h:109
void setProperties(const UT_OptionsHolder &props)
Definition: IMX_VDB.h:245
void voxelBounds(UT_Vector3i &lower, UT_Vector3i &upper) const
Definition: IMX_VDB.h:191
UT_SharedPtr< IMX_VDB > IMX_VDBPtr
Definition: IMX_VDB.h:34
bool isAligned(const IMX_VDB *vdb) const
True if the two vdbs map the same indices to the same positions.
Definition: IMX_VDB.h:125
UT_SharedPtr< UT_Array< UT_Vector3i > > getCPUTileStarts() const
Definition: IMX_VDB.h:209
bool allocated() const
Definition: IMX_VDB.h:240
void setTypeInfo(IMX_TypeInfo typeinfo)
Definition: IMX_VDB.h:116
virtual void unloadFromGPU()=0
Definition: format.h:1821
void updateProperties(const OP &op)
Definition: IMX_VDB.h:255
void swap(IMX_VDB &other)
UT_Vector3 voxelSize() const
Definition: IMX_VDB.h:120
exint lowerCount() const
Definition: IMX_VDB.h:183
GLenum GLuint GLsizei const GLenum * props
Definition: glcorearb.h:2525
GLenum src
Definition: glcorearb.h:1793