//============================================================================ // 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. //============================================================================ #ifndef vtk_m_cont_StorageVirtual_hxx #define vtk_m_cont_StorageVirtual_hxx #include #include #include #include #include #include #include #ifdef VTKM_NO_DEPRECATED_VIRTUAL #error "This header should not be included when VTKM_NO_DEPRECATED_VIRTUAL is set." #endif // This is a deprecated class. Don't warn about deprecation while implementing // deprecated functionality. VTKM_DEPRECATED_SUPPRESS_BEGIN namespace vtkm { namespace cont { namespace detail { template struct TransferToDevice { template inline bool operator()(DeviceAdapterTag devId, Payload&& payload, Args&&... args) const { using TransferType = cont::internal::VirtualObjectTransfer; using shared_memory_transfer = std::is_base_of, TransferType>; return this->Transfer( devId, shared_memory_transfer{}, std::forward(payload), std::forward(args)...); } template inline bool Transfer(DeviceAdapterTag devId, std::true_type, Payload&& payload, Args&&... args) const { //shared memory transfer so we just need auto smp_ptr = new DerivedPortal(std::forward(args)...); auto host = std::unique_ptr(smp_ptr); payload.updateDevice(devId, std::move(host), smp_ptr, nullptr); return true; } template inline bool Transfer(DeviceAdapterTag devId, std::false_type, Payload&& payload, Args&&... args) const { //separate memory transfer //construct all new transfer payload using TransferType = cont::internal::VirtualObjectTransfer; auto host = std::unique_ptr(new DerivedPortal(std::forward(args)...)); auto transfer = std::make_shared(host.get()); auto device = transfer->PrepareForExecution(true); payload.updateDevice(devId, std::move(host), device, std::static_pointer_cast(transfer)); return true; } }; } // namespace detail template inline void make_transferToDevice(vtkm::cont::DeviceAdapterId devId, Args&&... args) { vtkm::cont::TryExecuteOnDevice( devId, detail::TransferToDevice{}, std::forward(args)...); } template inline void make_hostPortal(Payload&& payload, Args&&... args) { auto host = std::unique_ptr(new DerivedPortal(std::forward(args)...)); payload.updateHost(std::move(host)); } namespace internal { namespace detail { VTKM_CONT template StorageVirtualImpl::StorageVirtualImpl(const vtkm::cont::ArrayHandle& ah) : vtkm::cont::internal::detail::StorageVirtual() , Handle(ah) { } VTKM_CONT template StorageVirtualImpl::StorageVirtualImpl(vtkm::cont::ArrayHandle&& ah) noexcept : vtkm::cont::internal::detail::StorageVirtual() , Handle(std::move(ah)) { } /// release execution side resources template void StorageVirtualImpl::ReleaseResourcesExecution() { this->DropExecutionPortal(); this->Handle.ReleaseResourcesExecution(); } /// release control side resources template void StorageVirtualImpl::ReleaseResources() { this->DropAllPortals(); this->Handle.ReleaseResources(); } template void StorageVirtualImpl::Allocate(vtkm::Id numberOfValues) { this->DropAllPortals(); this->Handle.Allocate(numberOfValues); } template void StorageVirtualImpl::Shrink(vtkm::Id numberOfValues) { this->DropAllPortals(); this->Handle.Allocate(numberOfValues, vtkm::CopyFlag::On); } struct PortalWrapperToDevice { template inline bool operator()(DeviceAdapterTag device, Handle&& handle, vtkm::cont::internal::TransferInfoArray& payload) const { vtkm::cont::Token token; auto portal = handle.PrepareForInput(device, token); using DerivedPortal = vtkm::ArrayPortalWrapper; vtkm::cont::detail::TransferToDevice transfer; return transfer(device, payload, portal); } template inline bool operator()(DeviceAdapterTag device, Handle&& handle, vtkm::Id numberOfValues, vtkm::cont::internal::TransferInfoArray& payload, vtkm::cont::internal::detail::StorageVirtual::OutputMode mode) const { using ACCESS_MODE = vtkm::cont::internal::detail::StorageVirtual::OutputMode; if (mode == ACCESS_MODE::WRITE) { vtkm::cont::Token token; auto portal = handle.PrepareForOutput(numberOfValues, device, token); using DerivedPortal = vtkm::ArrayPortalWrapper; vtkm::cont::detail::TransferToDevice transfer; return transfer(device, payload, portal); } else { vtkm::cont::Token token; auto portal = handle.PrepareForInPlace(device, token); using DerivedPortal = vtkm::ArrayPortalWrapper; vtkm::cont::detail::TransferToDevice transfer; return transfer(device, payload, portal); } } }; template void StorageVirtualImpl::ControlPortalForInput( vtkm::cont::internal::TransferInfoArray& payload) const { auto portal = this->Handle.ReadPortal(); using DerivedPortal = vtkm::ArrayPortalWrapper; vtkm::cont::make_hostPortal(payload, portal); } template inline void make_writableHostPortal(std::true_type, vtkm::cont::internal::TransferInfoArray& payload, HandleType& handle) { auto portal = handle.WritePortal(); using DerivedPortal = vtkm::ArrayPortalWrapper; vtkm::cont::make_hostPortal(payload, portal); } template inline void make_writableHostPortal(std::false_type, vtkm::cont::internal::TransferInfoArray& payload, HandleType&) { payload.updateHost(nullptr); throw vtkm::cont::ErrorBadValue( "ArrayHandleAny was bound to an ArrayHandle that doesn't support output."); } template void StorageVirtualImpl::ControlPortalForOutput( vtkm::cont::internal::TransferInfoArray& payload) { using HT = vtkm::cont::ArrayHandle; constexpr auto isWritable = typename vtkm::cont::internal::IsWritableArrayHandle::type{}; detail::make_writableHostPortal(isWritable, payload, this->Handle); } template void StorageVirtualImpl::TransferPortalForInput( vtkm::cont::internal::TransferInfoArray& payload, vtkm::cont::DeviceAdapterId devId) const { vtkm::cont::TryExecuteOnDevice(devId, detail::PortalWrapperToDevice(), this->Handle, payload); } template void StorageVirtualImpl::TransferPortalForOutput( vtkm::cont::internal::TransferInfoArray& payload, vtkm::cont::internal::detail::StorageVirtual::OutputMode mode, vtkm::Id numberOfValues, vtkm::cont::DeviceAdapterId devId) { vtkm::cont::TryExecuteOnDevice( devId, detail::PortalWrapperToDevice(), this->Handle, numberOfValues, payload, mode); } } // namespace detail VTKM_DEPRECATED_SUPPRESS_BEGIN template void Storage::Allocate(vtkm::Id numberOfValues) { if (this->VirtualStorage) { this->VirtualStorage->Allocate(numberOfValues); } else if (numberOfValues != 0) { throw vtkm::cont::ErrorBadAllocation("Attempted to allocate memory in a virtual array that " "does not have an underlying concrete array."); } else { // Allocating a non-existing array to 0 is OK. } } template void Storage::Shrink(vtkm::Id numberOfValues) { if (this->VirtualStorage) { this->VirtualStorage->Shrink(numberOfValues); } else if (numberOfValues != 0) { throw vtkm::cont::ErrorBadAllocation( "Attempted to shrink a virtual array that does not have an underlying concrete array."); } else { // Shrinking a non-existing array to 0 is OK. } } template void Storage::ReleaseResources() { if (this->VirtualStorage) { this->VirtualStorage->ReleaseResources(); } else { // No concrete array, nothing allocated, nothing to do. } } template Storage Storage::NewInstance() const { if (this->GetStorageVirtual()) { return Storage(this->GetStorageVirtual()->NewInstance()); } else { return Storage(); } } namespace detail { template class VTKM_ALWAYS_EXPORT ArrayTransferVirtual { using StorageType = vtkm::cont::internal::Storage; vtkm::cont::internal::detail::StorageVirtual* Storage; public: using ValueType = T; using PortalControl = typename StorageType::PortalType; using PortalConstControl = typename StorageType::PortalConstType; using PortalExecution = vtkm::ArrayPortalRef; using PortalConstExecution = vtkm::ArrayPortalRef; VTKM_CONT ArrayTransferVirtual(StorageType* storage) : Storage(storage->GetStorageVirtual()) { } VTKM_CONT vtkm::Id GetNumberOfValues() const { return this->Storage->GetNumberOfValues(); } VTKM_CONT PortalConstExecution PrepareForInput(vtkm::cont::DeviceAdapterId device) { return vtkm::make_ArrayPortalRef(static_cast*>( this->Storage->PrepareForInput(device)), this->GetNumberOfValues()); } VTKM_CONT PortalExecution PrepareForOutput(vtkm::Id numberOfValues, vtkm::cont::DeviceAdapterId device) { return make_ArrayPortalRef(static_cast*>( this->Storage->PrepareForOutput(numberOfValues, device)), numberOfValues); } VTKM_CONT PortalExecution PrepareForInPlace(vtkm::cont::DeviceAdapterId device) { return vtkm::make_ArrayPortalRef(static_cast*>( this->Storage->PrepareForInPlace(device)), this->GetNumberOfValues()); } VTKM_CONT void RetrieveOutputData(StorageType* vtkmNotUsed(storage)) const { // Implementation of this method should be unnecessary. The internal array handles should // automatically retrieve the output data as necessary. } VTKM_CONT void Shrink(vtkm::Id numberOfValues) { this->Storage->Shrink(numberOfValues); } VTKM_CONT void ReleaseResources() { this->Storage->ReleaseResourcesExecution(); } }; #ifndef vtk_m_cont_StorageVirtual_cxx #define VTK_M_ARRAY_TRANSFER_VIRTUAL_EXPORT(T) \ extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayTransferVirtual; \ extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayTransferVirtual>; \ extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayTransferVirtual>; \ extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayTransferVirtual> VTK_M_ARRAY_TRANSFER_VIRTUAL_EXPORT(char); VTK_M_ARRAY_TRANSFER_VIRTUAL_EXPORT(vtkm::Int8); VTK_M_ARRAY_TRANSFER_VIRTUAL_EXPORT(vtkm::UInt8); VTK_M_ARRAY_TRANSFER_VIRTUAL_EXPORT(vtkm::Int16); VTK_M_ARRAY_TRANSFER_VIRTUAL_EXPORT(vtkm::UInt16); VTK_M_ARRAY_TRANSFER_VIRTUAL_EXPORT(vtkm::Int32); VTK_M_ARRAY_TRANSFER_VIRTUAL_EXPORT(vtkm::UInt32); VTK_M_ARRAY_TRANSFER_VIRTUAL_EXPORT(vtkm::Int64); VTK_M_ARRAY_TRANSFER_VIRTUAL_EXPORT(vtkm::UInt64); VTK_M_ARRAY_TRANSFER_VIRTUAL_EXPORT(vtkm::Float32); VTK_M_ARRAY_TRANSFER_VIRTUAL_EXPORT(vtkm::Float64); #undef VTK_M_ARRAY_TRANSFER_VIRTUAL_EXPORT #define VTK_M_STORAGE_VIRTUAL_EXPORT(T) \ extern template class VTKM_CONT_TEMPLATE_EXPORT StorageVirtualImpl; \ extern template class VTKM_CONT_TEMPLATE_EXPORT \ StorageVirtualImpl, VTKM_DEFAULT_STORAGE_TAG>; \ extern template class VTKM_CONT_TEMPLATE_EXPORT \ StorageVirtualImpl, VTKM_DEFAULT_STORAGE_TAG>; \ extern template class VTKM_CONT_TEMPLATE_EXPORT \ StorageVirtualImpl, VTKM_DEFAULT_STORAGE_TAG> VTK_M_STORAGE_VIRTUAL_EXPORT(char); VTK_M_STORAGE_VIRTUAL_EXPORT(vtkm::Int8); VTK_M_STORAGE_VIRTUAL_EXPORT(vtkm::UInt8); VTK_M_STORAGE_VIRTUAL_EXPORT(vtkm::Int16); VTK_M_STORAGE_VIRTUAL_EXPORT(vtkm::UInt16); VTK_M_STORAGE_VIRTUAL_EXPORT(vtkm::Int32); VTK_M_STORAGE_VIRTUAL_EXPORT(vtkm::UInt32); VTK_M_STORAGE_VIRTUAL_EXPORT(vtkm::Int64); VTK_M_STORAGE_VIRTUAL_EXPORT(vtkm::UInt64); VTK_M_STORAGE_VIRTUAL_EXPORT(vtkm::Float32); VTK_M_STORAGE_VIRTUAL_EXPORT(vtkm::Float64); #undef VTK_M_STORAGE_VIRTUAL_EXPORT #endif //!vtk_m_cont_StorageVirtual_cxx } // namespace detail template struct ArrayTransfer : detail::ArrayTransferVirtual { using Superclass = detail::ArrayTransferVirtual; VTKM_CONT ArrayTransfer(vtkm::cont::internal::Storage* storage) : Superclass(storage) { } VTKM_CONT typename Superclass::PortalConstExecution PrepareForInput(bool vtkmNotUsed(updateData), vtkm::cont::Token&) { return this->Superclass::PrepareForInput(Device()); } VTKM_CONT typename Superclass::PortalExecution PrepareForOutput(vtkm::Id numberOfValues, vtkm::cont::Token&) { return this->Superclass::PrepareForOutput(numberOfValues, Device()); } VTKM_CONT typename Superclass::PortalExecution PrepareForInPlace(bool vtkmNotUsed(updateData), vtkm::cont::Token&) { return this->Superclass::PrepareForInPlace(Device()); } }; VTKM_DEPRECATED_SUPPRESS_END } } } // namespace vtkm::cont::internal VTKM_DEPRECATED_SUPPRESS_END #endif // vtk_m_cont_StorageVirtual_hxx