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