Viskores  1.0
cuda/internal/TransferToOpenGL.h
Go to the documentation of this file.
1 //============================================================================
2 // The contents of this file are covered by the Viskores license. See
3 // LICENSE.txt for details.
4 //
5 // By contributing to this file, all contributors agree to the Developer
6 // Certificate of Origin Version 1.1 (DCO 1.1) as stated in DCO.txt.
7 //============================================================================
8 
9 //============================================================================
10 // Copyright (c) Kitware, Inc.
11 // All rights reserved.
12 // See LICENSE.txt for details.
13 //
14 // This software is distributed WITHOUT ANY WARRANTY; without even
15 // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
16 // PURPOSE. See the above copyright notice for more information.
17 //============================================================================
18 #ifndef viskores_interop_cuda_internal_TransferToOpenGL_h
19 #define viskores_interop_cuda_internal_TransferToOpenGL_h
20 
23 
25 
27 
28 // Disable warnings we check viskores for but Thrust does not.
31 #include <thrust/copy.h>
32 #include <thrust/device_ptr.h>
33 #include <thrust/system/cuda/execution_policy.h>
34 #include <viskores/exec/cuda/internal/ExecutionPolicy.h>
36 
37 namespace viskores
38 {
39 namespace interop
40 {
41 namespace internal
42 {
43 
49 class CudaTransferResource : public viskores::interop::internal::TransferResource
50 {
51 public:
52  CudaTransferResource()
53  : viskores::interop::internal::TransferResource()
54  {
55  this->Registered = false;
56  }
57 
58  ~CudaTransferResource()
59  {
60  //unregister the buffer
61  if (this->Registered)
62  {
63  cudaGraphicsUnregisterResource(this->CudaResource);
64  }
65  }
66 
67  bool IsRegistered() const { return Registered; }
68 
69  void Register(GLuint* handle)
70  {
71  if (this->Registered)
72  {
73  //If you don't release the cuda resource before re-registering you
74  //will leak memory on the OpenGL side.
75  cudaGraphicsUnregisterResource(this->CudaResource);
76  }
77 
78  this->Registered = true;
79  cudaError_t cError =
80  cudaGraphicsGLRegisterBuffer(&this->CudaResource, *handle, cudaGraphicsMapFlagsWriteDiscard);
81  if (cError != cudaSuccess)
82  {
83  throw viskores::cont::ErrorExecution("Could not register the OpenGL buffer handle to CUDA.");
84  }
85  }
86 
87  void Map()
88  {
89  //map the resource into cuda, so we can copy it
90  cudaError_t cError = cudaGraphicsMapResources(1, &this->CudaResource, cudaStreamPerThread);
91  if (cError != cudaSuccess)
92  {
94  "Could not allocate enough memory in CUDA for OpenGL interop.");
95  }
96  }
97 
98  template <typename ValueType>
99  ValueType* GetMappedPoiner(viskores::Int64 desiredSize)
100  {
101  //get the mapped pointer
102  std::size_t cuda_size;
103  ValueType* pointer = nullptr;
104  cudaError_t cError =
105  cudaGraphicsResourceGetMappedPointer((void**)&pointer, &cuda_size, this->CudaResource);
106 
107  if (cError != cudaSuccess)
108  {
110  "Unable to get pointers to CUDA memory for OpenGL buffer.");
111  }
112 
113  //assert that cuda_size is the same size as the buffer we created in OpenGL
114  VISKORES_ASSERT(cuda_size >= static_cast<std::size_t>(desiredSize));
115  return pointer;
116  }
117 
118  void UnMap() { cudaGraphicsUnmapResources(1, &this->CudaResource, cudaStreamPerThread); }
119 
120 private:
121  bool Registered;
122  cudaGraphicsResource_t CudaResource;
123 };
124 
130 template <typename ValueType>
131 class TransferToOpenGL<ValueType, viskores::cont::DeviceAdapterTagCuda>
132 {
133  using DeviceAdapterTag = viskores::cont::DeviceAdapterTagCuda;
134 
135 public:
136  VISKORES_CONT explicit TransferToOpenGL(BufferState& state)
137  : State(state)
138  , Resource(nullptr)
139  {
140  if (!this->State.HasType())
141  {
142  this->State.DeduceAndSetType(ValueType());
143  }
144 
145  this->Resource =
146  dynamic_cast<viskores::interop::internal::CudaTransferResource*>(state.GetResource());
147  if (!this->Resource)
148  {
149  viskores::interop::internal::CudaTransferResource* cudaResource =
150  new viskores::interop::internal::CudaTransferResource();
151 
152  //reset the resource to be a cuda resource
153  this->State.SetResource(cudaResource);
154  this->Resource = cudaResource;
155  }
156  }
157 
158  template <typename StorageTag>
159  VISKORES_CONT void Transfer(
161  {
162  //make a buffer for the handle if the user has forgotten too
163  if (!glIsBuffer(*this->State.GetHandle()))
164  {
165  glGenBuffers(1, this->State.GetHandle());
166  }
167 
168  //bind the buffer to the given buffer type
169  glBindBuffer(this->State.GetType(), *this->State.GetHandle());
170 
171  //Determine if we need to reallocate the buffer
172  const viskores::Int64 size =
173  static_cast<viskores::Int64>(sizeof(ValueType)) * handle.GetNumberOfValues();
174  this->State.SetSize(size);
175  const bool resize = this->State.ShouldRealloc(size);
176  if (resize)
177  {
178  //Allocate the memory and set it as GL_DYNAMIC_DRAW draw
179  glBufferData(this->State.GetType(), static_cast<GLsizeiptr>(size), 0, GL_DYNAMIC_DRAW);
180 
181  this->State.SetCapacity(size);
182  }
183 
184  if (!this->Resource->IsRegistered() || resize)
185  {
186  //register the buffer as being used by cuda. This needs to be done everytime
187  //we change the size of the buffer. That is why we only change the buffer
188  //size as infrequently as possible
189  this->Resource->Register(this->State.GetHandle());
190  }
191 
192  this->Resource->Map();
193 
194  ValueType* beginPointer = this->Resource->GetMappedPoiner<ValueType>(size);
196  beginPointer, handle.GetNumberOfValues(), DeviceAdapterTag{}, [](void*) {});
197 
198  //Do a device to device memory copy
200 
201  //unmap the resource
202  this->Resource->UnMap();
203  }
204 
205 private:
207  viskores::interop::internal::CudaTransferResource* Resource;
208 };
209 }
210 }
211 } //namespace viskores::interop::cuda::internal
212 
213 #endif
ErrorBadAllocation.h
viskores::cont::ErrorBadAllocation
This class is thrown when Viskores attempts to manipulate memory that it should not.
Definition: ErrorBadAllocation.h:33
viskores::cont::ErrorExecution
This class is thrown in the control environment whenever an error occurs in the execution environment...
Definition: ErrorExecution.h:33
VISKORES_THIRDPARTY_POST_INCLUDE
#define VISKORES_THIRDPARTY_POST_INCLUDE
Definition: Configure.h:200
viskores::cont::DeviceAdapterTagCuda
Tag for a device adapter that uses a CUDA capable GPU device.
Definition: DeviceAdapterTagCuda.h:41
viskores::cont::ArrayHandle
Manages an array-worth of data.
Definition: ArrayHandle.h:313
ThrustPatches.h
DeviceAdapterTagCuda.h
viskores::Int64
signed long long Int64
Base type to use for 64-bit signed integer numbers.
Definition: Types.h:212
VISKORES_CONT
#define VISKORES_CONT
Definition: ExportMacros.h:65
viskores
Groups connected points that have the same field value.
Definition: Atomic.h:27
viskores::cont::DeviceAdapterAlgorithm::Copy
static void Copy(const viskores::cont::ArrayHandle< T, CIn > &input, viskores::cont::ArrayHandle< U, COut > &output)
Copy the contents of one ArrayHandle to another.
viskores::interop::BufferState
Manages the state for transferring an ArrayHandle to opengl.
Definition: BufferState.h:64
viskores::cont::ArrayHandleBasic
Basic array storage for an array handle.
Definition: ArrayHandleBasic.h:120
viskores::cont::ArrayHandle::GetNumberOfValues
viskores::Id GetNumberOfValues() const
Returns the number of entries in the array.
Definition: ArrayHandle.h:482
viskores::interop::TransferToOpenGL
void TransferToOpenGL(const viskores::cont::ArrayHandle< ValueType, StorageTag > &handle, BufferState &state, DeviceAdapterTag)
Manages transferring an ArrayHandle to opengl .
Definition: TransferToOpenGL.h:49
VISKORES_ASSERT
#define VISKORES_ASSERT(condition)
Definition: Assert.h:51
ErrorExecution.h
TransferToOpenGL.h
VISKORES_THIRDPARTY_PRE_INCLUDE
#define VISKORES_THIRDPARTY_PRE_INCLUDE
Definition: Configure.h:199