1 //============================================================================
2 //  Copyright (c) Kitware, Inc.
3 //  All rights reserved.
4 //  See LICENSE.txt for details.
5 //
6 //  This software is distributed WITHOUT ANY WARRANTY; without even
7 //  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
8 //  PURPOSE.  See the above copyright notice for more information.
9 //============================================================================
10 #ifndef vtk_m_rendering_raytracing_MeshConnectivityBase
11 #define vtk_m_rendering_raytracing_MeshConnectivityBase
12 
13 #include <sstream>
14 #include <vtkm/CellShape.h>
15 #include <vtkm/VirtualObjectBase.h>
16 #include <vtkm/cont/ErrorBadValue.h>
17 #include <vtkm/cont/VirtualObjectHandle.h>
18 #include <vtkm/rendering/raytracing/BoundingVolumeHierarchy.h>
19 #include <vtkm/rendering/raytracing/CellTables.h>
20 #include <vtkm/rendering/raytracing/Logger.h>
21 #include <vtkm/rendering/raytracing/Ray.h>
22 #include <vtkm/rendering/raytracing/TriangleIntersector.h>
23 
24 namespace vtkm
25 {
26 namespace rendering
27 {
28 namespace raytracing
29 {
30 //
31 // Base class for different types of face-to-connecting-cell
32 // and other mesh information
33 //
34 class VTKM_ALWAYS_EXPORT MeshConnectivityBase : public VirtualObjectBase
35 {
36 public:
37   VTKM_EXEC_CONT
38   virtual vtkm::Id GetConnectingCell(const vtkm::Id& cellId, const vtkm::Id& face) const = 0;
39 
40   VTKM_EXEC_CONT
41   virtual vtkm::Int32 GetCellIndices(vtkm::Id cellIndices[8], const vtkm::Id& cellId) const = 0;
42 
43   VTKM_EXEC_CONT
44   virtual vtkm::UInt8 GetCellShape(const vtkm::Id& cellId) const = 0;
45 };
46 
47 // A simple concrete type to wrap MeshConnectivityBase so we can
48 // pass an ExeObject to worklets.
49 class MeshWrapper
50 {
51 private:
52   MeshConnectivityBase* MeshConn;
53 
54 public:
MeshWrapper()55   MeshWrapper() {}
56 
MeshWrapper(MeshConnectivityBase * meshConn)57   MeshWrapper(MeshConnectivityBase* meshConn)
58     : MeshConn(meshConn){};
59 
60   VTKM_EXEC_CONT
GetConnectingCell(const vtkm::Id & cellId,const vtkm::Id & face)61   vtkm::Id GetConnectingCell(const vtkm::Id& cellId, const vtkm::Id& face) const
62   {
63     return MeshConn->GetConnectingCell(cellId, face);
64   }
65 
66   VTKM_EXEC_CONT
GetCellIndices(vtkm::Id cellIndices[8],const vtkm::Id & cellId)67   vtkm::Int32 GetCellIndices(vtkm::Id cellIndices[8], const vtkm::Id& cellId) const
68   {
69     return MeshConn->GetCellIndices(cellIndices, cellId);
70   }
71 
72   VTKM_EXEC_CONT
GetCellShape(const vtkm::Id & cellId)73   vtkm::UInt8 GetCellShape(const vtkm::Id& cellId) const { return MeshConn->GetCellShape(cellId); }
74 };
75 
76 class VTKM_ALWAYS_EXPORT MeshConnStructured : public MeshConnectivityBase
77 {
78 protected:
79   typedef typename vtkm::cont::ArrayHandle<vtkm::Id4> Id4Handle;
80   vtkm::Id3 CellDims;
81   vtkm::Id3 PointDims;
82 
83   VTKM_CONT MeshConnStructured() = default;
84 
85 public:
86   VTKM_CONT
MeshConnStructured(const vtkm::Id3 & cellDims,const vtkm::Id3 & pointDims)87   MeshConnStructured(const vtkm::Id3& cellDims, const vtkm::Id3& pointDims)
88     : CellDims(cellDims)
89     , PointDims(pointDims)
90   {
91   }
92 
93   VTKM_EXEC_CONT
GetConnectingCell(const vtkm::Id & cellId,const vtkm::Id & face)94   vtkm::Id GetConnectingCell(const vtkm::Id& cellId, const vtkm::Id& face) const override
95   {
96     //TODO: there is probably a better way to do this.
97     vtkm::Id3 logicalCellId;
98     logicalCellId[0] = cellId % CellDims[0];
99     logicalCellId[1] = (cellId / CellDims[0]) % CellDims[1];
100     logicalCellId[2] = cellId / (CellDims[0] * CellDims[1]);
101     if (face == 0)
102       logicalCellId[1] -= 1;
103     if (face == 2)
104       logicalCellId[1] += 1;
105     if (face == 1)
106       logicalCellId[0] += 1;
107     if (face == 3)
108       logicalCellId[0] -= 1;
109     if (face == 4)
110       logicalCellId[2] -= 1;
111     if (face == 5)
112       logicalCellId[2] += 1;
113     vtkm::Id nextCell =
114       (logicalCellId[2] * CellDims[1] + logicalCellId[1]) * CellDims[0] + logicalCellId[0];
115     bool validCell = true;
116     if (logicalCellId[0] >= CellDims[0])
117       validCell = false;
118     if (logicalCellId[1] >= CellDims[1])
119       validCell = false;
120     if (logicalCellId[2] >= CellDims[2])
121       validCell = false;
122     vtkm::Id minId = vtkm::Min(logicalCellId[0], vtkm::Min(logicalCellId[1], logicalCellId[2]));
123     if (minId < 0)
124       validCell = false;
125     if (!validCell)
126       nextCell = -1;
127     return nextCell;
128   }
129 
130   VTKM_EXEC_CONT
GetCellIndices(vtkm::Id cellIndices[8],const vtkm::Id & cellIndex)131   vtkm::Int32 GetCellIndices(vtkm::Id cellIndices[8], const vtkm::Id& cellIndex) const override
132   {
133     vtkm::Id3 cellId;
134     cellId[0] = cellIndex % CellDims[0];
135     cellId[1] = (cellIndex / CellDims[0]) % CellDims[1];
136     cellId[2] = cellIndex / (CellDims[0] * CellDims[1]);
137     cellIndices[0] = (cellId[2] * PointDims[1] + cellId[1]) * PointDims[0] + cellId[0];
138     cellIndices[1] = cellIndices[0] + 1;
139     cellIndices[2] = cellIndices[1] + PointDims[0];
140     cellIndices[3] = cellIndices[2] - 1;
141     cellIndices[4] = cellIndices[0] + PointDims[0] * PointDims[1];
142     cellIndices[5] = cellIndices[4] + 1;
143     cellIndices[6] = cellIndices[5] + PointDims[0];
144     cellIndices[7] = cellIndices[6] - 1;
145     return 8;
146   }
147 
148   VTKM_EXEC
GetCellShape(const vtkm::Id & vtkmNotUsed (cellId))149   vtkm::UInt8 GetCellShape(const vtkm::Id& vtkmNotUsed(cellId)) const override
150   {
151     return vtkm::UInt8(CELL_SHAPE_HEXAHEDRON);
152   }
153 }; // MeshConnStructured
154 
155 template <typename Device>
156 class VTKM_ALWAYS_EXPORT MeshConnUnstructured : public MeshConnectivityBase
157 {
158 protected:
159   using IdHandle = typename vtkm::cont::ArrayHandle<vtkm::Id>;
160   using UCharHandle = typename vtkm::cont::ArrayHandle<vtkm::UInt8>;
161   using IdConstPortal = typename IdHandle::ReadPortalType;
162   using UCharConstPortal = typename UCharHandle::ReadPortalType;
163 
164   // Constant Portals for the execution Environment
165   //FaceConn
166   IdConstPortal FaceConnPortal;
167   IdConstPortal FaceOffsetsPortal;
168   //Cell Set
169   IdConstPortal CellConnPortal;
170   IdConstPortal CellOffsetsPortal;
171   UCharConstPortal ShapesPortal;
172 
173   VTKM_CONT MeshConnUnstructured() = default;
174 
175 public:
176   VTKM_CONT
MeshConnUnstructured(const IdHandle & faceConnectivity,const IdHandle & faceOffsets,const IdHandle & cellConn,const IdHandle & cellOffsets,const UCharHandle & shapes,vtkm::cont::Token & token)177   MeshConnUnstructured(const IdHandle& faceConnectivity,
178                        const IdHandle& faceOffsets,
179                        const IdHandle& cellConn,
180                        const IdHandle& cellOffsets,
181                        const UCharHandle& shapes,
182                        vtkm::cont::Token& token)
183     : FaceConnPortal(faceConnectivity.PrepareForInput(Device(), token))
184     , FaceOffsetsPortal(faceOffsets.PrepareForInput(Device(), token))
185     , CellConnPortal(cellConn.PrepareForInput(Device(), token))
186     , CellOffsetsPortal(cellOffsets.PrepareForInput(Device(), token))
187     , ShapesPortal(shapes.PrepareForInput(Device(), token))
188   {
189   }
190 
191   VTKM_EXEC_CONT
GetConnectingCell(const vtkm::Id & cellId,const vtkm::Id & face)192   vtkm::Id GetConnectingCell(const vtkm::Id& cellId, const vtkm::Id& face) const override
193   {
194     BOUNDS_CHECK(FaceOffsetsPortal, cellId);
195     vtkm::Id cellStartIndex = FaceOffsetsPortal.Get(cellId);
196     BOUNDS_CHECK(FaceConnPortal, cellStartIndex + face);
197     return FaceConnPortal.Get(cellStartIndex + face);
198   }
199 
200   //----------------------------------------------------------------------------
201   VTKM_EXEC
GetCellIndices(vtkm::Id cellIndices[8],const vtkm::Id & cellId)202   vtkm::Int32 GetCellIndices(vtkm::Id cellIndices[8], const vtkm::Id& cellId) const override
203   {
204     const vtkm::Int32 shapeId = static_cast<vtkm::Int32>(ShapesPortal.Get(cellId));
205     CellTables tables;
206     const vtkm::Int32 numIndices = tables.FaceLookUp(tables.CellTypeLookUp(shapeId), 2);
207     BOUNDS_CHECK(CellOffsetsPortal, cellId);
208     const vtkm::Id cellOffset = CellOffsetsPortal.Get(cellId);
209 
210     for (vtkm::Int32 i = 0; i < numIndices; ++i)
211     {
212       BOUNDS_CHECK(CellConnPortal, cellOffset + i);
213       cellIndices[i] = CellConnPortal.Get(cellOffset + i);
214     }
215     return numIndices;
216   }
217 
218   //----------------------------------------------------------------------------
219   VTKM_EXEC
GetCellShape(const vtkm::Id & cellId)220   vtkm::UInt8 GetCellShape(const vtkm::Id& cellId) const override
221   {
222     BOUNDS_CHECK(ShapesPortal, cellId);
223     return ShapesPortal.Get(cellId);
224   }
225 
226 }; // MeshConnUnstructured
227 
228 template <typename Device>
229 class MeshConnSingleType : public MeshConnectivityBase
230 {
231 protected:
232   using IdHandle = typename vtkm::cont::ArrayHandle<vtkm::Id>;
233   using IdConstPortal = typename IdHandle::ReadPortalType;
234 
235   using CountingHandle = typename vtkm::cont::ArrayHandleCounting<vtkm::Id>;
236   using CountingPortal = typename CountingHandle::ReadPortalType;
237   // Constant Portals for the execution Environment
238   IdConstPortal FaceConnPortal;
239   IdConstPortal CellConnectivityPortal;
240   CountingPortal CellOffsetsPortal;
241 
242   vtkm::Int32 ShapeId;
243   vtkm::Int32 NumIndices;
244   vtkm::Int32 NumFaces;
245 
246 private:
247   VTKM_CONT
MeshConnSingleType()248   MeshConnSingleType() {}
249 
250 public:
251   VTKM_CONT
MeshConnSingleType(IdHandle & faceConn,IdHandle & cellConn,CountingHandle & cellOffsets,vtkm::Int32 shapeId,vtkm::Int32 numIndices,vtkm::Int32 numFaces,vtkm::cont::Token & token)252   MeshConnSingleType(IdHandle& faceConn,
253                      IdHandle& cellConn,
254                      CountingHandle& cellOffsets,
255                      vtkm::Int32 shapeId,
256                      vtkm::Int32 numIndices,
257                      vtkm::Int32 numFaces,
258                      vtkm::cont::Token& token)
259     : FaceConnPortal(faceConn.PrepareForInput(Device(), token))
260     , CellConnectivityPortal(cellConn.PrepareForInput(Device(), token))
261     , CellOffsetsPortal(cellOffsets.PrepareForInput(Device(), token))
262     , ShapeId(shapeId)
263     , NumIndices(numIndices)
264     , NumFaces(numFaces)
265   {
266   }
267 
268   //----------------------------------------------------------------------------
269   //                       Execution Environment Methods
270   //----------------------------------------------------------------------------
271   VTKM_EXEC
GetConnectingCell(const vtkm::Id & cellId,const vtkm::Id & face)272   vtkm::Id GetConnectingCell(const vtkm::Id& cellId, const vtkm::Id& face) const override
273   {
274     BOUNDS_CHECK(CellOffsetsPortal, cellId);
275     vtkm::Id cellStartIndex = cellId * NumFaces;
276     BOUNDS_CHECK(FaceConnPortal, cellStartIndex + face);
277     return FaceConnPortal.Get(cellStartIndex + face);
278   }
279 
280   VTKM_EXEC
GetCellIndices(vtkm::Id cellIndices[8],const vtkm::Id & cellId)281   vtkm::Int32 GetCellIndices(vtkm::Id cellIndices[8], const vtkm::Id& cellId) const override
282   {
283     BOUNDS_CHECK(CellOffsetsPortal, cellId);
284     const vtkm::Id cellOffset = CellOffsetsPortal.Get(cellId);
285 
286     for (vtkm::Int32 i = 0; i < NumIndices; ++i)
287     {
288       BOUNDS_CHECK(CellConnectivityPortal, cellOffset + i);
289       cellIndices[i] = CellConnectivityPortal.Get(cellOffset + i);
290     }
291 
292     return NumIndices;
293   }
294 
295   //----------------------------------------------------------------------------
296   VTKM_EXEC
GetCellShape(const vtkm::Id & vtkmNotUsed (cellId))297   vtkm::UInt8 GetCellShape(const vtkm::Id& vtkmNotUsed(cellId)) const override
298   {
299     return vtkm::UInt8(ShapeId);
300   }
301 
302 }; //MeshConn Single type specialization
303 
304 class VTKM_ALWAYS_EXPORT MeshConnHandle
305   : public vtkm::cont::VirtualObjectHandle<MeshConnectivityBase>
306 {
307 private:
308   using Superclass = vtkm::cont::VirtualObjectHandle<MeshConnectivityBase>;
309 
310 public:
311   MeshConnHandle() = default;
312 
313   template <typename MeshConnType, typename DeviceAdapterList = VTKM_DEFAULT_DEVICE_ADAPTER_LIST>
314   explicit MeshConnHandle(MeshConnType* meshConn,
315                           bool aquireOwnership = true,
316                           DeviceAdapterList devices = DeviceAdapterList())
Superclass(meshConn,aquireOwnership,devices)317     : Superclass(meshConn, aquireOwnership, devices)
318   {
319   }
320 };
321 
322 template <typename MeshConnType, typename DeviceAdapterList = VTKM_DEFAULT_DEVICE_ADAPTER_LIST>
323 VTKM_CONT MeshConnHandle make_MeshConnHandle(MeshConnType&& func,
324                                              DeviceAdapterList devices = DeviceAdapterList())
325 {
326   using IFType = typename std::remove_reference<MeshConnType>::type;
327   return MeshConnHandle(new IFType(std::forward<MeshConnType>(func)), true, devices);
328 }
329 }
330 }
331 } //namespace vtkm::rendering::raytracing
332 
333 
334 // Cuda seems to have a bug where it expects the template class VirtualObjectTransfer
335 // to be instantiated in a consistent order among all the translation units of an
336 // executable. Failing to do so results in random crashes and incorrect results.
337 // We workaroud this issue by explicitly instantiating VirtualObjectTransfer for
338 // all the implicit functions here.
339 #ifdef VTKM_CUDA
340 #include <vtkm/cont/internal/VirtualObjectTransferInstantiate.h>
341 VTKM_EXPLICITLY_INSTANTIATE_TRANSFER(vtkm::rendering::raytracing::MeshConnStructured);
342 VTKM_EXPLICITLY_INSTANTIATE_TRANSFER_CUDA(
343   vtkm::rendering::raytracing::MeshConnUnstructured<vtkm::cont::DeviceAdapterTagCuda>);
344 VTKM_EXPLICITLY_INSTANTIATE_TRANSFER_KOKKOS(
345   vtkm::rendering::raytracing::MeshConnUnstructured<vtkm::cont::DeviceAdapterTagKokkos>);
346 #endif
347 
348 #endif // MeshConnectivityBase
349