HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
GAS_NetVDBSliceExchange.C
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2024
3  * Side Effects Software Inc. All rights reserved.
4  *
5  * Redistribution and use of Houdini Development Kit samples in source and
6  * binary forms, with or without modification, are permitted provided that the
7  * following conditions are met:
8  * 1. Redistributions of source code must retain the above copyright notice,
9  * this list of conditions and the following disclaimer.
10  * 2. The name of Side Effects Software may not be used to endorse or
11  * promote products derived from this software without specific prior
12  * written permission.
13  *
14  * THIS SOFTWARE IS PROVIDED BY SIDE EFFECTS SOFTWARE `AS IS' AND ANY EXPRESS
15  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
17  * NO EVENT SHALL SIDE EFFECTS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
18  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
19  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
20  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
21  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
22  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
23  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  *
25  *----------------------------------------------------------------------------
26  */
27 
29 
30 #include <UT/UT_DSOVersion.h>
31 #include <UT/UT_Interrupt.h>
32 #include <UT/UT_NetMessage.h>
33 #include <UT/UT_StringStream.h>
34 
35 #include <SIM/SIM_PRMShared.h>
36 #include <SIM/SIM_DopDescription.h>
37 #include <SIM/SIM_Object.h>
38 #include <SIM/SIM_GeometryCopy.h>
39 #include <SIM/SIM_Slice.h>
40 
41 #include <GEO/GEO_PrimVolume.h>
42 #include <GU/GU_PrimVDB.h>
43 
44 using namespace HDK_Sample;
45 
46 ///
47 /// This is the hook that Houdini grabs from the dll to link in
48 /// this. As such, it merely has to implement the data factory
49 /// for this node.
50 ///
51 void
53 {
55 }
56 
57 //
58 // GAS_NetVDBSliceExchange
59 //
61  : BaseClass(factory)
62 {
63 }
64 
66 {
67 }
68 
69 const SIM_DopDescription *
70 GAS_NetVDBSliceExchange::getDopDescription()
71 {
72  static PRM_Name theGeometryName(GAS_NAME_GEOMETRY, "Geometry");
73  static PRM_Default theGeometryNameDefault(0, "Geometry");
74  static PRM_Name theVDBName("vdbname", "VDB Names");
75  static PRM_Default theVDBNameDefault(0, "*");
76 
77  static PRM_Name theAddrName(GAS_NAME_TRACKERADDR, "Tracker Address");
78  static PRM_Name thePortName(GAS_NAME_TRACKERPORT, "Tracker Port");
79  static PRM_Name theJobName(GAS_NAME_JOBNAME, "Job Name");
80  static PRM_Default thePortDefault(8000);
81  static PRM_Default theJobDefault(0, "${OS}_$F");
82  static PRM_Name theThisSliceName("slice", "Slice Number");
83 
84  static PRM_Name theSliceRootName("sliceroot", "Slice Data Root");
85  static PRM_Default theSliceRootDefault(0, "Slice");
86 
87  static PRM_Name theOverlapName("overlap", "Slice Overlap");
88  static PRM_Name theOverlapVoxelName("overlapvoxel", "Voxel Overlap");
89 
90  static PRM_Template theTemplates[] = {
91  PRM_Template(PRM_STRING, 1, &theGeometryName, &theGeometryNameDefault),
92  PRM_Template(PRM_STRING, 1, &theVDBName, &theVDBNameDefault),
93 
94  PRM_Template(PRM_STRING, 1, &theAddrName),
95  PRM_Template(PRM_INT, 1, &thePortName, &thePortDefault),
96  PRM_Template(PRM_STRING, 1, &theJobName, &theJobDefault),
97  PRM_Template(PRM_INT, 1, &theThisSliceName, PRMzeroDefaults),
98 
99  PRM_Template(PRM_STRING, 1, &theSliceRootName, &theSliceRootDefault),
100 
101  PRM_Template(PRM_FLT, 1, &theOverlapName, PRMzeroDefaults,
102  0, 0, 0, &PRM_SpareData::unitsLength ),
103  PRM_Template(PRM_FLT, 1, &theOverlapVoxelName, PRMzeroDefaults),
104  PRM_Template()
105  };
106 
107  static SIM_DopDescription theDopDescription(true,
108  "hdk_gasnetvdbsliceexchange",
109  "Gas Net VDB Slice Exchange",
110  "$OS",
111  classname(),
112  theTemplates);
113  setGasDescription(theDopDescription);
114 
115  return &theDopDescription;
116 }
117 
118 static void
119 GASreadDataFromPacket(fpreal32 &value, UT_NetMessage *msg, exint offset)
120 {
121  value = msg->extractFloat32(offset);
122 }
123 
124 static void
125 GASreadDataFromPacket(fpreal64 &value, UT_NetMessage *msg, exint offset)
126 {
127  value = msg->extractFloat64(offset);
128 }
129 
130 static void
131 GASreadDataFromPacket(int32 &value, UT_NetMessage *msg, exint offset)
132 {
133  value = msg->extractInt32(offset);
134 }
135 
136 static void
137 GASreadDataFromPacket(int64 &value, UT_NetMessage *msg, exint offset)
138 {
139  value = msg->extractInt64(offset);
140 }
141 
142 static void
143 GASreadDataFromPacket(openvdb::math::Vec3<float> &value, UT_NetMessage *msg, exint offset)
144 {
145  value[0] = msg->extractFloat32(offset);
146  value[1] = msg->extractFloat32(offset + sizeof(value[0]));
147  value[2] = msg->extractFloat32(offset + 2*sizeof(value[0]));
148 }
149 
150 static void
151 GASreadDataFromPacket(openvdb::math::Vec3<double> &value, UT_NetMessage *msg, exint offset)
152 {
153  value[0] = msg->extractFloat64(offset);
154  value[1] = msg->extractFloat64(offset + sizeof(value[0]));
155  value[2] = msg->extractFloat64(offset + 2*sizeof(value[0]));
156 }
157 
158 static void
159 GASreadDataFromPacket(openvdb::math::Vec3<int32> &value, UT_NetMessage *msg, exint offset)
160 {
161  value[0] = msg->extractInt32(offset);
162  value[1] = msg->extractInt32(offset + sizeof(value[0]));
163  value[2] = msg->extractInt32(offset + 2*sizeof(value[0]));
164 }
165 
166 /*
167 static void
168 GASreadDataFromPacket(openvdb::math::Vec3<int64> &value, UT_NetMessage *msg, exint offset)
169 {
170  value[0] = msg->extractInt64(offset);
171  value[1] = msg->extractInt64(offset + sizeof(value[0]));
172  value[2] = msg->extractInt64(offset + 2*sizeof(value[0]));
173 }
174 */
175 
176 static void
177 GASwriteDataToPacket(UT_NetMessage *msg, exint offset, fpreal32 value)
178 {
179  msg->overwriteFloat32(offset, value);
180 }
181 
182 static void
183 GASwriteDataToPacket(UT_NetMessage *msg, exint offset, fpreal64 value)
184 {
185  msg->overwriteFloat64(offset, value);
186 }
187 
188 static void
189 GASwriteDataToPacket(UT_NetMessage *msg, exint offset, int32 value)
190 {
191  msg->overwriteInt32(offset, value);
192 }
193 
194 static void
195 GASwriteDataToPacket(UT_NetMessage *msg, exint offset, int64 value)
196 {
197  msg->overwriteInt64(offset, value);
198 }
199 
200 static void
201 GASwriteDataToPacket(UT_NetMessage *msg, exint offset, openvdb::math::Vec3<float> value)
202 {
203  msg->overwriteFloat32(offset, value[0]);
204  msg->overwriteFloat32(offset+sizeof(value[0]), value[1]);
205  msg->overwriteFloat32(offset+2*sizeof(value[0]), value[2]);
206 }
207 
208 static void
209 GASwriteDataToPacket(UT_NetMessage *msg, exint offset, openvdb::math::Vec3<double> value)
210 {
211  msg->overwriteFloat64(offset, value[0]);
212  msg->overwriteFloat64(offset+sizeof(value[0]), value[1]);
213  msg->overwriteFloat64(offset+2*sizeof(value[0]), value[2]);
214 }
215 
216 static void
217 GASwriteDataToPacket(UT_NetMessage *msg, exint offset, openvdb::math::Vec3<int32> value)
218 {
219  msg->overwriteInt32(offset, value[0]);
220  msg->overwriteInt32(offset+sizeof(value[0]), value[1]);
221  msg->overwriteInt32(offset+2*sizeof(value[0]), value[2]);
222 }
223 
224 /*
225 static void
226 GASwriteDataToPacket(UT_NetMessage *msg, exint offset, openvdb::math::Vec3<int64> value)
227 {
228  msg->overwriteInt64(offset, value[0]);
229  msg->overwriteInt64(offset+sizeof(value[0]), value[1]);
230  msg->overwriteInt64(offset+2*sizeof(value[0]), value[2]);
231 }
232 */
233 
234 template <typename GridType>
235 void
237  GridType &grid,
238  GAS_NetVDBSliceExchange *solver, SIM_Object *obj,
239  UT_NetMessage *msg)
240 {
241  int srcpeer = msg->extractInt16(6);
242 
243  typename GridType::Accessor acc = grid.getAccessor();
244  using ValueType = typename GridType::ValueType;
245 
246  exint numreply;
247  numreply = msg->extractInt32(8);
248 
249  // Where we are reading packets.
250  exint replyoff = 16;
251 
252  for (exint reply = 0; reply < numreply; reply++)
253  {
254  if (replyoff >= msg->length())
255  {
256  std::cerr << "Malformed reply from " << srcpeer << ", total replies " << numreply << " exhausted message packet sized " << msg->length() << std::endl;
257  return;
258  }
259 
260  UT_Vector3I minvxl;
261  minvxl.x() = msg->extractInt32(replyoff+0);
262  minvxl.y() = msg->extractInt32(replyoff+4);
263  minvxl.z() = msg->extractInt32(replyoff+8);
264  int magictoken = msg->extractInt32(replyoff+12);
265  if (magictoken != 0x51DEEFC5)
266  {
267  // Corrupted data stream or we lost count, we should
268  // abandon
269  std::cerr << "Malformed reply from " << srcpeer << ", total replies " << numreply << " missing magic token on packet " << reply << " at offset " << replyoff << std::endl;
270  return;
271  }
272 
273  char nodemask[64];
274  for (int nm = 0; nm < 64; nm++)
275  nodemask[nm] = msg->extractInt8(replyoff+16+nm);
276 
277  // Get to data.
278  replyoff += 16 + 64;
279  int nodemaskpos = 0;
280  exint nodeoff = 0;
281  for (int x = 0; x < 8; x++)
282  {
283  for (int y = 0; y < 8; y++)
284  {
285  int flag = 1;
286  for (int z = 0; z < 8; z++)
287  {
288  if (nodemask[nodemaskpos] & flag)
289  {
290  // Read in a value and store in grid
291  ValueType v;
292 
293  GASreadDataFromPacket(v, msg, replyoff+nodeoff);
294  openvdb::Coord coord(minvxl.x() + x, minvxl.y() + y, minvxl.z() + z);
295  acc.setValueOn(coord, v);
296  nodeoff += sizeof(v);
297  }
298  flag += flag;
299  }
300  nodemaskpos++;
301  }
302  }
303 
304  replyoff += nodeoff;
305  }
306 }
307 
308 void
310  GU_PrimVDB *vdb,
311  GAS_NetVDBSliceExchange *solver, SIM_Object *obj,
312  UT_NetMessage *msg)
313 {
316  vdb->getGrid(),
317  solver, obj, msg);
318 }
319 
320 template <typename GridType>
321 void
323  const GEO_PrimVolumeXform &indexxform,
325  GAS_NetVDBSliceExchange *solver, SIM_Object *obj,
326  fpreal overlap,
327  exint thisslice, const SIM_SliceSearchTable &slicetable)
328 {
329  typename GridType::Accessor acc = grid.getAccessor();
330  using ValueType = typename GridType::ValueType;
331 
332  UT_ExintArray msgpackets, msgoffsets;
333  int numslice = msgs.entries();
334  for (int i = 0; i < numslice; i++)
335  {
336  msgpackets.append(0);
337  msgoffsets.append(16);
338  if (i != thisslice)
339  {
340  msgs(i) = new UT_NetMessage();
341  // first 8 is standard header
342  // 4 for numreplies
343  // 4 for reserved.
344  msgs(i)->setWriteDataLength(8 + 8);
345  }
346  }
347 
348  UT_Array<UT_IntArray> packetvoxeloffset;
349  UT_Array<UT_Array<ValueType>> packetvoxelvalue;
350  packetvoxeloffset.setSize(numslice);
351  packetvoxelvalue.setSize(numslice);
352 
353  ValueType background = grid.background();
354 
355  for (auto it = grid.tree().beginLeaf(); it; ++it)
356  {
357  // Get voxel bounds.
358  auto vdb_box = it->getNodeBoundingBox();
359 
360  UT_Vector3 tstart, tend;
361  UT_BoundingBox tbbox, tbbox_expand;
362 
363  tstart.assign(vdb_box.min().x()-0.5, vdb_box.min().y()-0.5, vdb_box.min().z()-0.5);
364  tend.assign(vdb_box.max().x()+0.5, vdb_box.max().y()+0.5, vdb_box.max().z()+0.5);
365  tbbox.initBounds(tstart);
366  tbbox.enlargeBounds(tend);
367  indexxform.fromVoxelSpace(tbbox);
368 
369  tbbox_expand = tbbox;
370  tbbox_expand.expandBounds(overlap, overlap, overlap);
371 
372  // If our expanded box is entirely inside our slice we have no
373  // voxels to deactivate or transmit (As external slices are only
374  // interested in a distance up to overlap)
375  if (SIM_Slice::isInsideSlice(slicetable(thisslice), tbbox_expand))
376  {
377  continue;
378  }
379 
380  // If our tight bounding box is entirely outside of our slice
381  // we have no voxels to transmit and all our voxels must be
382  // de-activated.
383  if (!SIM_Slice::doesIntersectSlice(slicetable(thisslice), tbbox))
384  {
385  for (int i = vdb_box.min().x(); i <= vdb_box.max().x(); i++)
386  for (int j = vdb_box.min().y(); j <= vdb_box.max().y(); j++)
387  for (int k = vdb_box.min().z(); k <= vdb_box.max().z(); k++)
388  acc.setValueOff(openvdb::Coord(i, j, k), background);
389  continue;
390  }
391 
392  // We have at box that has some voxels that may need to
393  // be transferred.
394  // Given a slice topology there often is only a few potential
395  // candidates, but so long as total machines is small there
396  // isn't much gain in overthinking this.
397 
398  for (int slice = 0; slice < numslice; slice++)
399  {
400  packetvoxeloffset(slice).entries(0);
401  packetvoxelvalue(slice).entries(0);
402  }
403 
404  int offset = 0;
405  for (int i = vdb_box.min().x(); i <= vdb_box.max().x(); i++)
406  for (int j = vdb_box.min().y(); j <= vdb_box.max().y(); j++)
407  for (int k = vdb_box.min().z(); k <= vdb_box.max().z(); k++)
408  {
409  UT_Vector3 pos(i, j, k);
410  pos = indexxform.fromVoxelSpace(pos);
411 
412  if (!SIM_Slice::isInsideSlice(slicetable(thisslice), pos))
413  {
414  // This coordinate is outside our slice, so we
415  // do not own it. We thus de-activate it.
416  acc.setValueOff(openvdb::Coord(i, j, k), background);
417  }
418  else
419  {
420  // Test each slice to see if we need to transfer
421  // to that slice.
422  for (int slice = 0; slice < numslice; slice++)
423  {
424  // Don't send to ourself.
425  if (slice == thisslice)
426  continue;
427 
428  // See if the given slice is within overlap
429  if (SIM_Slice::computeSliceDist(slicetable(slice), pos) < overlap)
430  {
431  packetvoxeloffset(slice).append( offset );
432  packetvoxelvalue(slice).append( acc.getValue(openvdb::Coord(i, j, k)) );
433  }
434  }
435  }
436 
437  offset++;
438  }
439 
440  // We've now bulid the packetvoxeloffset & value lists.
441  // For any that are non zero we want to add a packet.
442  for (int slice = 0; slice < numslice; slice++)
443  {
444  if (slice == thisslice)
445  continue;
446 
447  if (packetvoxeloffset(slice).entries() == 0)
448  continue;
449 
450  auto && msg = msgs(slice);
451 
452  exint msgoffset = msgoffsets(slice);
453  msgpackets(slice)++;
454 
455  msg->growWriteData(msgoffset + 16 + 64 + sizeof(ValueType) * packetvoxeloffset(slice).entries());
456 
457  msg->overwriteInt32(msgoffset + 0, vdb_box.min().x());
458  msg->overwriteInt32(msgoffset + 4, vdb_box.min().y());
459  msg->overwriteInt32(msgoffset + 8, vdb_box.min().z());
460  msg->overwriteInt32(msgoffset + 12, 0x51DEEFC5);
461 
462  msgoffset += 16;
463 
464  char nodemask[64];
465  memset(nodemask, 0, 64);
466  for (auto && offset : packetvoxeloffset(slice))
467  {
468  nodemask[offset >> 3] |= 1 << (offset & 7);
469  }
470 
471  for (int nm = 0; nm < 64; nm++)
472  msg->overwriteInt8(msgoffset + nm, nodemask[nm]);
473 
474  msgoffset += 64;
475 
476  for (auto && value : packetvoxelvalue(slice))
477  {
478  GASwriteDataToPacket(msg, msgoffset, value);
479  msgoffset += sizeof(value);
480  }
481 
482  // Write back the new offset.
483  msgoffsets(slice) = msgoffset;
484  }
485  }
486 
487  // Write out the number of backets in each message.
488  for (int slice = 0; slice < numslice; slice++)
489  {
490  if (slice == thisslice)
491  continue;
492 
493  msgs(slice)->overwriteInt32(8, msgpackets(slice));
494  }
495 }
496 
497 void
500  GAS_NetVDBSliceExchange *solver, SIM_Object *obj,
501  fpreal overlap,
502  exint thisslice, const SIM_SliceSearchTable &slicetable)
503 {
506  vdb->getGrid(),
507  vdb->getIndexSpaceTransform(),
508  msgs,
509  solver, obj,
510  overlap, thisslice, slicetable);
511 }
512 
513 void
515  SIM_Object *obj,
516  GU_PrimVDB *vdb,
517  const char *tracker, int port, const char *jobname,
518  exint thisslice,
519  const SIM_SliceSearchTable &slicetable)
520 {
521  exint nslice = slicetable.entries();
522 
523  // Trivial to sync unsliced fields.
524  if (nslice <= 1)
525  return;
526 
527  vdb->makeGridUnique();
528 
529  fpreal overlap = solver->getOverlap();
530 
531  overlap += solver->getOverlapVoxel() * vdb->getVoxelDiameter();
532 
533  //
534  // dispatch
535  // 32, 32, 32 - world voxel bottom left
536  // 32 - magic number
537  // 64*8 - voxel mask
538  // sizeof*active - values
539  //
540 
541  UT_NetExchange netxchg(tracker, port, thisslice, nslice, jobname);
542  UT_Array<UT_NetMessage *> dispatchmsgs;
544 
545  dispatchmsgs.setSize(nslice);
546 
547  // Build all of our messages and deactivate outside voxels:
548  GASnetvdbsliceexchangeBuildPacket(vdb, dispatchmsgs,
549  solver, obj,
550  overlap,
551  thisslice, slicetable);
552 
553  // Send requests to all of our peers.
554  for (int slice = 0; slice < nslice; slice++)
555  {
556  if (slice == thisslice)
557  continue;
558 
559  netxchg.sendData(slice, dispatchmsgs(slice));
560  }
561 
562  // We expect a message, possibly empty, from all peers except
563  // ourself.
564  netxchg.receiveDataLoop(completed, nslice -1);
565 
566  // Apply all of our done packets.
567  for (int i = 0; i < completed.entries(); i++)
568  {
569  UT_NetMessage *msg = completed(i);
570  completed(i) = 0;
571  GASnetvdbsliceexchangeApplyPacket(vdb, solver, obj, msg);
572  delete msg;
573  }
574 }
575 
576 bool
578  SIM_Object *obj,
579  SIM_Time time,
580  SIM_Time timestep)
581 {
582  SIM_GeometryCopy *geometry = 0;
583 
584  int port;
585  UT_String address, jobname;
586  UT_WorkBuffer exchangename;
587 
588  port = getTrackerPort();
589  getTrackerAddress(address);
590  getJobName(jobname);
591 
592  // No valid host means we should not do any exchange.
593  if (!address.isstring())
594  return true;
595 
596  UT_String sliceroot;
597  SIM_ConstDataArray slices;
598  SIM_SliceSearchTable slicetable;
599 
600  exint slice = getSlice();
601  getSliceRoot(sliceroot);
602 
603  // Get our slice list.
604  obj->filterConstSubData(slices, 0, SIM_DataFilterByType("SIM_Slice"),
605  sliceroot, SIM_DataFilterNone());
606 
607  SIM_Slice::buildSliceSearch(slicetable, slices);
608 
609  exint numslice = slicetable.entries();
610  if (numslice <= 1)
611  {
612  // Trivial, no slices.
613  return true;
614  }
615 
616  geometry = getGeometryCopy(obj, GAS_NAME_GEOMETRY);
617 
618  // Nothing to do if no geometry.
619  if (!geometry)
620  return true;
621 
622  SIM_GeometryAutoWriteLock lock(geometry);
623  GU_Detail &gdp = lock.getGdp();
624 
625  UT_Array<GEO_Primitive *> namedprims;
626  UT_String vdbname;
627  getVDBName(vdbname);
628 
629  // Stage 1:
630  // Determine what primitives we want to sync, their names
631  // and types.
632 
633  gdp.findAllPrimitivesByName(namedprims, vdbname);
634 
635  UT_Array<GU_PrimVDB *> vdblist;
636  UT_StringArray namelist;
637  UT_Array<UT_VDBType> typelist;
638  GA_ROHandleS name_h(&gdp, GA_ATTRIB_PRIMITIVE, "name");
639  exint msglen = 8 + 4;
640 
641  for (auto && prim : namedprims)
642  {
643  if (prim->getTypeId() == GEO_PRIMVDB)
644  {
645  GU_PrimVDB *vdb = (GU_PrimVDB *) prim;
646  vdblist.append(vdb);
647  if (!name_h.isValid())
648  namelist.append("unnamed");
649  else
650  namelist.append(name_h.get(prim->getMapOffset()));
651  typelist.append( vdb->getStorageType() );
652  msglen += 4 + namelist.last().length() + 1;
653  }
654  }
655 
656  // Early exit if nothing to synchronize.
657  if (!vdblist.entries())
658  return true;
659 
660  // Stage 2:
661  // Send to slice 0 a list of all primitives and types we want
662  // to process.
663  UT_WorkBuffer errormsg;
664 
665  // Build an exchange and send to first peer our list.
666  {
667  exchangename.sprintf("%s_verifyvdblist", (const char *) jobname);
668  UT_NetExchange netxchg(address, port, slice, numslice, exchangename.buffer());
669 
670  if (slice != 0)
671  {
672  UT_NetMessage *msg = 0;
673 
674  msg = new UT_NetMessage();
675 
676  msg->setWriteDataLength(msglen);
677  msg->overwriteInt32(8, vdblist.entries());
678 
679  exint msgoff = 8 + 4;
680 
681  for (int i = 0; i < vdblist.entries(); i++)
682  {
683  // Write null terminated name.
684  const char *name = namelist(i);
685  while (*name)
686  {
687  msg->overwriteInt8(msgoff++, *name);
688  name++;
689  }
690  msg->overwriteInt8(msgoff++, 0);
691 
692  // Write out the type.
693  msg->overwriteInt32(msgoff, (int32) typelist(i));
694  msgoff += sizeof(int32);
695  }
696 
697  // Send the message
698  netxchg.sendData(/*dstpeer=*/ 0, msg);
699  }
700 
702 
703  // Slice 0 gets all the other slice messages.
704  netxchg.receiveDataLoop(completed, (!slice ? (numslice-1) : 0) );
705 
706  if (slice == 0)
707  {
708  // Build our error message.
710 
711  for (int i = 0; i < completed.entries(); i++)
712  {
713  UT_NetMessage *msg = 0;
714 
715  msg = completed(i);
716  completed(i) = 0;
717 
718  int srcslice = msg->extractInt16(6);
719 
720  int numvdb = msg->extractInt32(8);
721  if (numvdb != vdblist.entries())
722  {
723  errormsg.appendSprintf("Mismatch VDB count: Slice 0 has %d; but Slice %d has %d.\n", (int) vdblist.entries(), srcslice, numvdb);
724  delete msg;
725  continue;
726  }
727 
728  exint msgoff = 8 + 4;
729  int curvdb = 0;
730  bool ok = true;
731  while (ok && curvdb < numvdb && msgoff < msg->length())
732  {
733  // Read the name...
734  name.clear();
735  while (msgoff < msg->length())
736  {
737  char c = msg->extractInt8(msgoff++);
738  name.append(c);
739  if (!c)
740  break;
741  }
742  UT_VDBType type = (UT_VDBType) msg->extractInt32(msgoff);
743  msgoff += sizeof(int32);
744 
745  if (name.strcmp(namelist(curvdb)))
746  {
747  // Name mismatch failure.
748  ok = false;
749  errormsg.appendSprintf("Mismatch VDB name. Vdb #%d has name %s in Slice 0 but %s in Slice %d.\n",
750  curvdb, (const char *) namelist(curvdb),
751  name.buffer(), srcslice);
752  }
753  if (type != typelist(curvdb))
754  {
755  ok = false;
756  errormsg.appendSprintf("Mismatch VDB type. VDB #%d has type %d in Slice 0 but %d in Slice %d.\n",
757  curvdb, (int) typelist(curvdb),
758  (int) type, srcslice);
759  }
760  curvdb++;
761  }
762 
763  if (ok && (curvdb != numvdb))
764  {
765  // Malformed packet.
766  errormsg.appendSprintf("Malformed packet from slice %d; got %d vdbs but expected %d.\n", srcslice, curvdb, numvdb);
767  }
768 
769  delete msg;
770  }
771  }
772  else
773  {
774  UT_ASSERT(!completed.entries());
775  }
776  }
777 
778  // Now if we are slice 0 we have an error message that we want
779  // to broad cast back out so everyone else can go into an error
780  // state rather than just having the system hang.
781  //
782  // We also output the errormsg to std out, which isn't normally
783  // a kosher thing to do but there is a risk traditional errors
784  // get eaten on the way to the output driver and distributed sims
785  // are almost always run non-interactively.
786  if (errormsg.isstring())
787  {
788  std::cerr << "Error: " << errormsg.buffer() << std::endl;
789  }
790 
791  {
792  exchangename.sprintf("%s_reportvdblist", (const char *) jobname);
793  UT_NetExchange netxchg(address, port, slice, numslice, exchangename.buffer());
794 
795  if (slice == 0)
796  {
797  for (int dstslice = 1; dstslice < numslice; dstslice++)
798  {
799  UT_NetMessage *msg = 0;
800 
801  msg = new UT_NetMessage();
802 
803  msg->setWriteDataLength(8 + errormsg.length()+1);
804 
805  exint msgoff = 8;
806  const char *text = errormsg.buffer();
807  while (*text)
808  {
809  msg->overwriteInt8(msgoff++, *text);
810  text++;
811  }
812  msg->overwriteInt8(msgoff++, 0);
813 
814  // Send the message
815  netxchg.sendData(dstslice, msg);
816  }
817  }
818 
820 
821  // Expect one message in for every slice except 0.
822  netxchg.receiveDataLoop(completed, (slice ? 1 : 0) );
823 
824  UT_ASSERT(completed.entries() == (slice != 0));
825 
826  for (int i = 0; i < completed.entries(); i++)
827  {
828  UT_NetMessage *msg = 0;
829  msg = completed(i);
830  completed(i) = 0;
831 
832  exint msgoff = 8;
833  while (msgoff < msg->length())
834  {
835  char c = msg->extractInt8(msgoff++);
836  errormsg.append(c);
837  if (!c)
838  break;
839  }
840 
841  delete msg;
842  }
843 
844  // Now errormsg is either unchanged (if we are slice 0)
845  // or comes from slice 0. In any case, we can use it
846  // to report our error.
847 
848  if (UTisstring(errormsg.buffer()))
849  {
850  addError(obj, SIM_MESSAGE, errormsg.buffer(), UT_ERROR_ABORT);
851 
852  return false;
853  }
854 
855  }
856 
857  // TODO: We should first synchronize to verify we have matching
858  // names and types before continuing.
859 
860  for (auto && vdb : vdblist)
861  {
862  exchangename.sprintf("%s_%d", (const char *) jobname, (int)vdb->getMapIndex());
864  vdb,
865  address, port, exchangename.buffer(),
866  slice, slicetable);
867  }
868 
869  return true;
870 }
871 
T & last()
Definition: UT_Array.h:796
void filterConstSubData(SIM_ConstDataArray &dp, UT_StringArray *names, const SIM_DataFilter &filter, const char *startfrom, const SIM_DataFilter &recurseFilter) const
fpreal32 extractFloat32(exint offset)
int int32
Definition: SYS_Types.h:39
SYS_FORCE_INLINE exint length() const
SYS_FORCE_INLINE UT_VDBType getStorageType() const
Get the storage type of the grid.
Definition: GEO_PrimVDB.h:155
PRM_API const PRM_Type PRM_FLT
#define GAS_NAME_GEOMETRY
Definition: GAS_Utils.h:30
PRM_API const PRM_Type PRM_STRING
#define IMPLEMENT_DATAFACTORY(DataClass)
GT_API const UT_StringHolder time
const GLdouble * v
Definition: glcorearb.h:837
static void setGasDescription(SIM_DopDescription &descr)
int32 extractInt32(exint offset)
GLsizei const GLfloat * value
Definition: glcorearb.h:824
SIM_GeometryCopy * getGeometryCopy(SIM_Object *obj, const char *name, bool silent=false)
GLdouble GLdouble GLdouble z
Definition: glcorearb.h:848
constexpr SYS_FORCE_INLINE T & z() noexcept
Definition: UT_Vector3.h:667
int64 exint
Definition: SYS_Types.h:125
void overwriteInt32(exint offset, int32 val)
SYS_FORCE_INLINE bool isValid() const
Definition: GA_Handle.h:906
SYS_FORCE_INLINE const HOLDER & get(GA_Offset off, int comp=0) const
Get the string at the given offset.
Definition: GA_Handle.h:911
SYS_FORCE_INLINE const char * buffer() const
fpreal getVoxelDiameter() const
GLuint GLsizei GLsizei * length
Definition: glcorearb.h:795
void setWriteDataLength(exint bufsize)
static fpreal computeSliceDist(const SIM_SliceSearchList &list, const UT_Vector3 &pos)
GLint y
Definition: glcorearb.h:103
fpreal64 extractFloat64(exint offset)
UT_VDBType
Definition: UT_VDBUtils.h:11
static bool doesIntersectSlice(const SIM_SliceSearchList &list, const UT_BoundingBox &bbox)
Returns true if the bounding box at all intersects the slice.
void overwriteInt8(exint offset, int8 val)
float fpreal32
Definition: SYS_Types.h:200
void overwriteFloat64(exint offset, fpreal64 val)
void GASnetvdbsliceexchangeApplyPacket(GU_PrimVDB *vdb, GAS_NetVDBSliceExchange *solver, SIM_Object *obj, UT_NetMessage *msg)
UT_Vector3 fromVoxelSpace(UT_Vector3 pos) const
void setSize(exint newsize)
Definition: UT_Array.h:666
SYS_FORCE_INLINE void expandBounds(T relative, T absolute)
void initializeSIM(void *)
double fpreal64
Definition: SYS_Types.h:201
PRM_API const PRM_Type PRM_INT
#define UTvdbCallAllType(TYPE, FNAME, GRIDBASE,...)
Definition: UT_VDBUtils.h:401
int8 extractInt8(exint offset)
void GASnetvdbsliceexchangeBuildPacket(GU_PrimVDB *vdb, UT_Array< UT_NetMessage * > &msgs, GAS_NetVDBSliceExchange *solver, SIM_Object *obj, fpreal overlap, exint thisslice, const SIM_SliceSearchTable &slicetable)
GLintptr offset
Definition: glcorearb.h:665
exint length() const
bool receiveDataLoop(UT_Array< UT_NetMessage * > &completed, int expectedmessages, int timeoutms=100)
static PRM_SpareData unitsLength
#define GAS_NAME_TRACKERADDR
Definition: GAS_Utils.h:43
#define GAS_NAME_TRACKERPORT
Definition: GAS_Utils.h:44
void addError(const SIM_RootData *root, int errorcode, const char *errorparm, UT_ErrorSeverity severity) const
Adds an error to our SIM_Engine.
long long int64
Definition: SYS_Types.h:116
void overwriteInt64(exint offset, int64 val)
GLuint const GLchar * name
Definition: glcorearb.h:786
void enlargeBounds(const UT_Vector3T< T > &min, const UT_Vector3T< T > &max)
GLint GLenum GLint x
Definition: glcorearb.h:409
exint append()
Definition: UT_Array.h:142
bool isInsideSlice(const UT_Vector3 &pos) const
int sprintf(const char *fmt,...) SYS_PRINTF_CHECK_ATTRIBUTE(2
exint entries() const
Alias of size(). size() is preferred.
Definition: UT_Array.h:648
GLint j
Definition: glad.h:2733
void assign(T xx=0.0f, T yy=0.0f, T zz=0.0f)
Set the values of the vector components.
Definition: UT_Vector3.h:694
SYS_FORCE_INLINE int strcmp(const char *src) const
bool solveGasSubclass(SIM_Engine &engine, SIM_Object *obj, SIM_Time time, SIM_Time timestep) override
SYS_FORCE_INLINE bool isstring() const
void findAllPrimitivesByName(UT_Array< const GEO_Primitive * > &primlist, const char *nametomatch, const GA_PrimCompat::TypeMask &mask=GEO_PrimTypeCompat::GEOPRIMALL, const char *nameattrib="name") const
Like findPrimitiveByName, but adds all matching primitives to the list.
exint length() const
#define GAS_NAME_JOBNAME
Definition: GAS_Utils.h:45
int int appendSprintf(const char *fmt,...) SYS_PRINTF_CHECK_ATTRIBUTE(2
SYS_FORCE_INLINE void makeGridUnique()
If this primitive's grid's voxel data (i.e., its tree) is shared, replace the tree with a deep copy o...
Definition: GEO_PrimVDB.h:444
This filter rejects all data.
void GASnetvdbsliceexchangeApplyPacketToVDB(GridType &grid, GAS_NetVDBSliceExchange *solver, SIM_Object *obj, UT_NetMessage *msg)
GEO_PrimVolumeXform getIndexSpaceTransform() const
fpreal64 fpreal
Definition: SYS_Types.h:277
void growWriteData(exint newlen)
SYS_FORCE_INLINE bool UTisstring(const char *s)
SYS_FORCE_INLINE void append(char character)
SYS_FORCE_INLINE void initBounds()
**But if you need a or simply need to know when the task has * completed
Definition: thread.h:613
GAS_NetVDBSliceExchange(const SIM_DataFactory *factory)
void GASnetvdbsliceexchangeNetExchange(GAS_NetVDBSliceExchange *solver, SIM_Object *obj, GU_PrimVDB *vdb, const char *tracker, int port, const char *jobname, exint thisslice, const SIM_SliceSearchTable &slicetable)
bool isstring() const
Definition: UT_String.h:691
#define UT_ASSERT(ZZ)
Definition: UT_Assert.h:156
SYS_FORCE_INLINE void clear()
Definition: core.h:1131
void buildSliceSearch(SIM_SliceSearchTable &table) const
SYS_FORCE_INLINE const openvdb::GridBase & getGrid() const
Return a reference to this primitive's grid.
Definition: GEO_PrimVDB.h:460
int64 extractInt64(exint offset)
void GASnetvdbsliceexchangeBuildPacketGrid(GridType &grid, const GEO_PrimVolumeXform &indexxform, UT_Array< UT_NetMessage * > &msgs, GAS_NetVDBSliceExchange *solver, SIM_Object *obj, fpreal overlap, exint thisslice, const SIM_SliceSearchTable &slicetable)
constexpr SYS_FORCE_INLINE T & y() noexcept
Definition: UT_Vector3.h:665
PRM_API PRM_Default PRMzeroDefaults[]
type
Definition: core.h:1059
void overwriteFloat32(exint offset, fpreal32 val)
void sendData(int destpeer, const char *data, exint len)
int16 extractInt16(exint offset)
constexpr SYS_FORCE_INLINE T & x() noexcept
Definition: UT_Vector3.h:663
This implements a SIM_Geometry that copies the source geometry.