Commit ef83adf3 authored by Robert Maynard's avatar Robert Maynard
Browse files

Field, CoordinateSystem, VirtualCoordinates all use the new virtual code

parent 3d67a008
......@@ -59,6 +59,12 @@ public:
ArrayHandle()
: Storage(nullptr){};
/// virtual destructor, as required to make sure derived classes that
/// might have member variables are properly cleaned up.
//
virtual ~ArrayHandle() = default;
///Move existing shared_ptr of vtkm::cont::StorageVirtual to be
///owned by this ArrayHandleVirtual.
///This is generally how derived class construct a valid ArrayHandleVirtual
......@@ -107,23 +113,20 @@ public:
VTKM_CONT bool IsType() const
{
VTKM_IS_ARRAY_HANDLE(ArrayHandleType);
//We need to go long the way to find the StorageType
//as StorageType is private on lots of derived ArrayHandles
//See Issue #314
using VT = typename ArrayHandleType::ValueType;
static_assert(
std::is_same<VT, T>::value,
"ArrayHandleVirtual<ValueType> can only be casted to an ArrayHandle of the same ValueType.");
//We need to determine if we are checking that `ArrayHandleType`
//is a virtual array handle since that is an easy check.
//Or if we have to go ask the storage if they are holding
//
using ST = typename ArrayHandleType::StorageTag;
return this->Storage->IsType(typeid(vtkm::cont::internal::Storage<VT, ST>));
using is_base = std::is_same<vtkm::cont::StorageTagVirtual, ST>;
return this->IsSameType<ArrayHandleType>(is_base{});
}
/// Returns a view on the internal storage of the ArrayHandleVirtual
///
VTKM_CONT const StorageType* GetStorage() const { return this->Storage.get(); }
/// Returns a new instance of an ArrayHandleVirtual with the same storage
///
VTKM_CONT ArrayHandle<T, ::vtkm::cont::StorageTagVirtual> NewInstance() const
......@@ -133,29 +136,57 @@ public:
: ArrayHandle<T, ::vtkm::cont::StorageTagVirtual>();
}
// Return a ArrayPortalRef that wraps the real virtual portal. We need a stack object for
// the following reasons:
// 1. Device Adapter algorithms only support const AH<T,S>& and not const AH<T,S>*
// 2. Devices will want to get the length of a portal before execution, but for CUDA
// we can't ask this information of the portal as it only valid on the device, instead
// we have to store this information also in the ref wrapper
vtkm::ArrayPortalRef<T> PrepareForInput(vtkm::cont::DeviceAdapterId devId) const
/// Returns a view on the internal storage of the ArrayHandleVirtual
///
VTKM_CONT const StorageType* GetStorage() const { return this->Storage.get(); }
/// Get the array portal of the control array.
/// Since worklet invocations are asynchronous and this routine is a synchronization point,
/// exceptions maybe thrown for errors from previously executed worklets.
///
PortalControl GetPortalControl()
{
return make_ArrayPortalRef(
static_cast<const vtkm::ArrayPortalVirtual<T>*>(this->Storage->PrepareForInput(devId)),
static_cast<const vtkm::ArrayPortalVirtual<T>*>(this->Storage->GetPortalControl()),
this->GetNumberOfValues());
}
vtkm::ArrayPortalRef<T> PrepareForOutput(vtkm::Id numberOfValues,
vtkm::cont::DeviceAdapterId devId)
/// Get the array portal of the control array.
/// Since worklet invocations are asynchronous and this routine is a synchronization point,
/// exceptions maybe thrown for errors from previously executed worklets.
///
PortalConstControl GetPortalConstControl() const
{
return make_ArrayPortalRef(static_cast<const vtkm::ArrayPortalVirtual<T>*>(
this->Storage->PrepareForOutput(numberOfValues, devId)),
numberOfValues);
return make_ArrayPortalRef(
static_cast<const vtkm::ArrayPortalVirtual<T>*>(this->Storage->GetPortalConstControl()),
this->GetNumberOfValues());
}
/// Returns the number of entries in the array.
///
vtkm::Id GetNumberOfValues() const { return this->Storage->GetNumberOfValues(); }
/// \brief Allocates an array large enough to hold the given number of values.
///
/// The allocation may be done on an already existing array, but can wipe out
/// any data already in the array. This method can throw
/// ErrorBadAllocation if the array cannot be allocated or
/// ErrorBadValue if the allocation is not feasible (for example, the
/// array storage is read-only).
///
VTKM_CONT
void Allocate(vtkm::Id numberOfValues) { return this->Storage->Allocate(numberOfValues); }
/// \brief Reduces the size of the array without changing its values.
///
/// This method allows you to resize the array without reallocating it. The
/// number of entries in the array is changed to \c numberOfValues. The data
/// in the array (from indices 0 to \c numberOfValues - 1) are the same, but
/// \c numberOfValues must be equal or less than the preexisting size
/// (returned from GetNumberOfValues). That is, this method can only be used
/// to shorten the array, not lengthen.
void Shrink(vtkm::Id numberOfValues) { return this->Storage->Shrink(numberOfValues); }
/// Releases any resources being used in the execution environment (that are
/// not being shared by the control environment).
///
......@@ -165,30 +196,80 @@ public:
///
void ReleaseResources() { return this->Storage->ReleaseResources(); }
/// Get the array portal of the control array.
/// Since worklet invocations are asynchronous and this routine is a synchronization point,
/// exceptions maybe thrown for errors from previously executed worklets.
/// Prepares this array to be used as an input to an operation in the
/// execution environment. If necessary, copies data to the execution
/// environment. Can throw an exception if this array does not yet contain
/// any data. Returns a portal that can be used in code running in the
/// execution environment.
///
PortalControl GetPortalControl()
/// Return a ArrayPortalRef that wraps the real virtual portal. We need a stack object for
/// the following reasons:
/// 1. Device Adapter algorithms only support const AH<T,S>& and not const AH<T,S>*
/// 2. Devices will want to get the length of a portal before execution, but for CUDA
/// we can't ask this information of the portal as it only valid on the device, instead
/// we have to store this information also in the ref wrapper
vtkm::ArrayPortalRef<T> PrepareForInput(vtkm::cont::DeviceAdapterId devId) const
{
return make_ArrayPortalRef(
static_cast<const vtkm::ArrayPortalVirtual<T>*>(this->Storage->GetPortalControl()),
static_cast<const vtkm::ArrayPortalVirtual<T>*>(this->Storage->PrepareForInput(devId)),
this->GetNumberOfValues());
}
/// Get the array portal of the control array.
/// Since worklet invocations are asynchronous and this routine is a synchronization point,
/// exceptions maybe thrown for errors from previously executed worklets.
/// Prepares (allocates) this array to be used as an output from an operation
/// in the execution environment. The internal state of this class is set to
/// have valid data in the execution array with the assumption that the array
/// will be filled soon (i.e. before any other methods of this object are
/// called). Returns a portal that can be used in code running in the
/// execution environment.
///
PortalConstControl GetPortalConstControl() const
vtkm::ArrayPortalRef<T> PrepareForOutput(vtkm::Id numberOfValues,
vtkm::cont::DeviceAdapterId devId)
{
return make_ArrayPortalRef(static_cast<const vtkm::ArrayPortalVirtual<T>*>(
this->Storage->PrepareForOutput(numberOfValues, devId)),
numberOfValues);
}
/// Prepares this array to be used in an in-place operation (both as input
/// and output) in the execution environment. If necessary, copies data to
/// the execution environment. Can throw an exception if this array does not
/// yet contain any data. Returns a portal that can be used in code running
/// in the execution environment.
///
vtkm::ArrayPortalRef<T> PrepareForInPlace(vtkm::cont::DeviceAdapterId devId)
{
return make_ArrayPortalRef(
static_cast<const vtkm::ArrayPortalVirtual<T>*>(this->Storage->GetPortalConstControl()),
static_cast<const vtkm::ArrayPortalVirtual<T>*>(this->Storage->PrepareForInput(devId)),
this->GetNumberOfValues());
}
/// Returns the DeviceAdapterId for the current device. If there is no device
/// with an up-to-date copy of the data, VTKM_DEVICE_ADAPTER_UNDEFINED is
/// returned.
VTKM_CONT
DeviceAdapterId GetDeviceAdapterId() const { return this->Storage->GetDeviceAdapterId(); }
protected:
std::shared_ptr<StorageType> Storage = nullptr;
private:
template <typename ArrayHandleType>
bool IsSameType(std::true_type vtkmNotUsed(inheritsFromArrayHandleVirtual)) const
{
//All classes that derive from ArrayHandleVirtual have virtual methods so we can use
//typeid directly
return typeid(*this) == typeid(ArrayHandleType);
}
template <typename ArrayHandleType>
bool IsSameType(std::false_type vtkmNotUsed(notFromArrayHandleVirtual)) const
{
//We need to go long the way to find the StorageType
//as StorageType is private on lots of derived ArrayHandles
//See Issue #314
using ST = typename ArrayHandleType::StorageTag;
return this->Storage->IsType(typeid(vtkm::cont::internal::Storage<T, ST>));
}
};
template <typename T>
......
......@@ -20,17 +20,16 @@
#ifndef vtk_m_cont_ArrayHandleVirtualCoordinates_h
#define vtk_m_cont_ArrayHandleVirtualCoordinates_h
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/ArrayHandleAny.h>
#include <vtkm/cont/ArrayHandleVirtual.h>
#include <vtkm/cont/ArrayHandleCartesianProduct.h>
#include <vtkm/cont/ArrayHandleCast.h>
#include <vtkm/cont/ArrayHandleUniformPointCoordinates.h>
#include <vtkm/cont/ErrorBadType.h>
#include <vtkm/cont/Logging.h>
#include <vtkm/cont/TryExecute.h>
#include <vtkm/cont/VirtualObjectHandle.h>
#include <vtkm/cont/internal/DynamicTransform.h>
#include <vtkm/VecTraits.h>
#include <vtkm/VirtualObjectBase.h>
#include <memory>
#include <type_traits>
......@@ -40,473 +39,57 @@ namespace vtkm
namespace cont
{
namespace internal
{
//=============================================================================
class VTKM_ALWAYS_EXPORT CoordinatesPortalBase : public VirtualObjectBase
{
public:
VTKM_EXEC_CONT virtual vtkm::Vec<vtkm::FloatDefault, 3> Get(vtkm::Id i) const = 0;
VTKM_EXEC_CONT virtual void Set(vtkm::Id i,
const vtkm::Vec<vtkm::FloatDefault, 3>& val) const = 0;
};
template <typename PortalType, typename ValueType>
class VTKM_ALWAYS_EXPORT CoordinatesPortalImpl : public CoordinatesPortalBase
{
public:
VTKM_CONT CoordinatesPortalImpl() = default;
VTKM_CONT explicit CoordinatesPortalImpl(const PortalType& portal)
: Portal(portal)
{
}
VTKM_CONT void SetPortal(const PortalType& portal) { this->Portal = portal; }
VTKM_EXEC_CONT vtkm::Vec<vtkm::FloatDefault, 3> Get(vtkm::Id i) const override
{
auto val = this->Portal.Get(i);
return { static_cast<vtkm::FloatDefault>(val[0]),
static_cast<vtkm::FloatDefault>(val[1]),
static_cast<vtkm::FloatDefault>(val[2]) };
}
VTKM_EXEC_CONT void Set(vtkm::Id i, const vtkm::Vec<vtkm::FloatDefault, 3>& val) const override
{
using VecType = typename PortalType::ValueType;
using ComponentType = typename vtkm::VecTraits<VecType>::ComponentType;
this->Portal.Set(i,
{ static_cast<ComponentType>(val[0]),
static_cast<ComponentType>(val[1]),
static_cast<ComponentType>(val[2]) });
}
private:
PortalType Portal;
};
template <typename PortalType>
class VTKM_ALWAYS_EXPORT CoordinatesPortalImpl<PortalType, void*> : public CoordinatesPortalBase
{
public:
VTKM_CONT CoordinatesPortalImpl() = default;
VTKM_CONT explicit CoordinatesPortalImpl(const PortalType&) {}
VTKM_CONT void SetPortal(const PortalType&) {}
VTKM_EXEC_CONT vtkm::Vec<vtkm::FloatDefault, 3> Get(vtkm::Id) const override { return {}; }
VTKM_EXEC_CONT void Set(vtkm::Id, const vtkm::Vec<vtkm::FloatDefault, 3>&) const override {}
};
template <typename PortalType>
class VTKM_ALWAYS_EXPORT CoordinatesPortal
: public CoordinatesPortalImpl<PortalType, typename PortalType::ValueType>
{
public:
VTKM_CONT CoordinatesPortal() = default;
VTKM_CONT explicit CoordinatesPortal(const PortalType& portal)
: CoordinatesPortalImpl<PortalType, typename PortalType::ValueType>(portal)
{
}
};
template <typename PortalType>
class VTKM_ALWAYS_EXPORT CoordinatesPortalConst : public CoordinatesPortalBase
{
public:
VTKM_CONT CoordinatesPortalConst() = default;
VTKM_CONT explicit CoordinatesPortalConst(const PortalType& portal)
: Portal(portal)
{
}
VTKM_CONT void SetPortal(const PortalType& portal) { this->Portal = portal; }
VTKM_EXEC_CONT vtkm::Vec<vtkm::FloatDefault, 3> Get(vtkm::Id i) const override
{
auto val = this->Portal.Get(i);
return { static_cast<vtkm::FloatDefault>(val[0]),
static_cast<vtkm::FloatDefault>(val[1]),
static_cast<vtkm::FloatDefault>(val[2]) };
}
VTKM_EXEC_CONT void Set(vtkm::Id, const vtkm::Vec<vtkm::FloatDefault, 3>&) const override {}
private:
PortalType Portal;
};
class VTKM_ALWAYS_EXPORT ArrayPortalVirtualCoordinates
/// ArrayHandleVirtualCoordinates is a specialization of ArrayHandle.
class VTKM_CONT_EXPORT ArrayHandleVirtualCoordinates final
: public vtkm::cont::ArrayHandleVirtual<vtkm::Vec<vtkm::FloatDefault, 3>>
{
public:
using ValueType = vtkm::Vec<vtkm::FloatDefault, 3>;
using StorageTag = vtkm::cont::StorageTagVirtual;
VTKM_EXEC_CONT ArrayPortalVirtualCoordinates()
: NumberOfValues(0)
, VirtualPortal(nullptr)
{
}
VTKM_EXEC_CONT ArrayPortalVirtualCoordinates(vtkm::Id numberOfValues,
const CoordinatesPortalBase* virtualPortal)
: NumberOfValues(numberOfValues)
, VirtualPortal(virtualPortal)
{
}
VTKM_EXEC_CONT vtkm::Id GetNumberOfValues() const { return this->NumberOfValues; }
using NonDefaultCoord = typename std::conditional<std::is_same<vtkm::FloatDefault, float>::value,
vtkm::Vec<double, 3>,
vtkm::Vec<float, 3>>::type;
VTKM_EXEC_CONT ValueType Get(vtkm::Id i) const { return this->VirtualPortal->Get(i); }
VTKM_EXEC_CONT void Set(vtkm::Id i, const ValueType& val) const
ArrayHandleVirtualCoordinates()
: vtkm::cont::ArrayHandleVirtual<ValueType>()
{
this->VirtualPortal->Set(i, val);
}
private:
vtkm::Id NumberOfValues;
const CoordinatesPortalBase* VirtualPortal;
};
//=============================================================================
class VTKM_ALWAYS_EXPORT CoordinatesArrayHandleBase
{
public:
using Portal = ArrayPortalVirtualCoordinates;
using PortalConst = ArrayPortalVirtualCoordinates;
virtual ~CoordinatesArrayHandleBase() = default;
VTKM_CONT virtual vtkm::Id GetNumberOfValues() const = 0;
VTKM_CONT virtual Portal GetPortalControl() = 0;
VTKM_CONT virtual PortalConst GetPortalConstControl() = 0;
VTKM_CONT virtual void Allocate(vtkm::Id numberOfValues) = 0;
VTKM_CONT virtual void Shrink(vtkm::Id numberOfValues) = 0;
VTKM_CONT virtual void ReleaseResources() = 0;
VTKM_CONT virtual void ReleaseResourcesExecution() = 0;
VTKM_CONT virtual PortalConst PrepareForInput(vtkm::cont::DeviceAdapterId deviceId) = 0;
VTKM_CONT virtual Portal PrepareForOutput(vtkm::Id numberOfValues,
vtkm::cont::DeviceAdapterId deviceId) = 0;
VTKM_CONT virtual Portal PrepareForInPlace(vtkm::cont::DeviceAdapterId deviceId) = 0;
};
template <typename ArrayHandleType>
class VTKM_ALWAYS_EXPORT CoordinatesArrayHandleArrayWrapper : public CoordinatesArrayHandleBase
{
public:
VTKM_CONT explicit CoordinatesArrayHandleArrayWrapper(const ArrayHandleType& array)
: Array(array)
{
}
VTKM_CONT const ArrayHandleType& GetArray() const { return this->Array; }
protected:
ArrayHandleType Array;
};
template <typename ArrayHandleType, typename DeviceList>
class VTKM_ALWAYS_EXPORT CoordinatesArrayHandle
: public CoordinatesArrayHandleArrayWrapper<ArrayHandleType>
{
public:
static_assert(std::is_same<DeviceList, vtkm::cont::DeviceAdapterListTagCommon>::value, "error");
using Portal = CoordinatesArrayHandleBase::Portal;
using PortalConst = CoordinatesArrayHandleBase::PortalConst;
VTKM_CONT explicit CoordinatesArrayHandle(const ArrayHandleType& array)
: CoordinatesArrayHandleArrayWrapper<ArrayHandleType>(array)
{
}
VTKM_CONT vtkm::Id GetNumberOfValues() const override { return this->Array.GetNumberOfValues(); }
VTKM_CONT Portal GetPortalControl() override
{
this->ControlPortal.SetPortal(this->Array.GetPortalControl());
return Portal(this->GetNumberOfValues(), &this->ControlPortal);
}
VTKM_CONT PortalConst GetPortalConstControl() override
{
this->ControlConstPortal.SetPortal(this->Array.GetPortalConstControl());
return PortalConst(this->GetNumberOfValues(), &this->ControlConstPortal);
}
VTKM_CONT void Allocate(vtkm::Id numberOfValues) override
{
this->Array.Allocate(numberOfValues);
}
VTKM_CONT void Shrink(vtkm::Id numberOfValues) override { this->Array.Shrink(numberOfValues); }
VTKM_CONT void ReleaseResources() override { this->Array.ReleaseResources(); }
VTKM_CONT void ReleaseResourcesExecution() override { this->Array.ReleaseResourcesExecution(); }
VTKM_CONT PortalConst PrepareForInput(vtkm::cont::DeviceAdapterId deviceId) override
{
PortalConst portal;
bool success = vtkm::cont::TryExecuteOnDevice(
deviceId, PrepareForInputFunctor(), DeviceList(), this, portal);
if (!success)
{
throwFailedRuntimeDeviceTransfer("ArrayHandleVirtualCoordinates", deviceId);
}
return portal;
}
VTKM_CONT Portal PrepareForOutput(vtkm::Id numberOfValues,
vtkm::cont::DeviceAdapterId deviceId) override
{
Portal portal;
bool success = vtkm::cont::TryExecuteOnDevice(
deviceId, PrepareForOutputFunctor(), DeviceList(), this, numberOfValues, portal);
if (!success)
{
throwFailedRuntimeDeviceTransfer("ArrayHandleVirtualCoordinates", deviceId);
}
return portal;
}
VTKM_CONT Portal PrepareForInPlace(vtkm::cont::DeviceAdapterId deviceId) override
{
Portal portal;
bool success = vtkm::cont::TryExecuteOnDevice(
deviceId, PrepareForInPlaceFunctor(), DeviceList(), this, portal);
if (!success)
{
throwFailedRuntimeDeviceTransfer("ArrayHandleVirtualCoordinates", deviceId);
}
return portal;
}
private:
struct PrepareForInputFunctor
{
template <typename DeviceAdapter>
VTKM_CONT bool operator()(DeviceAdapter device,
CoordinatesArrayHandle* instance,
PortalConst& ret) const
{
auto portal = instance->Array.PrepareForInput(device);
instance->DevicePortalHandle.Reset(new CoordinatesPortalConst<decltype(portal)>(portal),
true,
vtkm::ListTagBase<DeviceAdapter>());
ret = PortalConst(portal.GetNumberOfValues(),
instance->DevicePortalHandle.PrepareForExecution(device));
return true;
}
};
struct PrepareForOutputFunctor
{
template <typename DeviceAdapter>
VTKM_CONT bool operator()(DeviceAdapter device,
CoordinatesArrayHandle* instance,
vtkm::Id numberOfValues,
Portal& ret) const
{
auto portal = instance->Array.PrepareForOutput(numberOfValues, device);
instance->DevicePortalHandle.Reset(
new CoordinatesPortal<decltype(portal)>(portal), true, vtkm::ListTagBase<DeviceAdapter>());
ret = Portal(numberOfValues, instance->DevicePortalHandle.PrepareForExecution(device));
return true;
}
};
struct PrepareForInPlaceFunctor
{
template <typename DeviceAdapter>
VTKM_CONT bool operator()(DeviceAdapter device,
CoordinatesArrayHandle* instance,
Portal& ret) const
{
auto portal = instance->Array.PrepareForInPlace(device);
instance->DevicePortalHandle.Reset(
new CoordinatesPortal<decltype(portal)>(portal), true, vtkm::ListTagBase<DeviceAdapter>());
ret = Portal(instance->Array.GetNumberOfValues(),
instance->DevicePortalHandle.PrepareForExecution(device));
return true;
}
};
CoordinatesPortal<typename ArrayHandleType::PortalControl> ControlPortal;
CoordinatesPortalConst<typename ArrayHandleType::PortalConstControl> ControlConstPortal;
vtkm::cont::VirtualObjectHandle<CoordinatesPortalBase> DevicePortalHandle;
};
//=============================================================================
struct VTKM_ALWAYS_EXPORT StorageTagVirtualCoordinates
{
};
template <>
class VTKM_ALWAYS_EXPORT Storage<vtkm::Vec<vtkm::FloatDefault, 3>, StorageTagVirtualCoordinates>
{
public:
using ValueType = vtkm::Vec<vtkm::FloatDefault, 3>;
using PortalType = CoordinatesArrayHandleBase::Portal;
using PortalConstType = CoordinatesArrayHandleBase::PortalConst;
VTKM_CONT Storage() = default;
template <typename ArrayHandleType, typename DeviceList>
VTKM_CONT explicit Storage(const ArrayHandleType& array, DeviceList)
: Array(new CoordinatesArrayHandle<ArrayHandleType, DeviceList>(array))
{
}
VTKM_CONT PortalType GetPortal() { return this->Array->GetPortalControl(); }
VTKM_CONT PortalConstType GetPortalConst() const { return this->Array->GetPortalConstControl(); }
VTKM_CONT vtkm::Id GetNumberOfValues() const { return this->Array->GetNumberOfValues(); }
VTKM_CONT void Allocate(vtkm::Id numberOfValues) { this->Array->Allocate(numberOfValues); }
VTKM_CONT void Shrink(vtkm::Id numberOfValues) { this->Array->Shrink(numberOfValues); }
VTKM_CONT void ReleaseResources() { this->Array->ReleaseResources(); }
VTKM_CONT CoordinatesArrayHandleBase* GetVirtualArray() const { return this->Array.get(); }
private:
std::shared_ptr<CoordinatesArrayHandleBase> Array;
};
//=============================================================================
template <typename DeviceAdapter>
class VTKM_ALWAYS_EXPORT
ArrayTransfer<vtkm::Vec<vtkm::FloatDefault, 3>, StorageTagVirtualCoordinates, DeviceAdapter>
{
public:
using ValueType = vtkm::Vec<vtkm::FloatDefault, 3>;
using StorageType = vtkm::cont::internal::Storage<ValueType, StorageTagVirtualCoordinates>;
using PortalControl = typename StorageType::PortalType;
using PortalConstControl = typename StorageType::PortalConstType;
using PortalExecution = CoordinatesArrayHandleBase::Portal;
using PortalConstExecution = CoordinatesArrayHandleBase::PortalConst;
VTKM_CONT