vtk-m/vtkm/rendering/raytracing/MeshConnectivityContainers.cxx
Haocheng LIU 415252c662 Introduce asynchronous and device independent timer
The timer class now is asynchronous and device independent. it's using an
similiar API as vtkOpenGLRenderTimer with Start(), Stop(), Reset(), Ready(),
and GetElapsedTime() function. For convenience and backward compability, Each
Start() function call will call Reset() internally and each GetElapsedTime()
function call will call Stop() function if it hasn't been called yet for keeping
backward compatibility purpose.

Bascially it can be used in two modes:

* Create a Timer without any device info. vtkm::cont::Timer time;

  * It would enable timers for all enabled devices on the machine. Users can get a
specific elapsed time by passing a device id into the GetElapsedtime function.
If no device is provided, it would pick the maximum of all timer results - the
logic behind this decision is that if cuda is disabled, openmp, serial and tbb
roughly give the same results; if cuda is enabled it's safe to return the
maximum elapsed time since users are more interested in the device execution
time rather than the kernal launch time. The Ready function can be handy here
to query the status of the timer.

* Create a Timer with a device id. vtkm::cont::Timer time((vtkm::cont::DeviceAdapterTagCuda()));

  * It works as the old timer that times for a specific device id.
2019-02-05 12:01:56 -05:00

309 lines
10 KiB
C++

