Accelerated Computation Engine
opencl_buffer.h
1 #ifndef OPENCL_BUFFER_H
2 #define OPENCL_BUFFER_H
3 #include <CL/cl.h>
4 #include "opencl_context.h"
5 #include "opencl_commandqueue.h"
6 #include "opencl_event.h"
7 #include "opencl_common.h"
8 #include "eexception.h"
9 //
10 
11 
12 
13 namespace OpenCL
14 {
27  template<class T> class Buffer
28  {
29  public:
30  void operator=(Buffer<T>&& other);
31  T& operator[](int index);
32  public:
36  Buffer() = default;
37  Buffer(Context* context, int size);
38  Buffer(Buffer<T>&& other);
39  ~Buffer();
40  const T& at(int index) const;
41  bool isNull() const;
42  cl_mem id() const;
43  int size() const;
44  Event mapRead(CommandQueue* queue);
45  Event mapWrite(CommandQueue* queue);
46  Event unmap(CommandQueue* queue);
47  T* data();
48  private:
49  Event map(CommandQueue* queue, cl_map_flags mapping);
50  void clear();
51  void nullify();
56  cl_mem* _id {nullptr};
61  T* _data {nullptr};
66  int _size {-1};
71  cl_command_queue _last;
76  cl_map_flags _mapping;
77  };
78 
79 
80 
81 
82 
83 
91  template<class T> void Buffer<T>::operator=(Buffer<T>&& other)
92  {
93  // Clear this object of any OpenCL resources, take the other object's state, and
94  // set the other object to null.
95  clear();
96  _id = other._id;
97  _data = other._data;
98  _size = other._size;
99  _last = other._last;
100  _mapping = other._mapping;
101  other.nullify();
102  }
103 
104 
105 
106 
107 
108 
118  template<class T> T& Buffer<T>::operator[](int index)
119  {
120  // If this object is not mapped, the mapping is not for writing, or the given
121  // index is out of range then throw an exception, else return a reference to the
122  // mapped element with the given index.
123  if ( !_data )
124  {
125  E_MAKE_EXCEPTION(e);
126  e.setTitle(QObject::tr("Logic Error"));
127  e.setDetails(QObject::tr("Cannot access data from unmapped OpenCL buffer."));
128  throw e;
129  }
130  if ( _mapping != CL_MAP_WRITE )
131  {
132  E_MAKE_EXCEPTION(e);
133  e.setTitle(QObject::tr("Logic Error"));
134  e.setDetails(QObject::tr("Cannot write data to OpenCL buffer mapped for reading."));
135  throw e;
136  }
137  if ( index < 0 || index >= _size )
138  {
139  E_MAKE_EXCEPTION(e);
140  e.setTitle(QObject::tr("Out Of Range"));
141  e.setDetails(QObject::tr("The index %1 is out of range for this OpenCL buffer (%2 size).")
142  .arg(index)
143  .arg(_size));
144  throw e;
145  }
146  return _data[index];
147  }
148 
149 
150 
151 
152 
153 
163  template<class T> Buffer<T>::Buffer(Context* context, int size):
164  _id(new cl_mem),
165  _size(size)
166  {
167  // Create a new OpenCL buffer and set this object's buffer ID to the new buffer.
168  // If creation fails then throw an exception.
169  cl_int code;
170  *_id = clCreateBuffer(context->id(),CL_MEM_READ_WRITE,sizeof(T)*_size,nullptr,&code);
171  if ( code != CL_SUCCESS )
172  {
173  E_MAKE_EXCEPTION(e);
174  fillException(&e,code);
175  throw e;
176  }
177  }
178 
179 
180 
181 
182 
183 
191  template<class T> Buffer<T>::Buffer(Buffer<T>&& other):
192  _id(other._id),
193  _data(other._data),
194  _size(other._size),
195  _last(other._last),
196  _mapping(other._mapping)
197  {
198  other.nullify();
199  }
200 
201 
202 
203 
204 
205 
209  template<class T> Buffer<T>::~Buffer()
210  {
211  clear();
212  }
213 
214 
215 
216 
217 
218 
229  template<class T> const T& Buffer<T>::at(int index) const
230  {
231  // If this object is not mapped, the mapping is not for reading, or the given
232  // index is out of range then throw an exception, else return a read only
233  // reference to the mapped element with the given index.
234  if ( !_data )
235  {
236  E_MAKE_EXCEPTION(e);
237  e.setTitle(QObject::tr("Logic Error"));
238  e.setDetails(QObject::tr("Cannot access data from unmapped OpenCL buffer."));
239  throw e;
240  }
241  if ( _mapping != CL_MAP_READ )
242  {
243  E_MAKE_EXCEPTION(e);
244  e.setTitle(QObject::tr("Logic Error"));
245  e.setDetails(QObject::tr("Cannot read data from OpenCL buffer mapped for writing."));
246  throw e;
247  }
248  if ( index < 0 || index >= _size )
249  {
250  E_MAKE_EXCEPTION(e);
251  e.setTitle(QObject::tr("Out Of Range"));
252  e.setDetails(QObject::tr("The index %1 is out of range for this OpenCL buffer (%2 size).")
253  .arg(index)
254  .arg(_size));
255  throw e;
256  }
257  return _data[index];
258  }
259 
260 
261 
262 
263 
264 
270  template<class T> bool Buffer<T>::isNull() const
271  {
272  return !_id;
273  }
274 
275 
276 
277 
278 
279 
286  template<class T> cl_mem Buffer<T>::id() const
287  {
288  // If this object is null then throw an exception, else return this object's
289  // OpenCL buffer ID.
290  if ( !_id )
291  {
292  E_MAKE_EXCEPTION(e);
293  e.setTitle(QObject::tr("Logic Error"));
294  e.setDetails(QObject::tr("Cannot return OpenCL buffer ID of null object."));
295  throw e;
296  }
297  return *_id;
298  }
299 
300 
301 
302 
303 
304 
312  template<class T> int Buffer<T>::size() const
313  {
314  return _size;
315  }
316 
317 
318 
319 
320 
321 
334  template<class T> Event Buffer<T>::mapRead(CommandQueue* queue)
335  {
336  return map(queue,CL_MAP_READ);
337  }
338 
339 
340 
341 
342 
343 
356  template<class T> Event Buffer<T>::mapWrite(CommandQueue* queue)
357  {
358  return map(queue,CL_MAP_WRITE);
359  }
360 
361 
362 
363 
364 
365 
377  template<class T> Event Buffer<T>::unmap(CommandQueue* queue)
378  {
379  // If this object is null or is not mapped then throw an exception, else go to the
380  // next step.
381  if ( !_id )
382  {
383  E_MAKE_EXCEPTION(e);
384  e.setTitle(QObject::tr("Logic Error"));
385  e.setDetails(QObject::tr("Cannot unmap OpenCL buffer that is null."));
386  throw e;
387  }
388  if ( !_data )
389  {
390  E_MAKE_EXCEPTION(e);
391  e.setTitle(QObject::tr("Logic Error"));
392  e.setDetails(QObject::tr("Cannot unmap OpenCL buffer that is not mapped."));
393  throw e;
394  }
395 
396  // Add an unmap command to the given command queue for this object's OpenCL
397  // buffer. If adding the command fails then throw an exception.
398  cl_event id;
399  clEnqueueUnmapMemObject(queue->id(),*_id,_data,0,nullptr,&id);
400 
401  // Release the OpenCL command queue used to map this object's buffer and return
402  // the event of the unmapping command added to the given command queue in the last
403  // step. If releasing the command queue fails then throw an exception.
404  _data = nullptr;
405  cl_int code = {clReleaseCommandQueue(_last)};
406  if ( code != CL_SUCCESS )
407  {
408  E_MAKE_EXCEPTION(e);
409  fillException(&e,code);
410  throw e;
411  }
412  return Event(id);
413  }
414 
415 
416 
417 
418 
419 
428  template<class T> T* Buffer<T>::data()
429  {
430  // If this object is not mapped then throw an exception, else return the host
431  // memory pointer of this object's mapped OpenCL buffer.
432  if ( !_data )
433  {
434  E_MAKE_EXCEPTION(e);
435  e.setTitle(QObject::tr("Logic Error"));
436  e.setDetails(QObject::tr("Cannot access data from unmapped OpenCL buffer."));
437  throw e;
438  }
439  return _data;
440  }
441 
442 
443 
444 
445 
446 
458  template<class T> Event Buffer<T>::map(CommandQueue* queue, cl_map_flags mapping)
459  {
460  // If this object is null or is already mapped then throw an exception, else go to
461  // the next step.
462  if ( !_id )
463  {
464  E_MAKE_EXCEPTION(e);
465  e.setTitle(QObject::tr("Logic Error"));
466  e.setDetails(QObject::tr("Cannot unmap OpenCL buffer that is null."));
467  throw e;
468  }
469  if ( _data )
470  {
471  E_MAKE_EXCEPTION(e);
472  e.setTitle(QObject::tr("Logic Error"));
473  e.setDetails(QObject::tr("Cannot map OpenCL buffer that is already mapped."));
474  throw e;
475  }
476 
477  // Add a map command to the given command queue for this object's OpenCL buffer
478  // with the given mapping. If adding the command fails then throw an exception.
479  cl_int code;
480  cl_event id;
481  _data = static_cast<T*>(clEnqueueMapBuffer(queue->id()
482  ,*_id
483  ,false
484  ,mapping
485  ,0
486  ,sizeof(T)*_size
487  ,0
488  ,nullptr
489  ,&id
490  ,&code));
491  if ( code != CL_SUCCESS )
492  {
493  E_MAKE_EXCEPTION(e);
494  fillException(&e,code);
495  throw e;
496  }
497 
498  // Save the given command queue ID to this object, retain it, and return the event
499  // of the mapping command added to the given command queue in the last step. If
500  // retaining the command queue fails then throw an exception.
501  _last = queue->id();
502  code = clRetainCommandQueue(_last);
503  if ( code != CL_SUCCESS )
504  {
505  E_MAKE_EXCEPTION(e);
506  fillException(&e,code);
507  throw e;
508  }
509  _mapping = mapping;
510  return Event(id);
511  }
512 
513 
514 
515 
516 
517 
523  template<class T> void Buffer<T>::clear()
524  {
525  // If this object is null then do nothing and exit, else go to the next step.
526  if ( _id )
527  {
528  // If this object is mapped then call an unmap command with this object's saved
529  // command queue and then release it.
530  if ( _data )
531  {
532  clEnqueueUnmapMemObject(_last,*_id,_data,0,nullptr,nullptr);
533  clReleaseCommandQueue(_last);
534  }
535 
536  // Release this object's OpenCL buffer ID and then delete it.
537  clReleaseMemObject(*_id);
538  delete _id;
539  }
540  }
541 
542 
543 
544 
545 
546 
551  template<class T> void Buffer<T>::nullify()
552  {
553  // Set all this object's pointers and size to the null state.
554  _id = nullptr;
555  _data = nullptr;
556  _size = -1;
557  _last = nullptr;
558  }
559 }
560 
561 
562 
563 #endif
T * data()
Definition: opencl_buffer.h:428
const T & at(int index) const
Definition: opencl_buffer.h:229
~Buffer()
Definition: opencl_buffer.h:209
Event mapRead(CommandQueue *queue)
Definition: opencl_buffer.h:334
bool isNull() const
Definition: opencl_buffer.h:270
Definition: opencl_context.h:18
Definition: opencl_buffer.h:27
int size() const
Definition: opencl_buffer.h:312
cl_command_queue id() const
Definition: opencl_commandqueue.cpp:76
Definition: opencl_commandqueue.h:18
T & operator[](int index)
Definition: opencl_buffer.h:118
Definition: opencl_event.h:18
Event unmap(CommandQueue *queue)
Definition: opencl_buffer.h:377
cl_mem id() const
Definition: opencl_buffer.h:286
cl_context id() const
Definition: opencl_context.cpp:93
void fillException(EException *exception, cl_int code)
Definition: opencl_common.cpp:24
Buffer()=default
void operator=(Buffer< T > &&other)
Definition: opencl_buffer.h:91
Event mapWrite(CommandQueue *queue)
Definition: opencl_buffer.h:356
Definition: opencl.h:5