HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
GEO_BuildPrimitives.C
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2021
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  * Definitions of functions for building primitives in bulk.
27  */
28 
29 #include "GEO_BuildPrimitives.h"
30 
31 #include <GEO/GEO_Detail.h>
33 #include <GA/GA_PolyCounts.h>
34 #include <GA/GA_SplittableRange.h>
35 #include <GA/GA_Types.h>
36 #include <UT/UT_Lock.h>
37 #include <UT/UT_ParallelUtil.h>
38 #include <SYS/SYS_Types.h>
39 #include <utility>
40 
41 //#define TIMING_BUILDBLOCK
42 
43 #ifdef TIMING_BUILDBLOCK
44 #include <UT/UT_StopWatch.h>
45 #define TIMING_DEF \
46  UT_StopWatch timer; \
47  timer.start();
48 #define TIMING_LOG(msg) \
49  printf(msg ": %f milliseconds\n", 1000*timer.stop()); \
50  fflush(stdout); \
51  timer.start();
52 #else
53 #define TIMING_DEF
54 #define TIMING_LOG(msg)
55 #endif
56 
57 namespace HDK_Sample {
58 
59 template<typename INT_T>
61  GEO_Detail *detail,
62  const std::pair<int,exint> *primtype_count_pairs,
63  const GA_Offset init_startpt,
64  const GA_Size npoints_per_copy,
65  const GA_PolyCounts &vertexlistsizelist,
66  const INT_T *vertexpointnumbers,
67  const bool hassharedpoints,
68  const exint *closed_span_lengths,
69  const exint ncopies)
70 {
71  if (ncopies <= 0)
72  return GA_INVALID_OFFSET;
73 
74  GA_Size npolygons = vertexlistsizelist.getNumPolygons();
75  if (npolygons == 0)
76  return GA_INVALID_OFFSET;
77 
78  TIMING_DEF;
79 
80  const GA_Size nvertices = vertexlistsizelist.getNumVertices();
81 
82  UT_ASSERT(vertexpointnumbers != nullptr || npoints_per_copy == nvertices || nvertices == 0);
83 
84  // Create the empty primitives and vertices not yet wired to points.
85  GA_Offset init_startvtx;
86  const GA_Offset init_startprim = detail->appendPrimitivesAndVertices(primtype_count_pairs, vertexlistsizelist, init_startvtx, closed_span_lengths, ncopies);
87 
88  TIMING_LOG("Creating primitives");
89 
90  // Nothing more to do if no vertices
91  if (nvertices == 0)
92  return init_startprim;
93 
94  GA_ATITopology *const vertexToPoint = detail->getTopology().getPointRef();
95  GA_ATITopology *const pointToVertex = detail->getTopology().getVertexRef();
96  GA_ATITopology *const vertexToNext = detail->getTopology().getVertexNextRef();
97  GA_ATITopology *const vertexToPrev = detail->getTopology().getVertexPrevRef();
98 
99  // Everything from this point on is independent, except for hardening pages
100  // that have copies from different tasks in them.
101  auto &&functor = [init_startvtx,nvertices,init_startpt,npoints_per_copy,
102  vertexToPoint,pointToVertex,vertexToNext,vertexToPrev,
103  detail,vertexpointnumbers,hassharedpoints](const UT_BlockedRange<exint> &r)
104  {
105  GA_Offset startvtx = init_startvtx + r.begin()*nvertices;
106  GA_Offset startpt = init_startpt + r.begin()*npoints_per_copy;
107  for (exint copyi = r.begin(), endcopyi = r.end(); copyi < endcopyi; ++copyi, startvtx += nvertices, startpt += npoints_per_copy)
108  {
109  const GA_Offset endvtx = startvtx + nvertices;
110  const GA_Offset endpt = startpt + npoints_per_copy;
111 
112  TIMING_DEF;
113 
114  // Set the vertex-to-point mapping
115  if (vertexToPoint)
116  {
117  UTparallelForLightItems(GA_SplittableRange(GA_Range(detail->getVertexMap(), startvtx, endvtx)),
118  geo_SetTopoMappedParallel<INT_T>(vertexToPoint, startpt, startvtx, vertexpointnumbers));
119 
120  TIMING_LOG("Setting vtx->pt");
121  }
122 
123  // Check whether the linked list topologies need to be set
124 
125  if (vertexpointnumbers == nullptr)
126  {
127  if (pointToVertex)
128  {
129  // Only need to set pointToVertex, because next and prev will be
130  // default of GA_INVALID_OFFSET
131 
132  UTparallelForLightItems(GA_SplittableRange(GA_Range(detail->getPointMap(), startpt, endpt)),
133  geo_SetTopoMappedParallel<INT_T>(pointToVertex, startvtx, startpt, nullptr));
134 
135  TIMING_LOG("Setting pt->vtx fast");
136  }
137 
138  // That's all, for this simple case!
139  continue;
140  }
141  if (!hassharedpoints)
142  {
143  // Set the point-to-vertex mapping
144  if (pointToVertex)
145  {
146  pointToVertex->hardenAllPages(startpt, endpt);
147  UTparallelForLightItems(GA_SplittableRange(GA_Range(detail->getVertexMap(), startvtx, endvtx)),
148  geo_SetTopoRevMappedParallel<INT_T>(pointToVertex, startpt, startvtx, vertexpointnumbers));
149 
150  TIMING_LOG("Setting pt->vtx no shared points");
151  }
152 
153  // That's all, for this simple case!
154  continue;
155  }
156 
157  if (pointToVertex && vertexToNext && vertexToPrev)
158  {
159  // Create a trivial map from 0 to nvertices
160  UT_Array<INT_T> map;
161  map.setSizeNoInit(nvertices);
162 
163  TIMING_LOG("Allocating map");
164 
165  UTparallelForLightItems(UT_BlockedRange<GA_Size>(0, nvertices), geo_TrivialArrayParallel<INT_T>(map));
166 
167  TIMING_LOG("Creating trivial map");
168 
169  // Sort the map in parallel according to the point offsets of the vertices
170  UTparallelSort(map.array(), map.array() + nvertices, geo_VerticesByPointCompare<INT_T,true>(vertexpointnumbers));
171 
172  TIMING_LOG("Sorting array map");
173 
174  // Create arrays for the next vertex and prev vertex in parallel
175  // If we wanted to do this in geo_LinkToposParallel, we would first
176  // have to create an inverse map anyway to find out where vertices
177  // are in map, so this saves re-traversing things.
178  UT_Array<INT_T> nextvtxarray;
179  UT_Array<INT_T> prevvtxarray;
180  nextvtxarray.setSizeNoInit(nvertices);
181  prevvtxarray.setSizeNoInit(nvertices);
182  UT_Lock lock;
184  geo_NextPrevParallel<INT_T>(
185  map.getArray(), map.size(),
186  vertexpointnumbers,
187  nextvtxarray.getArray(), prevvtxarray.getArray(),
188  startvtx, startpt, pointToVertex, vertexToPrev, lock));
189 
190  TIMING_LOG("Finding next/prev");
191 
192  // Set the point-to-vertex topology in parallel
193  // This needs to be done after constructing the next/prev array,
194  // because it checks for existing vertices using the points.
195  UTparallelForLightItems(GA_SplittableRange(GA_Range(detail->getPointMap(), startpt, endpt)),
196  geo_Pt2VtxTopoParallel<INT_T>(pointToVertex, map.getArray(), map.size(), vertexpointnumbers, startvtx, startpt));
197 
198  TIMING_LOG("Setting pt->vtx");
199 
200  // Clear up some memory before filling up the linked list topologies
201  map.setCapacity(0);
202 
203  TIMING_LOG("Clearing map");
204 
205  // Fill in the linked list topologies
206  UTparallelForLightItems(GA_SplittableRange(GA_Range(detail->getVertexMap(), startvtx, endvtx)),
207  geo_LinkToposParallel<INT_T>(vertexToNext, vertexToPrev, nextvtxarray.getArray(), prevvtxarray.getArray(), startvtx));
208 
209  TIMING_LOG("Setting links");
210  }
211  }
212  };
213 
214  constexpr exint PARALLEL_THRESHOLD = 4096;
215  if (ncopies >= 2 && ncopies*nvertices >= PARALLEL_THRESHOLD)
216  {
217  // Harden pages in order to parallelize safely.
218  // TODO: Only harden pages that stradle task boundaries.
219  GA_Offset endvtx = init_startvtx + nvertices*ncopies;
220  GA_Offset endpt = init_startpt + npoints_per_copy*ncopies;
221  if (vertexToPoint)
222  vertexToPoint->hardenAllPages(init_startvtx, endvtx);
223  if (pointToVertex)
224  pointToVertex->hardenAllPages(init_startpt, endpt);
225  if (vertexpointnumbers != nullptr && hassharedpoints && vertexToNext && vertexToPrev)
226  {
227  vertexToNext->hardenAllPages(init_startvtx, endvtx);
228  vertexToPrev->hardenAllPages(init_startvtx, endvtx);
229  }
230 
231  UTparallelFor(UT_BlockedRange<exint>(0,ncopies), functor);
232  }
233  else
234  {
235  functor(UT_BlockedRange<exint>(0,ncopies));
236  }
237 
238  return init_startprim;
239 }
240 
241 // Template instantiations
243  GEO_Detail *detail,
244  const std::pair<int,exint> *primtype_count_pairs,
245  const GA_Offset init_startpt,
246  const GA_Size npoints_per_copy,
247  const GA_PolyCounts &polygonsizelist,
248  const int *polygonpointnumbers,
249  const bool hassharedpoints,
250  const exint *closed_span_lengths,
251  const exint ncopies);
253  GEO_Detail *detail,
254  const std::pair<int,exint> *primtype_count_pairs,
255  const GA_Offset init_startpt,
256  const GA_Size npoints_per_copy,
257  const GA_PolyCounts &polygonsizelist,
258  const exint *polygonpointnumbers,
259  const bool hassharedpoints,
260  const exint *closed_span_lengths,
261  const exint ncopies);
262 
263 } // End of HDK_Sample namespace
void UTparallelSort(RandomAccessIterator begin, RandomAccessIterator end, const Compare &compare)
#define TIMING_DEF
void setSizeNoInit(exint newsize)
Definition: UT_Array.h:507
template GA_Offset GEObuildPrimitives< exint >(GEO_Detail *detail, const std::pair< int, exint > *primtype_count_pairs, const GA_Offset init_startpt, const GA_Size npoints_per_copy, const GA_PolyCounts &polygonsizelist, const exint *polygonpointnumbers, const bool hassharedpoints, const exint *closed_span_lengths, const exint ncopies)
int64 exint
Definition: SYS_Types.h:125
T * array()
Definition: UT_Array.h:631
GA_Size getNumVertices() const
exint size() const
Definition: UT_Array.h:458
exint GA_Size
Defines the bit width for index and offset types in GA.
Definition: GA_Types.h:233
#define GA_INVALID_OFFSET
Definition: GA_Types.h:676
A range of elements in an index-map.
Definition: GA_Range.h:42
GA_Size GA_Offset
Definition: GA_Types.h:639
GA_Offset GEObuildPrimitives(GEO_Detail *detail, const std::pair< int, exint > *primtype_count_pairs, const GA_Offset init_startpt, const GA_Size npoints_per_copy, const GA_PolyCounts &vertexlistsizelist, const INT_T *vertexpointnumbers, const bool hassharedpoints, const exint *closed_span_lengths, const exint ncopies)
GA_Size getNumPolygons() const
void setCapacity(exint newcapacity)
Definition: UT_ArrayImpl.h:777
void UTparallelForLightItems(const Range &range, const Body &body)
SYS_FORCE_INLINE const GA_ATITopology * getVertexNextRef() const
Definition: GA_Topology.h:229
GA_Topology & getTopology()
Definition: GA_Detail.h:741
SYS_FORCE_INLINE const GA_ATITopology * getVertexPrevRef() const
Definition: GA_Topology.h:227
SYS_FORCE_INLINE const GA_ATITopology * getVertexRef() const
Definition: GA_Topology.h:225
GLdouble GLdouble GLdouble r
Definition: glew.h:1406
#define TIMING_LOG(msg)
template GA_Offset GEObuildPrimitives< int >(GEO_Detail *detail, const std::pair< int, exint > *primtype_count_pairs, const GA_Offset init_startpt, const GA_Size npoints_per_copy, const GA_PolyCounts &polygonsizelist, const int *polygonpointnumbers, const bool hassharedpoints, const exint *closed_span_lengths, const exint ncopies)
#define UT_ASSERT(ZZ)
Definition: UT_Assert.h:135
Declare prior to use.
SYS_FORCE_INLINE const GA_ATITopology * getPointRef() const
Definition: GA_Topology.h:221
void UTparallelFor(const Range &range, const Body &body, const int subscribe_ratio=2, const int min_grain_size=1)
T * getArray() const
Definition: UT_Array.h:628
GA_Offset appendPrimitivesAndVertices(const GA_PrimitiveTypeId &type, GA_Size nprimitives, GA_Size nvertices_each, GA_Offset &vertex_block_start, bool closed_flag=false)