VTK-m  2.0
internal/TransferToOpenGL.h
Go to the documentation of this file.
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_interop_internal_TransferToOpenGL_h
11 #define vtk_m_interop_internal_TransferToOpenGL_h
12 
13 #include <vtkm/cont/ArrayHandle.h>
14 #include <vtkm/cont/Storage.h>
15 
19 
22 
23 namespace vtkm
24 {
25 namespace interop
26 {
27 namespace internal
28 {
29 
36 class SMPTransferResource : public vtkm::interop::internal::TransferResource
37 {
38 public:
39  template <typename T>
40  SMPTransferResource(T, vtkm::Id numberOfValues)
41  : vtkm::interop::internal::TransferResource()
42  , Size(0)
43  , TempStorage()
44  {
45  this->resize<T>(numberOfValues);
46  }
47 
48  ~SMPTransferResource() {}
49 
50  template <typename T>
51  void resize(vtkm::Id numberOfValues)
52  {
53  if (this->Size != numberOfValues)
54  {
55  this->Size = numberOfValues;
56  T* storage = new T[static_cast<std::size_t>(this->Size)];
57  this->TempStorage.reset(reinterpret_cast<vtkm::UInt8*>(storage));
58  }
59  }
60 
61  template <typename T>
63  {
64  VTKM_ASSERT(this->Size > 0);
65  VTKM_ASSERT(this->Size >= size);
66 
67  T* storage = reinterpret_cast<T*>(this->TempStorage.get());
68  //construct a handle that is a view onto the memory
70  }
71 
72  template <typename T>
73  T* as() const
74  {
75  VTKM_ASSERT(this->Size > 0);
76  T* storage = reinterpret_cast<T*>(this->TempStorage.get());
77  return storage;
78  }
79 
80  vtkm::Id Size;
81  std::unique_ptr<vtkm::UInt8[]> TempStorage;
82 };
83 
84 namespace detail
85 {
86 
87 template <class ValueType, class StorageTag, class DeviceAdapterTag>
88 VTKM_CONT void CopyFromHandle(const vtkm::cont::ArrayHandle<ValueType, StorageTag>& handle,
90  DeviceAdapterTag)
91 {
92  //Generic implementation that will work no matter what. We copy the data
93  //in the given handle to storage held by the buffer state.
94  const vtkm::Id numberOfValues = handle.GetNumberOfValues();
95  const GLsizeiptr size =
96  static_cast<GLsizeiptr>(sizeof(ValueType)) * static_cast<GLsizeiptr>(numberOfValues);
97 
98  //grab the temporary storage from the buffer resource
99  vtkm::interop::internal::SMPTransferResource* resource =
100  dynamic_cast<vtkm::interop::internal::SMPTransferResource*>(state.GetResource());
101 
102  //Determine if we need to reallocate the buffer
103  state.SetSize(size);
104  const bool resize = state.ShouldRealloc(size);
105 
106  if (resize)
107  {
108  //Allocate the memory and set it as GL_DYNAMIC_DRAW draw
109  glBufferData(state.GetType(), size, 0, GL_DYNAMIC_DRAW);
110  state.SetCapacity(size);
111 
112  //If we have an existing resource reallocate it to fit our new size
113  if (resource)
114  {
115  resource->resize<ValueType>(numberOfValues);
116  }
117  }
118 
119  //if we don't have a valid resource make a new one. We do this after the
120  //resize check so we don't double allocate when resource == nullptr and
121  //resize == true
122  if (!resource)
123  {
124  resource = new vtkm::interop::internal::SMPTransferResource(ValueType(), numberOfValues);
125  state.SetResource(resource);
126  }
127 
129  auto resourceHandle = resource->handle<ValueType>(numberOfValues);
130  Algorithm::Copy(handle, resourceHandle);
131 
132  //copy into opengl buffer
133  glBufferSubData(state.GetType(), 0, size, resource->as<ValueType>());
134 }
135 
136 template <class ValueType, class DeviceAdapterTag>
137 VTKM_CONT void CopyFromHandle(
140  DeviceAdapterTag)
141 {
142  //Specialization given that we are use an C allocated array storage tag
143  //that allows us to directly hook into the data. We pull the data
144  //back to the control environment using PerpareForInput and give an iterator
145  //from the portal to OpenGL to upload to the rendering system
146  //This also works because we know that this class isn't used for cuda interop,
147  //instead we are specialized
148  const GLsizeiptr size = static_cast<GLsizeiptr>(sizeof(ValueType)) *
149  static_cast<GLsizeiptr>(handle.GetNumberOfValues());
150 
151  //Determine if we need to reallocate the buffer
152  state.SetSize(size);
153  const bool resize = state.ShouldRealloc(size);
154  if (resize)
155  {
156  //Allocate the memory and set it as GL_DYNAMIC_DRAW draw
157  glBufferData(state.GetType(), size, 0, GL_DYNAMIC_DRAW);
158 
159  state.SetCapacity(size);
160  }
161 
162  //Allocate the memory and set it as static draw and copy into opengl
163  vtkm::cont::Token token;
164  auto portal = handle.PrepareForInput(DeviceAdapterTag{}, token);
165  const ValueType* memory = &(*vtkm::cont::ArrayPortalToIteratorBegin(portal));
166  glBufferSubData(state.GetType(), 0, size, memory);
167 }
168 
169 } //namespace detail
170 
176 template <typename ValueType, class DeviceAdapterTag>
177 class TransferToOpenGL
178 {
179 public:
180  VTKM_CONT explicit TransferToOpenGL(BufferState& state)
181  : State(state)
182  {
183  if (!this->State.HasType())
184  {
185  this->State.DeduceAndSetType(ValueType());
186  }
187  }
188 
189  template <typename StorageTag>
190  VTKM_CONT void Transfer(const vtkm::cont::ArrayHandle<ValueType, StorageTag>& handle) const
191  {
192  //make a buffer for the handle if the user has forgotten too
193  if (!glIsBuffer(*this->State.GetHandle()))
194  {
195  glGenBuffers(1, this->State.GetHandle());
196  }
197 
198  //bind the buffer to the given buffer type
199  glBindBuffer(this->State.GetType(), *this->State.GetHandle());
200 
201  //transfer the data.
202  //the primary concern that we have at this point is data locality and
203  //the type of storage. Our options include using DeviceAdapterAlgorithm::Copy
204  //and provide a temporary location for the values to reside before we give it
205  //to openGL this works for all storage types.
206  //
207  //Second option is to call PrepareForInput and get a PortalConst in the
208  //execution environment.
209  //if we are StorageTagBasic this would allow us the ability to grab
210  //the raw memory value and copy those, which we know are valid and remove
211  //a unneeded copy.
212  //
213  //The end result is that we have CopyFromHandle which does number two
214  //from StorageTagBasic, and does the DeviceAdapterAlgorithm::Copy for everything
215  //else
216  detail::CopyFromHandle(handle, this->State, DeviceAdapterTag());
217  }
218 
219 private:
221 };
222 }
223 }
224 } //namespace vtkm::interop::internal
225 
226 //-----------------------------------------------------------------------------
227 // These includes are intentionally placed here after the declaration of the
228 // TransferToOpenGL class, so that people get the correct device adapter
230 #if VTKM_DEVICE_ADAPTER == VTKM_DEVICE_ADAPTER_CUDA
232 #endif
233 
234 #endif //vtk_m_interop_internal_TransferToOpenGL_h
vtkm::cont::ArrayPortalToIteratorBegin
VTKM_SUPPRESS_EXEC_WARNINGS VTKM_EXEC_CONT vtkm::cont::ArrayPortalToIterators< PortalType >::IteratorType ArrayPortalToIteratorBegin(const PortalType &portal)
Convenience function for converting an ArrayPortal to a begin iterator.
Definition: ArrayPortalToIterators.h:178
vtkm::cont::ArrayHandle::GetNumberOfValues
VTKM_CONT vtkm::Id GetNumberOfValues() const
Returns the number of entries in the array.
Definition: ArrayHandle.h:448
vtkm::interop::TransferToOpenGL
VTKM_CONT void TransferToOpenGL(const vtkm::cont::ArrayHandle< ValueType, StorageTag > &handle, BufferState &state, DeviceAdapterTag)
Manages transferring an ArrayHandle to opengl .
Definition: TransferToOpenGL.h:41
vtkm::cont::make_ArrayHandle
VTKM_CONT vtkm::cont::ArrayHandleBasic< T > make_ArrayHandle(const T *array, vtkm::Id numberOfValues, vtkm::CopyFlag copy)
A convenience function for creating an ArrayHandle from a standard C array.
Definition: ArrayHandleBasic.h:217
vtkm::cont::ArrayHandle< T, vtkm::cont::StorageTagBasic >
ArrayHandle.h
vtkm::interop::BufferState
Manages the state for transferring an ArrayHandle to opengl.
Definition: BufferState.h:56
vtkm
Groups connected points that have the same field value.
Definition: Atomic.h:19
VTKM_ASSERT
#define VTKM_ASSERT(condition)
Definition: Assert.h:43
vtkm::cont::ArrayHandle::PrepareForInput
VTKM_CONT ReadPortalType PrepareForInput(vtkm::cont::DeviceAdapterId device, vtkm::cont::Token &token) const
Prepares this array to be used as an input to an operation in the execution environment.
Definition: ArrayHandle.h:574
DeviceAdapterTBB.h
OpenGLHeaders.h
Storage.h
DeviceAdapterAlgorithm.h
vtkm::Id
vtkm::Int32 Id
Represents an ID (index into arrays).
Definition: Types.h:191
vtkm::interop::BufferState::ShouldRealloc
bool ShouldRealloc(vtkm::Int64 desiredSize) const
Definition: BufferState.h:150
vtkm::cont::Token
A token to hold the scope of an ArrayHandle or other object.
Definition: Token.h:35
DeviceAdapterSerial.h
VTKM_CONT
#define VTKM_CONT
Definition: ExportMacros.h:57
vtkm::cont::DeviceAdapterAlgorithm
Struct containing device adapter algorithms.
Definition: DeviceAdapterAlgorithm.h:41
vtkm::UInt8
uint8_t UInt8
Definition: Types.h:157
TransferToOpenGL.h
vtkm::interop::BufferState::GetType
GLenum GetType() const
return what OpenGL buffer type we are bound to
Definition: BufferState.h:110
vtkm::interop::BufferState::GetResource
vtkm::interop::internal::TransferResource * GetResource()
Definition: BufferState.h:163
vtkm::CopyFlag::Off
@ Off
BufferState.h
vtkm::interop::BufferState::SetCapacity
void SetCapacity(vtkm::Int64 capacity)
Definition: BufferState.h:160
vtkm::interop::BufferState::SetResource
void SetResource(vtkm::interop::internal::TransferResource *resource)
Definition: BufferState.h:166
vtkm::interop::BufferState::SetSize
void SetSize(vtkm::Int64 size)
Definition: BufferState.h:137