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