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_cont_VirtualObjectHandle_h 11 #define vtk_m_cont_VirtualObjectHandle_h 12 13 #include <vtkm/cont/DeviceAdapterList.h> 14 #include <vtkm/cont/ExecutionAndControlObjectBase.h> 15 #include <vtkm/cont/internal/DeviceAdapterListHelpers.h> 16 #include <vtkm/cont/internal/VirtualObjectTransfer.h> 17 18 #include <array> 19 #include <type_traits> 20 21 namespace vtkm 22 { 23 namespace cont 24 { 25 26 namespace internal 27 { 28 struct CreateTransferInterface 29 { 30 template <typename VirtualDerivedType, typename DeviceAdapter> operatorCreateTransferInterface31 VTKM_CONT inline void operator()(DeviceAdapter device, 32 internal::TransferState* transfers, 33 const VirtualDerivedType* virtualObject) const 34 { 35 using TransferImpl = TransferInterfaceImpl<VirtualDerivedType, DeviceAdapter>; 36 auto i = static_cast<std::size_t>(device.GetValue()); 37 transfers->DeviceTransferState[i].reset(new TransferImpl(virtualObject)); 38 } 39 }; 40 } 41 42 /// \brief Implements VTK-m's execution side <em> Virtual Methods </em> functionality. 43 /// 44 /// The template parameter \c VirtualBaseType is the base class that acts as the 45 /// interface. This base clase must inherit from \c vtkm::VirtualObjectBase. See the 46 /// documentation of that class to see the other requirements. 47 /// 48 /// A derived object can be bound to the handle either during construction or using the \c Reset 49 /// function on previously constructed handles. These function accept a control side pointer to 50 /// the derived class object, a boolean flag stating if the handle should acquire ownership of 51 /// the object (i.e. manage the lifetime), and a type-list of device adapter tags where the object 52 /// is expected to be used. 53 /// 54 /// To get an execution side pointer call the \c PrepareForExecution function. The device adapter 55 /// passed to this function should be one of the device in the list passed during the set up of 56 /// the handle. 57 /// 58 /// 59 /// \sa vtkm::VirtualObjectBase 60 /// 61 template <typename VirtualBaseType> 62 class VTKM_ALWAYS_EXPORT VirtualObjectHandle : public vtkm::cont::ExecutionAndControlObjectBase 63 { 64 VTKM_STATIC_ASSERT_MSG((std::is_base_of<vtkm::VirtualObjectBase, VirtualBaseType>::value), 65 "All virtual objects must be subclass of vtkm::VirtualObjectBase."); 66 67 public: VirtualObjectHandle()68 VTKM_CONT VirtualObjectHandle() 69 : Internals(std::make_shared<internal::TransferState>()) 70 { 71 } 72 73 template <typename VirtualDerivedType, 74 typename DeviceAdapterList = VTKM_DEFAULT_DEVICE_ADAPTER_LIST> 75 VTKM_CONT explicit VirtualObjectHandle(VirtualDerivedType* derived, 76 bool acquireOwnership = true, 77 DeviceAdapterList devices = DeviceAdapterList()) Internals(std::make_shared<internal::TransferState> ())78 : Internals(std::make_shared<internal::TransferState>()) 79 { 80 this->Reset(derived, acquireOwnership, devices); 81 } 82 83 /// Get if in a valid state (a target is bound) GetValid()84 VTKM_CONT bool GetValid() const { return this->Internals->HostPtr() != nullptr; } 85 86 87 /// Get if this handle owns the control side target object OwnsObject()88 VTKM_CONT bool OwnsObject() const { return this->Internals->WillReleaseHostPointer(); } 89 90 /// Get the control side pointer to the virtual object Get()91 VTKM_CONT VirtualBaseType* Get() const 92 { 93 return static_cast<VirtualBaseType*>(this->Internals->HostPtr()); 94 } 95 96 /// Reset the underlying derived type object 97 template <typename VirtualDerivedType, 98 typename DeviceAdapterList = VTKM_DEFAULT_DEVICE_ADAPTER_LIST> 99 VTKM_CONT void Reset(VirtualDerivedType* derived, 100 bool acquireOwnership = true, 101 DeviceAdapterList devices = DeviceAdapterList()) 102 { 103 VTKM_DEPRECATED_SUPPRESS_BEGIN 104 VTKM_STATIC_ASSERT_MSG((std::is_base_of<VirtualBaseType, VirtualDerivedType>::value), 105 "Tried to bind a type that is not a subclass of the base class."); 106 107 if (acquireOwnership) 108 { 109 auto deleter = [](void* p) { delete static_cast<VirtualBaseType*>(p); }; 110 this->Internals->UpdateHost(derived, deleter); 111 } 112 else 113 { 114 this->Internals->UpdateHost(derived, nullptr); 115 } 116 117 if (derived) 118 { 119 vtkm::cont::internal::ForEachValidDevice( 120 devices, internal::CreateTransferInterface(), this->Internals.get(), derived); 121 } 122 VTKM_DEPRECATED_SUPPRESS_END 123 } 124 125 /// Release all host and execution side resources ReleaseResources()126 VTKM_CONT void ReleaseResources() { this->Internals->ReleaseResources(); } 127 128 /// Release all the execution side resources ReleaseExecutionResources()129 VTKM_CONT void ReleaseExecutionResources() { this->Internals->ReleaseExecutionResources(); } 130 131 /// Get a valid \c VirtualBaseType* with the current control side state for \c deviceId. 132 /// VirtualObjectHandle and the returned pointer are analogous to ArrayHandle and Portal 133 /// The returned pointer will be invalidated if: 134 /// 1. A new pointer is requested for a different deviceId 135 /// 2. VirtualObjectHandle is destroyed 136 /// 3. Reset or ReleaseResources is called 137 /// PrepareForExecution(vtkm::cont::DeviceAdapterId deviceId,vtkm::cont::Token &)138 VTKM_CONT const VirtualBaseType* PrepareForExecution(vtkm::cont::DeviceAdapterId deviceId, 139 vtkm::cont::Token&) const 140 { 141 const bool validId = this->Internals->DeviceIdIsValid(deviceId); 142 if (!validId) 143 { //can't be reached since DeviceIdIsValid will through an exception 144 //if deviceId is not valid 145 return nullptr; 146 } 147 148 return static_cast<const VirtualBaseType*>(this->Internals->PrepareForExecution(deviceId)); 149 } 150 151 VTKM_CONT 152 VTKM_DEPRECATED(1.6, "PrepareForExecution now requires a vtkm::cont::Token object.") PrepareForExecution(vtkm::cont::DeviceAdapterId deviceId)153 const VirtualBaseType* PrepareForExecution(vtkm::cont::DeviceAdapterId deviceId) const 154 { 155 vtkm::cont::Token token; 156 return this->PrepareForExecution(deviceId, token); 157 } 158 159 /// Used as part of the \c ExecutionAndControlObjectBase interface. Returns the same pointer 160 /// as \c Get. PrepareForControl()161 VTKM_CONT const VirtualBaseType* PrepareForControl() const { return this->Get(); } 162 163 private: 164 std::shared_ptr<internal::TransferState> Internals; 165 }; 166 } 167 } // vtkm::cont 168 169 #endif // vtk_m_cont_VirtualObjectHandle_h 170