//============================================================================ // 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 2014 National Technology & Engineering Solutions of Sandia, LLC (NTESS). // Copyright 2014 UT-Battelle, LLC. // Copyright 2014 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. //============================================================================ #ifndef vtk_m_cont_ArrayHandleVirtualCoordinates_h #define vtk_m_cont_ArrayHandleVirtualCoordinates_h #include #include #include #include #include #include #include #include #include #include #include #include namespace vtkm { namespace cont { namespace internal { //============================================================================= class VTKM_ALWAYS_EXPORT CoordinatesPortalBase : public VirtualObjectBase { public: VTKM_EXEC_CONT virtual vtkm::Vec Get(vtkm::Id i) const = 0; VTKM_EXEC_CONT virtual void Set(vtkm::Id i, const vtkm::Vec& val) const = 0; }; template 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 Get(vtkm::Id i) const override { auto val = this->Portal.Get(i); return { static_cast(val[0]), static_cast(val[1]), static_cast(val[2]) }; } VTKM_EXEC_CONT void Set(vtkm::Id i, const vtkm::Vec& val) const override { using VecType = typename PortalType::ValueType; using ComponentType = typename vtkm::VecTraits::ComponentType; this->Portal.Set(i, { static_cast(val[0]), static_cast(val[1]), static_cast(val[2]) }); } private: PortalType Portal; }; template class VTKM_ALWAYS_EXPORT CoordinatesPortalImpl : public CoordinatesPortalBase { public: VTKM_CONT CoordinatesPortalImpl() = default; VTKM_CONT explicit CoordinatesPortalImpl(const PortalType&) {} VTKM_CONT void SetPortal(const PortalType&) {} VTKM_EXEC_CONT vtkm::Vec Get(vtkm::Id) const override { return {}; } VTKM_EXEC_CONT void Set(vtkm::Id, const vtkm::Vec&) const override {} }; template class VTKM_ALWAYS_EXPORT CoordinatesPortal : public CoordinatesPortalImpl { public: VTKM_CONT CoordinatesPortal() = default; VTKM_CONT explicit CoordinatesPortal(const PortalType& portal) : CoordinatesPortalImpl(portal) { } }; template 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 Get(vtkm::Id i) const override { auto val = this->Portal.Get(i); return { static_cast(val[0]), static_cast(val[1]), static_cast(val[2]) }; } VTKM_EXEC_CONT void Set(vtkm::Id, const vtkm::Vec&) const override {} private: PortalType Portal; }; class VTKM_ALWAYS_EXPORT ArrayPortalVirtualCoordinates { public: using ValueType = vtkm::Vec; 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; } 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 { 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 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 class VTKM_ALWAYS_EXPORT CoordinatesArrayHandle : public CoordinatesArrayHandleArrayWrapper { public: static_assert(std::is_same::value, "error"); using Portal = CoordinatesArrayHandleBase::Portal; using PortalConst = CoordinatesArrayHandleBase::PortalConst; VTKM_CONT explicit CoordinatesArrayHandle(const ArrayHandleType& array) : CoordinatesArrayHandleArrayWrapper(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 VTKM_CONT bool operator()(DeviceAdapter device, CoordinatesArrayHandle* instance, PortalConst& ret) const { auto portal = instance->Array.PrepareForInput(device); instance->DevicePortalHandle.Reset(new CoordinatesPortalConst(portal), true, vtkm::ListTagBase()); ret = PortalConst(portal.GetNumberOfValues(), instance->DevicePortalHandle.PrepareForExecution(device)); return true; } }; struct PrepareForOutputFunctor { template 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(portal), true, vtkm::ListTagBase()); ret = Portal(numberOfValues, instance->DevicePortalHandle.PrepareForExecution(device)); return true; } }; struct PrepareForInPlaceFunctor { template VTKM_CONT bool operator()(DeviceAdapter device, CoordinatesArrayHandle* instance, Portal& ret) const { auto portal = instance->Array.PrepareForInPlace(device); instance->DevicePortalHandle.Reset( new CoordinatesPortal(portal), true, vtkm::ListTagBase()); ret = Portal(instance->Array.GetNumberOfValues(), instance->DevicePortalHandle.PrepareForExecution(device)); return true; } }; CoordinatesPortal ControlPortal; CoordinatesPortalConst ControlConstPortal; vtkm::cont::VirtualObjectHandle DevicePortalHandle; }; //============================================================================= struct VTKM_ALWAYS_EXPORT StorageTagVirtualCoordinates { }; template <> class VTKM_ALWAYS_EXPORT Storage, StorageTagVirtualCoordinates> { public: using ValueType = vtkm::Vec; using PortalType = CoordinatesArrayHandleBase::Portal; using PortalConstType = CoordinatesArrayHandleBase::PortalConst; VTKM_CONT Storage() = default; template VTKM_CONT explicit Storage(const ArrayHandleType& array, DeviceList) : Array(new CoordinatesArrayHandle(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 Array; }; //============================================================================= template class VTKM_ALWAYS_EXPORT ArrayTransfer, StorageTagVirtualCoordinates, DeviceAdapter> { public: using ValueType = vtkm::Vec; using StorageType = vtkm::cont::internal::Storage; using PortalControl = typename StorageType::PortalType; using PortalConstControl = typename StorageType::PortalConstType; using PortalExecution = CoordinatesArrayHandleBase::Portal; using PortalConstExecution = CoordinatesArrayHandleBase::PortalConst; VTKM_CONT ArrayTransfer(StorageType* storage) : Array(storage->GetVirtualArray()) { } VTKM_CONT vtkm::Id GetNumberOfValues() const { return this->Array->GetNumberOfValues(); } VTKM_CONT PortalConstExecution PrepareForInput(bool) { return this->Array->PrepareForInput(DeviceAdapter()); } VTKM_CONT PortalExecution PrepareForInPlace(bool) { return this->Array->PrepareForInPlace(DeviceAdapter()); } VTKM_CONT PortalExecution PrepareForOutput(vtkm::Id numberOfValues) { return this->Array->PrepareForOutput(numberOfValues, DeviceAdapter()); } VTKM_CONT void RetrieveOutputData(StorageType*) const { // Implementation of this method should be unnecessary. } VTKM_CONT void Shrink(vtkm::Id numberOfValues) { this->Array->Shrink(numberOfValues); } // ArrayTransfer should only be capable of releasing resources in the execution // environment VTKM_CONT void ReleaseResources() { this->Array->ReleaseResourcesExecution(); } private: CoordinatesArrayHandleBase* Array; }; } // internal //============================================================================= class VTKM_ALWAYS_EXPORT ArrayHandleVirtualCoordinates : public ArrayHandle, internal::StorageTagVirtualCoordinates> { public: VTKM_ARRAY_HANDLE_SUBCLASS_NT( ArrayHandleVirtualCoordinates, (ArrayHandle, internal::StorageTagVirtualCoordinates>)); template explicit ArrayHandleVirtualCoordinates( const vtkm::cont::ArrayHandle, StorageTag>& array, DeviceList devices = DeviceList()) : Superclass(typename Superclass::StorageType(array, devices)) { } template explicit ArrayHandleVirtualCoordinates( const vtkm::cont::ArrayHandle, StorageTag>& array, DeviceList devices = DeviceList()) : Superclass(typename Superclass::StorageType(array, devices)) { } template bool IsType() const { return this->GetArrayHandleWrapper() != nullptr; } template bool IsSameType(const ArrayHandleType&) const { return this->GetArrayHandleWrapper() != nullptr; } template const ArrayHandleType Cast() const { auto wrapper = this->GetArrayHandleWrapper(); if (!wrapper) { VTKM_LOG_CAST_FAIL(*this, ArrayHandleType); throw vtkm::cont::ErrorBadType("dynamic cast failed"); } VTKM_LOG_CAST_SUCC(*this, wrapper->GetArray()); return ArrayHandleType(wrapper->GetArray()); } private: template struct WrapperType { VTKM_IS_ARRAY_HANDLE(ArrayHandleType); using ValueType = typename ArrayHandleType::ValueType; using StorageTag = typename ArrayHandleType::StorageTag; using BaseArrayHandleType = vtkm::cont::ArrayHandle; using Type = internal::CoordinatesArrayHandleArrayWrapper; }; template VTKM_CONT const typename WrapperType::Type* GetArrayHandleWrapper() const { auto va = this->GetStorage().GetVirtualArray(); return dynamic_cast::Type*>(va); } }; template void CastAndCall(const vtkm::cont::ArrayHandleVirtualCoordinates& coords, Functor&& f, Args&&... args) { if (coords.IsType()) { f(coords.Cast(), std::forward(args)...); } else { f(coords, std::forward(args)...); } } template void CastAndCall(const typename vtkm::cont::ArrayHandleVirtualCoordinates::Superclass& coords, Functor&& f, Args&&... args) { CastAndCall(static_cast(coords), std::forward(f), std::forward(args)...); } } } // vtkm::cont #ifdef VTKM_CUDA // Cuda seems to have a bug where it expects the template class VirtualObjectTransfer // to be instantiated in a consistent order among all the translation units of an // executable. Failing to do so results in random crashes and incorrect results. // We workaroud this issue by explicitly instantiating VirtualObjectTransfer for // all the portal types here. #include #include #include #include #include #include #include namespace vtkm { namespace cont { namespace internal { template struct CudaPortalTypes { using PortalConst = typename ArrayHandleType::template ExecutionTypes< vtkm::cont::DeviceAdapterTagCuda>::PortalConst; using Portal = typename ArrayHandleType::template ExecutionTypes::Portal; }; using CudaPortalsBasicF32 = CudaPortalTypes>>; using CudaPortalsBasicF64 = CudaPortalTypes>>; using CudaPortalsUniformPointCoordinates = CudaPortalTypes; using CudaPortalsRectilinearCoords = CudaPortalTypes< vtkm::cont::ArrayHandleCartesianProduct, vtkm::cont::ArrayHandle, vtkm::cont::ArrayHandle>>; using CudaPortalsCompositeCoords = CudaPortalTypes< vtkm::cont::ArrayHandleCompositeVector, vtkm::cont::ArrayHandle, vtkm::cont::ArrayHandle>>; } } } // vtkm::cont::internal VTKM_EXPLICITLY_INSTANTIATE_TRANSFER(vtkm::cont::internal::CoordinatesPortalConst< vtkm::cont::internal::CudaPortalsBasicF32::PortalConst>); VTKM_EXPLICITLY_INSTANTIATE_TRANSFER( vtkm::cont::internal::CoordinatesPortal); VTKM_EXPLICITLY_INSTANTIATE_TRANSFER(vtkm::cont::internal::CoordinatesPortalConst< vtkm::cont::internal::CudaPortalsBasicF64::PortalConst>); VTKM_EXPLICITLY_INSTANTIATE_TRANSFER( vtkm::cont::internal::CoordinatesPortal); VTKM_EXPLICITLY_INSTANTIATE_TRANSFER( vtkm::cont::internal::CoordinatesPortalConst< vtkm::cont::internal::CudaPortalsUniformPointCoordinates::PortalConst>); VTKM_EXPLICITLY_INSTANTIATE_TRANSFER( vtkm::cont::internal::CoordinatesPortal< vtkm::cont::internal::CudaPortalsUniformPointCoordinates::Portal>); VTKM_EXPLICITLY_INSTANTIATE_TRANSFER( vtkm::cont::internal::CoordinatesPortalConst< vtkm::cont::internal::CudaPortalsRectilinearCoords::PortalConst>); VTKM_EXPLICITLY_INSTANTIATE_TRANSFER(vtkm::cont::internal::CoordinatesPortal< vtkm::cont::internal::CudaPortalsRectilinearCoords::Portal>); VTKM_EXPLICITLY_INSTANTIATE_TRANSFER( vtkm::cont::internal::CoordinatesPortalConst< vtkm::cont::internal::CudaPortalsCompositeCoords::PortalConst>); VTKM_EXPLICITLY_INSTANTIATE_TRANSFER(vtkm::cont::internal::CoordinatesPortal< vtkm::cont::internal::CudaPortalsCompositeCoords::Portal>); #endif // VTKM_CUDA //============================================================================= // Specializations of serialization related classes namespace vtkm { namespace cont { template <> struct TypeString { static VTKM_CONT const std::string Get() { return "AH_VirtualCoordinates"; } }; template <> struct TypeString, vtkm::cont::internal::StorageTagVirtualCoordinates>> : TypeString { }; } } // vtkm::cont namespace diy { template <> struct Serialization { private: using Type = vtkm::cont::ArrayHandleVirtualCoordinates; using BaseType = vtkm::cont::ArrayHandle; using BasicCoordsType = vtkm::cont::ArrayHandle>; using RectilinearCoordsArrayType = vtkm::cont::ArrayHandleCartesianProduct, vtkm::cont::ArrayHandle, vtkm::cont::ArrayHandle>; public: static VTKM_CONT void save(BinaryBuffer& bb, const BaseType& obj) { const auto& virtArray = static_cast(obj); if (virtArray.IsType()) { auto array = virtArray.Cast(); diy::save(bb, vtkm::cont::TypeString::Get()); diy::save(bb, array); } else if (virtArray.IsType()) { auto array = virtArray.Cast(); diy::save(bb, vtkm::cont::TypeString::Get()); diy::save(bb, array); } else { diy::save(bb, vtkm::cont::TypeString::Get()); vtkm::cont::internal::ArrayHandleDefaultSerialization(bb, virtArray); } } static VTKM_CONT void load(BinaryBuffer& bb, BaseType& obj) { std::string typeString; diy::load(bb, typeString); if (typeString == vtkm::cont::TypeString::Get()) { vtkm::cont::ArrayHandleUniformPointCoordinates array; diy::load(bb, array); obj = vtkm::cont::ArrayHandleVirtualCoordinates(array); } else if (typeString == vtkm::cont::TypeString::Get()) { RectilinearCoordsArrayType array; diy::load(bb, array); obj = vtkm::cont::ArrayHandleVirtualCoordinates(array); } else if (typeString == vtkm::cont::TypeString::Get()) { BasicCoordsType array; diy::load(bb, array); obj = vtkm::cont::ArrayHandleVirtualCoordinates(array); } else { throw vtkm::cont::ErrorBadType( "Error deserializing ArrayHandleVirtualCoordinates. TypeString: " + typeString); } } }; template <> struct Serialization, vtkm::cont::internal::StorageTagVirtualCoordinates>> : Serialization { }; } // diy #endif // vtk_m_cont_ArrayHandleVirtualCoordinates_h