//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//
// Copyright 2015 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
// Copyright 2015 UT-Battelle, LLC.
// Copyright 2015 Los Alamos National Security.
//
// Under the terms of Contract DE-NA0003525 with NTESS,
// the U.S. Government retains certain rights in this software.
//
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//============================================================================
#include <sstream>
#include <vtkm/CellShape.h>
#include <vtkm/cont/ErrorBadValue.h>
#include <vtkm/cont/Timer.h>
#include <vtkm/cont/internal/DeviceAdapterListHelpers.h>
#include <vtkm/rendering/raytracing/BoundingVolumeHierarchy.h>
#include <vtkm/rendering/raytracing/Logger.h>
#include <vtkm/rendering/raytracing/MeshConnectivityBase.h>
#include <vtkm/rendering/raytracing/MeshConnectivityContainers.h>
#include <vtkm/rendering/raytracing/Ray.h>
#include <vtkm/rendering/raytracing/TriangleIntersector.h>
namespace vtkm
{
namespace rendering
{
namespace raytracing
{
MeshConnContainer::MeshConnContainer(){};
MeshConnContainer::~MeshConnContainer(){};
template <typename T>
VTKM_CONT void MeshConnContainer::FindEntryImpl(Ray<T>& rays)
{
bool getCellIndex = true;
Intersector.SetUseWaterTight(true);
Intersector.IntersectRays(rays, getCellIndex);
}
MeshWrapper MeshConnContainer::PrepareForExecution(const vtkm::cont::DeviceAdapterId deviceId)
{
return MeshWrapper(const_cast<MeshConnectivityBase*>(this->Construct(deviceId)));
}
void MeshConnContainer::FindEntry(Ray<vtkm::Float32>& rays)
{
this->FindEntryImpl(rays);
}
void MeshConnContainer::FindEntry(Ray<vtkm::Float64>& rays)
{
this->FindEntryImpl(rays);
}
VTKM_CONT
UnstructuredContainer::UnstructuredContainer(const vtkm::cont::CellSetExplicit<>& cellset,
const vtkm::cont::CoordinateSystem& coords,
IdHandle& faceConn,
IdHandle& faceOffsets,
Id4Handle& triangles)
: FaceConnectivity(faceConn)
, FaceOffsets(faceOffsets)
, Cellset(cellset)
, Coords(coords)
{
this->Triangles = triangles;
//
// Grab the cell arrays
//
CellConn =
Cellset.GetConnectivityArray(vtkm::TopologyElementTagPoint(), vtkm::TopologyElementTagCell());
CellOffsets =
Cellset.GetIndexOffsetArray(vtkm::TopologyElementTagPoint(), vtkm::TopologyElementTagCell());
Shapes = Cellset.GetShapesArray(vtkm::TopologyElementTagPoint(), vtkm::TopologyElementTagCell());
Intersector.SetData(Coords, Triangles);
}
UnstructuredContainer::~UnstructuredContainer(){};
const MeshConnectivityBase* UnstructuredContainer::Construct(
const vtkm::cont::DeviceAdapterId deviceId)
{
switch (deviceId.GetValue())
{
#ifdef VTKM_ENABLE_OPENMP
case VTKM_DEVICE_ADAPTER_OPENMP:
using OMP = vtkm::cont::DeviceAdapterTagOpenMP;
{
MeshConnUnstructured<OMP> conn(this->FaceConnectivity,
this->FaceOffsets,
this->CellConn,
this->CellOffsets,
this->Shapes);
Handle = make_MeshConnHandle(conn);
}
return Handle.PrepareForExecution(OMP());
#endif
#ifdef VTKM_ENABLE_TBB
case VTKM_DEVICE_ADAPTER_TBB:
using TBB = vtkm::cont::DeviceAdapterTagTBB;
{
MeshConnUnstructured<TBB> conn(this->FaceConnectivity,
this->FaceOffsets,
this->CellConn,
this->CellOffsets,
this->Shapes);
Handle = make_MeshConnHandle(conn);
}
return Handle.PrepareForExecution(TBB());
#endif
#ifdef VTKM_ENABLE_CUDA
case VTKM_DEVICE_ADAPTER_CUDA:
using CUDA = vtkm::cont::DeviceAdapterTagCuda;
{
MeshConnUnstructured<CUDA> conn(this->FaceConnectivity,
this->FaceOffsets,
this->CellConn,
this->CellOffsets,
this->Shapes);
Handle = make_MeshConnHandle(conn);
}
return Handle.PrepareForExecution(CUDA());
#endif
case VTKM_DEVICE_ADAPTER_SERIAL:
VTKM_FALLTHROUGH;
default:
using SERIAL = vtkm::cont::DeviceAdapterTagSerial;
{
MeshConnUnstructured<SERIAL> conn(this->FaceConnectivity,
this->FaceOffsets,
this->CellConn,
this->CellOffsets,
this->Shapes);
Handle = make_MeshConnHandle(conn);
}
return Handle.PrepareForExecution(SERIAL());
}
}
VTKM_CONT
UnstructuredSingleContainer::UnstructuredSingleContainer()
{
}
VTKM_CONT
UnstructuredSingleContainer::UnstructuredSingleContainer(
const vtkm::cont::CellSetSingleType<>& cellset,
const vtkm::cont::CoordinateSystem& coords,
IdHandle& faceConn,
Id4Handle& triangles)
: FaceConnectivity(faceConn)
, Coords(coords)
, Cellset(cellset)
{
this->Triangles = triangles;
this->Intersector.SetUseWaterTight(true);
CellConnectivity =
Cellset.GetConnectivityArray(vtkm::TopologyElementTagPoint(), vtkm::TopologyElementTagCell());
vtkm::cont::ArrayHandleConstant<vtkm::UInt8> shapes =
Cellset.GetShapesArray(vtkm::TopologyElementTagPoint(), vtkm::TopologyElementTagCell());
ShapeId = shapes.GetPortalConstControl().Get(0);
CellTables tables;
NumIndices = tables.FaceLookUp(tables.CellTypeLookUp(ShapeId), 2);
if (NumIndices == 0)
{
std::stringstream message;
message << "Unstructured Mesh Connecitity Single type Error: unsupported cell type: ";
message << ShapeId;
throw vtkm::cont::ErrorBadValue(message.str());
}
vtkm::Id start = 0;
NumFaces = tables.FaceLookUp(tables.CellTypeLookUp(ShapeId), 1);
vtkm::Id numCells = CellConnectivity.GetPortalConstControl().GetNumberOfValues();
CellOffsets = vtkm::cont::make_ArrayHandleCounting<vtkm::Id>(start, NumIndices, numCells);
Logger* logger = Logger::GetInstance();
logger->OpenLogEntry("mesh_conn_construction");
Intersector.SetData(Coords, Triangles);
}
const MeshConnectivityBase* UnstructuredSingleContainer::Construct(
const vtkm::cont::DeviceAdapterId deviceId)
{
switch (deviceId.GetValue())
{
#ifdef VTKM_ENABLE_OPENMP
case VTKM_DEVICE_ADAPTER_OPENMP:
using OMP = vtkm::cont::DeviceAdapterTagOpenMP;
{
MeshConnSingleType<OMP> conn(this->FaceConnectivity,
this->CellConnectivity,
this->CellOffsets,
this->ShapeId,
this->NumIndices,
this->NumFaces);
Handle = make_MeshConnHandle(conn);
}
return Handle.PrepareForExecution(OMP());
#endif
#ifdef VTKM_ENABLE_TBB
case VTKM_DEVICE_ADAPTER_TBB:
using TBB = vtkm::cont::DeviceAdapterTagTBB;
{
MeshConnSingleType<TBB> conn(this->FaceConnectivity,
this->CellConnectivity,
this->CellOffsets,
this->ShapeId,
this->NumIndices,
this->NumFaces);
Handle = make_MeshConnHandle(conn);
}
return Handle.PrepareForExecution(TBB());
#endif
#ifdef VTKM_ENABLE_CUDA
case VTKM_DEVICE_ADAPTER_CUDA:
using CUDA = vtkm::cont::DeviceAdapterTagCuda;
{
MeshConnSingleType<CUDA> conn(this->FaceConnectivity,
this->CellConnectivity,
this->CellOffsets,
this->ShapeId,
this->NumIndices,
this->NumFaces);
Handle = make_MeshConnHandle(conn);
}
return Handle.PrepareForExecution(CUDA());
#endif
case VTKM_DEVICE_ADAPTER_SERIAL:
VTKM_FALLTHROUGH;
default:
using SERIAL = vtkm::cont::DeviceAdapterTagSerial;
{
MeshConnSingleType<SERIAL> conn(this->FaceConnectivity,
this->CellConnectivity,
this->CellOffsets,
this->ShapeId,
this->NumIndices,
this->NumFaces);
Handle = make_MeshConnHandle(conn);
}
return Handle.PrepareForExecution(SERIAL());
}
}
StructuredContainer::StructuredContainer(const vtkm::cont::CellSetStructured<3>& cellset,
const vtkm::cont::CoordinateSystem& coords,
Id4Handle& triangles)
: Coords(coords)
, Cellset(cellset)
{
Triangles = triangles;
Intersector.SetUseWaterTight(true);
PointDims = Cellset.GetPointDimensions();
CellDims = Cellset.GetCellDimensions();
this->Intersector.SetData(Coords, Triangles);
}
const MeshConnectivityBase* StructuredContainer::Construct(
const vtkm::cont::DeviceAdapterId deviceId)
{
MeshConnStructured conn(CellDims, PointDims);
Handle = make_MeshConnHandle(conn);
switch (deviceId.GetValue())
{
#ifdef VTKM_ENABLE_OPENMP
case VTKM_DEVICE_ADAPTER_OPENMP:
return Handle.PrepareForExecution(vtkm::cont::DeviceAdapterTagOpenMP());
#endif
#ifdef VTKM_ENABLE_TBB
case VTKM_DEVICE_ADAPTER_TBB:
return Handle.PrepareForExecution(vtkm::cont::DeviceAdapterTagTBB());
#endif
#ifdef VTKM_ENABLE_CUDA
case VTKM_DEVICE_ADAPTER_CUDA:
return Handle.PrepareForExecution(vtkm::cont::DeviceAdapterTagCuda());
#endif
case VTKM_DEVICE_ADAPTER_SERIAL:
VTKM_FALLTHROUGH;
default:
return Handle.PrepareForExecution(vtkm::cont::DeviceAdapterTagSerial());
}
}
}
}
} //namespace vtkm::rendering::raytracing