• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //---------------------------------------------------------------------------//
2 // Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com>
3 //
4 // Distributed under the Boost Software License, Version 1.0
5 // See accompanying file LICENSE_1_0.txt or copy at
6 // http://www.boost.org/LICENSE_1_0.txt
7 //
8 // See http://boostorg.github.com/compute for more information.
9 //---------------------------------------------------------------------------//
10 
11 #ifndef BOOST_COMPUTE_COMMAND_QUEUE_HPP
12 #define BOOST_COMPUTE_COMMAND_QUEUE_HPP
13 
14 #include <cstddef>
15 #include <algorithm>
16 
17 #include <boost/assert.hpp>
18 
19 #include <boost/compute/config.hpp>
20 #include <boost/compute/event.hpp>
21 #include <boost/compute/buffer.hpp>
22 #include <boost/compute/device.hpp>
23 #include <boost/compute/kernel.hpp>
24 #include <boost/compute/context.hpp>
25 #include <boost/compute/exception.hpp>
26 #include <boost/compute/image/image1d.hpp>
27 #include <boost/compute/image/image2d.hpp>
28 #include <boost/compute/image/image3d.hpp>
29 #include <boost/compute/image/image_object.hpp>
30 #include <boost/compute/utility/wait_list.hpp>
31 #include <boost/compute/detail/get_object_info.hpp>
32 #include <boost/compute/detail/assert_cl_success.hpp>
33 #include <boost/compute/detail/diagnostic.hpp>
34 #include <boost/compute/utility/extents.hpp>
35 
36 namespace boost {
37 namespace compute {
38 namespace detail {
39 
40 inline void BOOST_COMPUTE_CL_CALLBACK
nullary_native_kernel_trampoline(void * user_func_ptr)41 nullary_native_kernel_trampoline(void *user_func_ptr)
42 {
43     void (*user_func)();
44     std::memcpy(&user_func, user_func_ptr, sizeof(user_func));
45     user_func();
46 }
47 
48 } // end detail namespace
49 
50 /// \class command_queue
51 /// \brief A command queue.
52 ///
53 /// Command queues provide the interface for interacting with compute
54 /// devices. The command_queue class provides methods to copy data to
55 /// and from a compute device as well as execute compute kernels.
56 ///
57 /// Command queues are created for a compute device within a compute
58 /// context.
59 ///
60 /// For example, to create a context and command queue for the default device
61 /// on the system (this is the normal set up code used by almost all OpenCL
62 /// programs):
63 /// \code
64 /// #include <boost/compute/core.hpp>
65 ///
66 /// // get the default compute device
67 /// boost::compute::device device = boost::compute::system::default_device();
68 ///
69 /// // set up a compute context and command queue
70 /// boost::compute::context context(device);
71 /// boost::compute::command_queue queue(context, device);
72 /// \endcode
73 ///
74 /// The default command queue for the system can be obtained with the
75 /// system::default_queue() method.
76 ///
77 /// \see buffer, context, kernel
78 class command_queue
79 {
80 public:
81     enum properties {
82         enable_profiling = CL_QUEUE_PROFILING_ENABLE,
83         enable_out_of_order_execution = CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE
84         #ifdef BOOST_COMPUTE_CL_VERSION_2_0
85         ,
86         on_device = CL_QUEUE_ON_DEVICE,
87         on_device_default = CL_QUEUE_ON_DEVICE_DEFAULT
88         #endif
89     };
90 
91     enum map_flags {
92         map_read = CL_MAP_READ,
93         map_write = CL_MAP_WRITE
94         #ifdef BOOST_COMPUTE_CL_VERSION_1_2
95         ,
96         map_write_invalidate_region = CL_MAP_WRITE_INVALIDATE_REGION
97         #endif
98     };
99 
100     #ifdef BOOST_COMPUTE_CL_VERSION_1_2
101     enum mem_migration_flags {
102         migrate_to_host = CL_MIGRATE_MEM_OBJECT_HOST,
103         migrate_content_undefined = CL_MIGRATE_MEM_OBJECT_CONTENT_UNDEFINED
104     };
105     #endif // BOOST_COMPUTE_CL_VERSION_1_2
106 
107     /// Creates a null command queue.
command_queue()108     command_queue()
109         : m_queue(0)
110     {
111     }
112 
command_queue(cl_command_queue queue,bool retain=true)113     explicit command_queue(cl_command_queue queue, bool retain = true)
114         : m_queue(queue)
115     {
116         if(m_queue && retain){
117             clRetainCommandQueue(m_queue);
118         }
119     }
120 
121     /// Creates a command queue in \p context for \p device with
122     /// \p properties.
123     ///
124     /// \see_opencl_ref{clCreateCommandQueue}
command_queue(const context & context,const device & device,cl_command_queue_properties properties=0)125     command_queue(const context &context,
126                   const device &device,
127                   cl_command_queue_properties properties = 0)
128     {
129         BOOST_ASSERT(device.id() != 0);
130 
131         cl_int error = 0;
132 
133         #ifdef BOOST_COMPUTE_CL_VERSION_2_0
134         if (device.check_version(2, 0)){
135             std::vector<cl_queue_properties> queue_properties;
136             if(properties){
137                 queue_properties.push_back(CL_QUEUE_PROPERTIES);
138                 queue_properties.push_back(cl_queue_properties(properties));
139                 queue_properties.push_back(cl_queue_properties(0));
140             }
141 
142             const cl_queue_properties *queue_properties_ptr =
143                 queue_properties.empty() ? 0 : &queue_properties[0];
144 
145             m_queue = clCreateCommandQueueWithProperties(
146                 context, device.id(), queue_properties_ptr, &error
147             );
148         } else
149         #endif
150         {
151             // Suppress deprecated declarations warning
152             BOOST_COMPUTE_DISABLE_DEPRECATED_DECLARATIONS();
153             m_queue = clCreateCommandQueue(
154                 context, device.id(), properties, &error
155             );
156             BOOST_COMPUTE_ENABLE_DEPRECATED_DECLARATIONS();
157         }
158 
159         if(!m_queue){
160             BOOST_THROW_EXCEPTION(opencl_error(error));
161         }
162     }
163 
164     /// Creates a new command queue object as a copy of \p other.
command_queue(const command_queue & other)165     command_queue(const command_queue &other)
166         : m_queue(other.m_queue)
167     {
168         if(m_queue){
169             clRetainCommandQueue(m_queue);
170         }
171     }
172 
173     /// Copies the command queue object from \p other to \c *this.
operator =(const command_queue & other)174     command_queue& operator=(const command_queue &other)
175     {
176         if(this != &other){
177             if(m_queue){
178                 clReleaseCommandQueue(m_queue);
179             }
180 
181             m_queue = other.m_queue;
182 
183             if(m_queue){
184                 clRetainCommandQueue(m_queue);
185             }
186         }
187 
188         return *this;
189     }
190 
191     #ifndef BOOST_COMPUTE_NO_RVALUE_REFERENCES
192     /// Move-constructs a new command queue object from \p other.
command_queue(command_queue && other)193     command_queue(command_queue&& other) BOOST_NOEXCEPT
194         : m_queue(other.m_queue)
195     {
196         other.m_queue = 0;
197     }
198 
199     /// Move-assigns the command queue from \p other to \c *this.
operator =(command_queue && other)200     command_queue& operator=(command_queue&& other) BOOST_NOEXCEPT
201     {
202         if(m_queue){
203             clReleaseCommandQueue(m_queue);
204         }
205 
206         m_queue = other.m_queue;
207         other.m_queue = 0;
208 
209         return *this;
210     }
211     #endif // BOOST_COMPUTE_NO_RVALUE_REFERENCES
212 
213     /// Destroys the command queue.
214     ///
215     /// \see_opencl_ref{clReleaseCommandQueue}
~command_queue()216     ~command_queue()
217     {
218         if(m_queue){
219             BOOST_COMPUTE_ASSERT_CL_SUCCESS(
220                 clReleaseCommandQueue(m_queue)
221             );
222         }
223     }
224 
225     /// Returns the underlying OpenCL command queue.
get() const226     cl_command_queue& get() const
227     {
228         return const_cast<cl_command_queue &>(m_queue);
229     }
230 
231     /// Returns the device that the command queue issues commands to.
get_device() const232     device get_device() const
233     {
234         return device(get_info<cl_device_id>(CL_QUEUE_DEVICE));
235     }
236 
237     /// Returns the context for the command queue.
get_context() const238     context get_context() const
239     {
240         return context(get_info<cl_context>(CL_QUEUE_CONTEXT));
241     }
242 
243     /// Returns information about the command queue.
244     ///
245     /// \see_opencl_ref{clGetCommandQueueInfo}
246     template<class T>
get_info(cl_command_queue_info info) const247     T get_info(cl_command_queue_info info) const
248     {
249         return detail::get_object_info<T>(clGetCommandQueueInfo, m_queue, info);
250     }
251 
252     /// \overload
253     template<int Enum>
254     typename detail::get_object_info_type<command_queue, Enum>::type
255     get_info() const;
256 
257     /// Returns the properties for the command queue.
get_properties() const258     cl_command_queue_properties get_properties() const
259     {
260         return get_info<cl_command_queue_properties>(CL_QUEUE_PROPERTIES);
261     }
262 
263     #if defined(BOOST_COMPUTE_CL_VERSION_2_1) || defined(BOOST_COMPUTE_DOXYGEN_INVOKED)
264     /// Returns the current default device command queue for the underlying device.
265     ///
266     /// \opencl_version_warning{2,1}
get_default_device_queue() const267     command_queue get_default_device_queue() const
268     {
269         return command_queue(get_info<cl_command_queue>(CL_QUEUE_DEVICE_DEFAULT));
270     }
271 
272     /// Replaces the default device command queue for the underlying device
273     /// with this command queue. Command queue must have been created
274     /// with CL_QUEUE_ON_DEVICE flag.
275     ///
276     /// \see_opencl21_ref{clSetDefaultDeviceCommandQueue}
277     ///
278     /// \opencl_version_warning{2,1}
set_as_default_device_queue() const279     void set_as_default_device_queue() const
280     {
281         cl_int ret = clSetDefaultDeviceCommandQueue(
282             this->get_context().get(),
283             this->get_device().get(),
284             m_queue
285         );
286         if(ret != CL_SUCCESS){
287             BOOST_THROW_EXCEPTION(opencl_error(ret));
288         }
289     }
290     #endif // BOOST_COMPUTE_CL_VERSION_2_1
291 
292     /// Enqueues a command to read data from \p buffer to host memory.
293     ///
294     /// \see_opencl_ref{clEnqueueReadBuffer}
295     ///
296     /// \see copy()
enqueue_read_buffer(const buffer & buffer,size_t offset,size_t size,void * host_ptr,const wait_list & events=wait_list ())297     event enqueue_read_buffer(const buffer &buffer,
298                               size_t offset,
299                               size_t size,
300                               void *host_ptr,
301                               const wait_list &events = wait_list())
302     {
303         BOOST_ASSERT(m_queue != 0);
304         BOOST_ASSERT(size <= buffer.size());
305         BOOST_ASSERT(buffer.get_context() == this->get_context());
306         BOOST_ASSERT(host_ptr != 0);
307 
308         event event_;
309 
310         cl_int ret = clEnqueueReadBuffer(
311             m_queue,
312             buffer.get(),
313             CL_TRUE,
314             offset,
315             size,
316             host_ptr,
317             events.size(),
318             events.get_event_ptr(),
319             &event_.get()
320         );
321 
322         if(ret != CL_SUCCESS){
323             BOOST_THROW_EXCEPTION(opencl_error(ret));
324         }
325 
326         return event_;
327     }
328 
329     /// Enqueues a command to read data from \p buffer to host memory. The
330     /// copy will be performed asynchronously.
331     ///
332     /// \see_opencl_ref{clEnqueueReadBuffer}
333     ///
334     /// \see copy_async()
enqueue_read_buffer_async(const buffer & buffer,size_t offset,size_t size,void * host_ptr,const wait_list & events=wait_list ())335     event enqueue_read_buffer_async(const buffer &buffer,
336                                     size_t offset,
337                                     size_t size,
338                                     void *host_ptr,
339                                     const wait_list &events = wait_list())
340     {
341         BOOST_ASSERT(m_queue != 0);
342         BOOST_ASSERT(size <= buffer.size());
343         BOOST_ASSERT(buffer.get_context() == this->get_context());
344         BOOST_ASSERT(host_ptr != 0);
345 
346         event event_;
347 
348         cl_int ret = clEnqueueReadBuffer(
349             m_queue,
350             buffer.get(),
351             CL_FALSE,
352             offset,
353             size,
354             host_ptr,
355             events.size(),
356             events.get_event_ptr(),
357             &event_.get()
358         );
359 
360         if(ret != CL_SUCCESS){
361             BOOST_THROW_EXCEPTION(opencl_error(ret));
362         }
363 
364         return event_;
365     }
366 
367     #if defined(BOOST_COMPUTE_CL_VERSION_1_1) || defined(BOOST_COMPUTE_DOXYGEN_INVOKED)
368     /// Enqueues a command to read a rectangular region from \p buffer to
369     /// host memory.
370     ///
371     /// \see_opencl_ref{clEnqueueReadBufferRect}
372     ///
373     /// \opencl_version_warning{1,1}
enqueue_read_buffer_rect(const buffer & buffer,const size_t buffer_origin[3],const size_t host_origin[3],const size_t region[3],size_t buffer_row_pitch,size_t buffer_slice_pitch,size_t host_row_pitch,size_t host_slice_pitch,void * host_ptr,const wait_list & events=wait_list ())374     event enqueue_read_buffer_rect(const buffer &buffer,
375                                    const size_t buffer_origin[3],
376                                    const size_t host_origin[3],
377                                    const size_t region[3],
378                                    size_t buffer_row_pitch,
379                                    size_t buffer_slice_pitch,
380                                    size_t host_row_pitch,
381                                    size_t host_slice_pitch,
382                                    void *host_ptr,
383                                    const wait_list &events = wait_list())
384     {
385         BOOST_ASSERT(m_queue != 0);
386         BOOST_ASSERT(buffer.get_context() == this->get_context());
387         BOOST_ASSERT(host_ptr != 0);
388 
389         event event_;
390 
391         cl_int ret = clEnqueueReadBufferRect(
392             m_queue,
393             buffer.get(),
394             CL_TRUE,
395             buffer_origin,
396             host_origin,
397             region,
398             buffer_row_pitch,
399             buffer_slice_pitch,
400             host_row_pitch,
401             host_slice_pitch,
402             host_ptr,
403             events.size(),
404             events.get_event_ptr(),
405             &event_.get()
406         );
407 
408         if(ret != CL_SUCCESS){
409             BOOST_THROW_EXCEPTION(opencl_error(ret));
410         }
411 
412         return event_;
413     }
414 
415     /// Enqueues a command to read a rectangular region from \p buffer to
416     /// host memory. The copy will be performed asynchronously.
417     ///
418     /// \see_opencl_ref{clEnqueueReadBufferRect}
419     ///
420     /// \opencl_version_warning{1,1}
enqueue_read_buffer_rect_async(const buffer & buffer,const size_t buffer_origin[3],const size_t host_origin[3],const size_t region[3],size_t buffer_row_pitch,size_t buffer_slice_pitch,size_t host_row_pitch,size_t host_slice_pitch,void * host_ptr,const wait_list & events=wait_list ())421     event enqueue_read_buffer_rect_async(const buffer &buffer,
422                                          const size_t buffer_origin[3],
423                                          const size_t host_origin[3],
424                                          const size_t region[3],
425                                          size_t buffer_row_pitch,
426                                          size_t buffer_slice_pitch,
427                                          size_t host_row_pitch,
428                                          size_t host_slice_pitch,
429                                          void *host_ptr,
430                                          const wait_list &events = wait_list())
431     {
432         BOOST_ASSERT(m_queue != 0);
433         BOOST_ASSERT(buffer.get_context() == this->get_context());
434         BOOST_ASSERT(host_ptr != 0);
435 
436         event event_;
437 
438         cl_int ret = clEnqueueReadBufferRect(
439             m_queue,
440             buffer.get(),
441             CL_FALSE,
442             buffer_origin,
443             host_origin,
444             region,
445             buffer_row_pitch,
446             buffer_slice_pitch,
447             host_row_pitch,
448             host_slice_pitch,
449             host_ptr,
450             events.size(),
451             events.get_event_ptr(),
452             &event_.get()
453         );
454 
455         if(ret != CL_SUCCESS){
456             BOOST_THROW_EXCEPTION(opencl_error(ret));
457         }
458 
459         return event_;
460     }
461     #endif // BOOST_COMPUTE_CL_VERSION_1_1
462 
463     /// Enqueues a command to write data from host memory to \p buffer.
464     ///
465     /// \see_opencl_ref{clEnqueueWriteBuffer}
466     ///
467     /// \see copy()
enqueue_write_buffer(const buffer & buffer,size_t offset,size_t size,const void * host_ptr,const wait_list & events=wait_list ())468     event enqueue_write_buffer(const buffer &buffer,
469                                size_t offset,
470                                size_t size,
471                                const void *host_ptr,
472                                const wait_list &events = wait_list())
473     {
474         BOOST_ASSERT(m_queue != 0);
475         BOOST_ASSERT(size <= buffer.size());
476         BOOST_ASSERT(buffer.get_context() == this->get_context());
477         BOOST_ASSERT(host_ptr != 0);
478 
479         event event_;
480 
481         cl_int ret = clEnqueueWriteBuffer(
482             m_queue,
483             buffer.get(),
484             CL_TRUE,
485             offset,
486             size,
487             host_ptr,
488             events.size(),
489             events.get_event_ptr(),
490             &event_.get()
491         );
492 
493         if(ret != CL_SUCCESS){
494             BOOST_THROW_EXCEPTION(opencl_error(ret));
495         }
496 
497         return event_;
498     }
499 
500     /// Enqueues a command to write data from host memory to \p buffer.
501     /// The copy is performed asynchronously.
502     ///
503     /// \see_opencl_ref{clEnqueueWriteBuffer}
504     ///
505     /// \see copy_async()
enqueue_write_buffer_async(const buffer & buffer,size_t offset,size_t size,const void * host_ptr,const wait_list & events=wait_list ())506     event enqueue_write_buffer_async(const buffer &buffer,
507                                      size_t offset,
508                                      size_t size,
509                                      const void *host_ptr,
510                                      const wait_list &events = wait_list())
511     {
512         BOOST_ASSERT(m_queue != 0);
513         BOOST_ASSERT(size <= buffer.size());
514         BOOST_ASSERT(buffer.get_context() == this->get_context());
515         BOOST_ASSERT(host_ptr != 0);
516 
517         event event_;
518 
519         cl_int ret = clEnqueueWriteBuffer(
520             m_queue,
521             buffer.get(),
522             CL_FALSE,
523             offset,
524             size,
525             host_ptr,
526             events.size(),
527             events.get_event_ptr(),
528             &event_.get()
529         );
530 
531         if(ret != CL_SUCCESS){
532             BOOST_THROW_EXCEPTION(opencl_error(ret));
533         }
534 
535         return event_;
536     }
537 
538     #if defined(BOOST_COMPUTE_CL_VERSION_1_1) || defined(BOOST_COMPUTE_DOXYGEN_INVOKED)
539     /// Enqueues a command to write a rectangular region from host memory
540     /// to \p buffer.
541     ///
542     /// \see_opencl_ref{clEnqueueWriteBufferRect}
543     ///
544     /// \opencl_version_warning{1,1}
enqueue_write_buffer_rect(const buffer & buffer,const size_t buffer_origin[3],const size_t host_origin[3],const size_t region[3],size_t buffer_row_pitch,size_t buffer_slice_pitch,size_t host_row_pitch,size_t host_slice_pitch,void * host_ptr,const wait_list & events=wait_list ())545     event enqueue_write_buffer_rect(const buffer &buffer,
546                                     const size_t buffer_origin[3],
547                                     const size_t host_origin[3],
548                                     const size_t region[3],
549                                     size_t buffer_row_pitch,
550                                     size_t buffer_slice_pitch,
551                                     size_t host_row_pitch,
552                                     size_t host_slice_pitch,
553                                     void *host_ptr,
554                                     const wait_list &events = wait_list())
555     {
556         BOOST_ASSERT(m_queue != 0);
557         BOOST_ASSERT(buffer.get_context() == this->get_context());
558         BOOST_ASSERT(host_ptr != 0);
559 
560         event event_;
561 
562         cl_int ret = clEnqueueWriteBufferRect(
563             m_queue,
564             buffer.get(),
565             CL_TRUE,
566             buffer_origin,
567             host_origin,
568             region,
569             buffer_row_pitch,
570             buffer_slice_pitch,
571             host_row_pitch,
572             host_slice_pitch,
573             host_ptr,
574             events.size(),
575             events.get_event_ptr(),
576             &event_.get()
577         );
578 
579         if(ret != CL_SUCCESS){
580             BOOST_THROW_EXCEPTION(opencl_error(ret));
581         }
582 
583         return event_;
584     }
585 
586     /// Enqueues a command to write a rectangular region from host memory
587     /// to \p buffer. The copy is performed asynchronously.
588     ///
589     /// \see_opencl_ref{clEnqueueWriteBufferRect}
590     ///
591     /// \opencl_version_warning{1,1}
enqueue_write_buffer_rect_async(const buffer & buffer,const size_t buffer_origin[3],const size_t host_origin[3],const size_t region[3],size_t buffer_row_pitch,size_t buffer_slice_pitch,size_t host_row_pitch,size_t host_slice_pitch,void * host_ptr,const wait_list & events=wait_list ())592     event enqueue_write_buffer_rect_async(const buffer &buffer,
593                                           const size_t buffer_origin[3],
594                                           const size_t host_origin[3],
595                                           const size_t region[3],
596                                           size_t buffer_row_pitch,
597                                           size_t buffer_slice_pitch,
598                                           size_t host_row_pitch,
599                                           size_t host_slice_pitch,
600                                           void *host_ptr,
601                                           const wait_list &events = wait_list())
602     {
603         BOOST_ASSERT(m_queue != 0);
604         BOOST_ASSERT(buffer.get_context() == this->get_context());
605         BOOST_ASSERT(host_ptr != 0);
606 
607         event event_;
608 
609         cl_int ret = clEnqueueWriteBufferRect(
610             m_queue,
611             buffer.get(),
612             CL_FALSE,
613             buffer_origin,
614             host_origin,
615             region,
616             buffer_row_pitch,
617             buffer_slice_pitch,
618             host_row_pitch,
619             host_slice_pitch,
620             host_ptr,
621             events.size(),
622             events.get_event_ptr(),
623             &event_.get()
624         );
625 
626         if(ret != CL_SUCCESS){
627             BOOST_THROW_EXCEPTION(opencl_error(ret));
628         }
629 
630         return event_;
631     }
632     #endif // BOOST_COMPUTE_CL_VERSION_1_1
633 
634     /// Enqueues a command to copy data from \p src_buffer to
635     /// \p dst_buffer.
636     ///
637     /// \see_opencl_ref{clEnqueueCopyBuffer}
638     ///
639     /// \see copy()
enqueue_copy_buffer(const buffer & src_buffer,const buffer & dst_buffer,size_t src_offset,size_t dst_offset,size_t size,const wait_list & events=wait_list ())640     event enqueue_copy_buffer(const buffer &src_buffer,
641                               const buffer &dst_buffer,
642                               size_t src_offset,
643                               size_t dst_offset,
644                               size_t size,
645                               const wait_list &events = wait_list())
646     {
647         BOOST_ASSERT(m_queue != 0);
648         BOOST_ASSERT(src_offset + size <= src_buffer.size());
649         BOOST_ASSERT(dst_offset + size <= dst_buffer.size());
650         BOOST_ASSERT(src_buffer.get_context() == this->get_context());
651         BOOST_ASSERT(dst_buffer.get_context() == this->get_context());
652 
653         event event_;
654 
655         cl_int ret = clEnqueueCopyBuffer(
656             m_queue,
657             src_buffer.get(),
658             dst_buffer.get(),
659             src_offset,
660             dst_offset,
661             size,
662             events.size(),
663             events.get_event_ptr(),
664             &event_.get()
665         );
666 
667         if(ret != CL_SUCCESS){
668             BOOST_THROW_EXCEPTION(opencl_error(ret));
669         }
670 
671         return event_;
672     }
673 
674     #if defined(BOOST_COMPUTE_CL_VERSION_1_1) || defined(BOOST_COMPUTE_DOXYGEN_INVOKED)
675     /// Enqueues a command to copy a rectangular region from
676     /// \p src_buffer to \p dst_buffer.
677     ///
678     /// \see_opencl_ref{clEnqueueCopyBufferRect}
679     ///
680     /// \opencl_version_warning{1,1}
enqueue_copy_buffer_rect(const buffer & src_buffer,const buffer & dst_buffer,const size_t src_origin[3],const size_t dst_origin[3],const size_t region[3],size_t buffer_row_pitch,size_t buffer_slice_pitch,size_t host_row_pitch,size_t host_slice_pitch,const wait_list & events=wait_list ())681     event enqueue_copy_buffer_rect(const buffer &src_buffer,
682                                    const buffer &dst_buffer,
683                                    const size_t src_origin[3],
684                                    const size_t dst_origin[3],
685                                    const size_t region[3],
686                                    size_t buffer_row_pitch,
687                                    size_t buffer_slice_pitch,
688                                    size_t host_row_pitch,
689                                    size_t host_slice_pitch,
690                                    const wait_list &events = wait_list())
691     {
692         BOOST_ASSERT(m_queue != 0);
693         BOOST_ASSERT(src_buffer.get_context() == this->get_context());
694         BOOST_ASSERT(dst_buffer.get_context() == this->get_context());
695 
696         event event_;
697 
698         cl_int ret = clEnqueueCopyBufferRect(
699             m_queue,
700             src_buffer.get(),
701             dst_buffer.get(),
702             src_origin,
703             dst_origin,
704             region,
705             buffer_row_pitch,
706             buffer_slice_pitch,
707             host_row_pitch,
708             host_slice_pitch,
709             events.size(),
710             events.get_event_ptr(),
711             &event_.get()
712         );
713 
714         if(ret != CL_SUCCESS){
715             BOOST_THROW_EXCEPTION(opencl_error(ret));
716         }
717 
718         return event_;
719     }
720     #endif // BOOST_COMPUTE_CL_VERSION_1_1
721 
722     #if defined(BOOST_COMPUTE_CL_VERSION_1_2) || defined(BOOST_COMPUTE_DOXYGEN_INVOKED)
723     /// Enqueues a command to fill \p buffer with \p pattern.
724     ///
725     /// \see_opencl_ref{clEnqueueFillBuffer}
726     ///
727     /// \opencl_version_warning{1,2}
728     ///
729     /// \see fill()
enqueue_fill_buffer(const buffer & buffer,const void * pattern,size_t pattern_size,size_t offset,size_t size,const wait_list & events=wait_list ())730     event enqueue_fill_buffer(const buffer &buffer,
731                               const void *pattern,
732                               size_t pattern_size,
733                               size_t offset,
734                               size_t size,
735                               const wait_list &events = wait_list())
736     {
737         BOOST_ASSERT(m_queue != 0);
738         BOOST_ASSERT(offset + size <= buffer.size());
739         BOOST_ASSERT(buffer.get_context() == this->get_context());
740 
741         event event_;
742 
743         cl_int ret = clEnqueueFillBuffer(
744             m_queue,
745             buffer.get(),
746             pattern,
747             pattern_size,
748             offset,
749             size,
750             events.size(),
751             events.get_event_ptr(),
752             &event_.get()
753         );
754 
755         if(ret != CL_SUCCESS){
756             BOOST_THROW_EXCEPTION(opencl_error(ret));
757         }
758 
759         return event_;
760     }
761     #endif // BOOST_COMPUTE_CL_VERSION_1_2
762 
763     /// Enqueues a command to map \p buffer into the host address space.
764     /// Event associated with map operation is returned through
765     /// \p map_buffer_event parameter.
766     ///
767     /// \see_opencl_ref{clEnqueueMapBuffer}
enqueue_map_buffer(const buffer & buffer,cl_map_flags flags,size_t offset,size_t size,event & map_buffer_event,const wait_list & events=wait_list ())768     void* enqueue_map_buffer(const buffer &buffer,
769                              cl_map_flags flags,
770                              size_t offset,
771                              size_t size,
772                              event &map_buffer_event,
773                              const wait_list &events = wait_list())
774     {
775         BOOST_ASSERT(m_queue != 0);
776         BOOST_ASSERT(offset + size <= buffer.size());
777         BOOST_ASSERT(buffer.get_context() == this->get_context());
778 
779         cl_int ret = 0;
780         void *pointer = clEnqueueMapBuffer(
781             m_queue,
782             buffer.get(),
783             CL_TRUE,
784             flags,
785             offset,
786             size,
787             events.size(),
788             events.get_event_ptr(),
789             &map_buffer_event.get(),
790             &ret
791         );
792 
793         if(ret != CL_SUCCESS){
794             BOOST_THROW_EXCEPTION(opencl_error(ret));
795         }
796 
797         return pointer;
798     }
799 
800     /// \overload
enqueue_map_buffer(const buffer & buffer,cl_map_flags flags,size_t offset,size_t size,const wait_list & events=wait_list ())801     void* enqueue_map_buffer(const buffer &buffer,
802                              cl_map_flags flags,
803                              size_t offset,
804                              size_t size,
805                              const wait_list &events = wait_list())
806     {
807         event event_;
808         return enqueue_map_buffer(buffer, flags, offset, size, event_, events);
809     }
810 
811     /// Enqueues a command to map \p buffer into the host address space.
812     /// Map operation is performed asynchronously. The pointer to the mapped
813     /// region cannot be used until the map operation has completed.
814     ///
815     /// Event associated with map operation is returned through
816     /// \p map_buffer_event parameter.
817     ///
818     /// \see_opencl_ref{clEnqueueMapBuffer}
enqueue_map_buffer_async(const buffer & buffer,cl_map_flags flags,size_t offset,size_t size,event & map_buffer_event,const wait_list & events=wait_list ())819     void* enqueue_map_buffer_async(const buffer &buffer,
820                                    cl_map_flags flags,
821                                    size_t offset,
822                                    size_t size,
823                                    event &map_buffer_event,
824                                    const wait_list &events = wait_list())
825     {
826         BOOST_ASSERT(m_queue != 0);
827         BOOST_ASSERT(offset + size <= buffer.size());
828         BOOST_ASSERT(buffer.get_context() == this->get_context());
829 
830         cl_int ret = 0;
831         void *pointer = clEnqueueMapBuffer(
832             m_queue,
833             buffer.get(),
834             CL_FALSE,
835             flags,
836             offset,
837             size,
838             events.size(),
839             events.get_event_ptr(),
840             &map_buffer_event.get(),
841             &ret
842         );
843 
844         if(ret != CL_SUCCESS){
845             BOOST_THROW_EXCEPTION(opencl_error(ret));
846         }
847 
848         return pointer;
849     }
850 
851     /// Enqueues a command to unmap \p buffer from the host memory space.
852     ///
853     /// \see_opencl_ref{clEnqueueUnmapMemObject}
enqueue_unmap_buffer(const buffer & buffer,void * mapped_ptr,const wait_list & events=wait_list ())854     event enqueue_unmap_buffer(const buffer &buffer,
855                                void *mapped_ptr,
856                                const wait_list &events = wait_list())
857     {
858         BOOST_ASSERT(buffer.get_context() == this->get_context());
859 
860         return enqueue_unmap_mem_object(buffer.get(), mapped_ptr, events);
861     }
862 
863     /// Enqueues a command to unmap \p mem from the host memory space.
864     ///
865     /// \see_opencl_ref{clEnqueueUnmapMemObject}
enqueue_unmap_mem_object(cl_mem mem,void * mapped_ptr,const wait_list & events=wait_list ())866     event enqueue_unmap_mem_object(cl_mem mem,
867                                    void *mapped_ptr,
868                                    const wait_list &events = wait_list())
869     {
870         BOOST_ASSERT(m_queue != 0);
871 
872         event event_;
873 
874         cl_int ret = clEnqueueUnmapMemObject(
875             m_queue,
876             mem,
877             mapped_ptr,
878             events.size(),
879             events.get_event_ptr(),
880             &event_.get()
881         );
882 
883         if(ret != CL_SUCCESS){
884             BOOST_THROW_EXCEPTION(opencl_error(ret));
885         }
886 
887         return event_;
888     }
889 
890     /// Enqueues a command to read data from \p image to host memory.
891     ///
892     /// \see_opencl_ref{clEnqueueReadImage}
enqueue_read_image(const image_object & image,const size_t * origin,const size_t * region,size_t row_pitch,size_t slice_pitch,void * host_ptr,const wait_list & events=wait_list ())893     event enqueue_read_image(const image_object& image,
894                              const size_t *origin,
895                              const size_t *region,
896                              size_t row_pitch,
897                              size_t slice_pitch,
898                              void *host_ptr,
899                              const wait_list &events = wait_list())
900     {
901         BOOST_ASSERT(m_queue != 0);
902 
903         event event_;
904 
905         cl_int ret = clEnqueueReadImage(
906             m_queue,
907             image.get(),
908             CL_TRUE,
909             origin,
910             region,
911             row_pitch,
912             slice_pitch,
913             host_ptr,
914             events.size(),
915             events.get_event_ptr(),
916             &event_.get()
917         );
918 
919         if(ret != CL_SUCCESS){
920             BOOST_THROW_EXCEPTION(opencl_error(ret));
921         }
922 
923         return event_;
924     }
925 
926     /// \overload
927     template<size_t N>
enqueue_read_image(const image_object & image,const extents<N> origin,const extents<N> region,void * host_ptr,size_t row_pitch=0,size_t slice_pitch=0,const wait_list & events=wait_list ())928     event enqueue_read_image(const image_object& image,
929                              const extents<N> origin,
930                              const extents<N> region,
931                              void *host_ptr,
932                              size_t row_pitch = 0,
933                              size_t slice_pitch = 0,
934                              const wait_list &events = wait_list())
935     {
936         BOOST_ASSERT(image.get_context() == this->get_context());
937 
938         size_t origin3[3] = { 0, 0, 0 };
939         size_t region3[3] = { 1, 1, 1 };
940 
941         std::copy(origin.data(), origin.data() + N, origin3);
942         std::copy(region.data(), region.data() + N, region3);
943 
944         return enqueue_read_image(
945             image, origin3, region3, row_pitch, slice_pitch, host_ptr, events
946         );
947     }
948 
949     /// Enqueues a command to write data from host memory to \p image.
950     ///
951     /// \see_opencl_ref{clEnqueueWriteImage}
enqueue_write_image(image_object & image,const size_t * origin,const size_t * region,const void * host_ptr,size_t input_row_pitch=0,size_t input_slice_pitch=0,const wait_list & events=wait_list ())952     event enqueue_write_image(image_object& image,
953                               const size_t *origin,
954                               const size_t *region,
955                               const void *host_ptr,
956                               size_t input_row_pitch = 0,
957                               size_t input_slice_pitch = 0,
958                               const wait_list &events = wait_list())
959     {
960         BOOST_ASSERT(m_queue != 0);
961 
962         event event_;
963 
964         cl_int ret = clEnqueueWriteImage(
965             m_queue,
966             image.get(),
967             CL_TRUE,
968             origin,
969             region,
970             input_row_pitch,
971             input_slice_pitch,
972             host_ptr,
973             events.size(),
974             events.get_event_ptr(),
975             &event_.get()
976         );
977 
978         if(ret != CL_SUCCESS){
979             BOOST_THROW_EXCEPTION(opencl_error(ret));
980         }
981 
982         return event_;
983     }
984 
985     /// \overload
986     template<size_t N>
enqueue_write_image(image_object & image,const extents<N> origin,const extents<N> region,const void * host_ptr,const size_t input_row_pitch=0,const size_t input_slice_pitch=0,const wait_list & events=wait_list ())987     event enqueue_write_image(image_object& image,
988                               const extents<N> origin,
989                               const extents<N> region,
990                               const void *host_ptr,
991                               const size_t input_row_pitch = 0,
992                               const size_t input_slice_pitch = 0,
993                               const wait_list &events = wait_list())
994     {
995         BOOST_ASSERT(image.get_context() == this->get_context());
996 
997         size_t origin3[3] = { 0, 0, 0 };
998         size_t region3[3] = { 1, 1, 1 };
999 
1000         std::copy(origin.data(), origin.data() + N, origin3);
1001         std::copy(region.data(), region.data() + N, region3);
1002 
1003         return enqueue_write_image(
1004             image, origin3, region3, host_ptr, input_row_pitch, input_slice_pitch, events
1005         );
1006     }
1007 
1008     /// Enqueues a command to map \p image into the host address space.
1009     ///
1010     /// Event associated with map operation is returned through
1011     /// \p map_image_event parameter.
1012     ///
1013     /// \see_opencl_ref{clEnqueueMapImage}
enqueue_map_image(const image_object & image,cl_map_flags flags,const size_t * origin,const size_t * region,size_t & output_row_pitch,size_t & output_slice_pitch,event & map_image_event,const wait_list & events=wait_list ())1014     void* enqueue_map_image(const image_object &image,
1015                             cl_map_flags flags,
1016                             const size_t *origin,
1017                             const size_t *region,
1018                             size_t &output_row_pitch,
1019                             size_t &output_slice_pitch,
1020                             event &map_image_event,
1021                             const wait_list &events = wait_list())
1022     {
1023         BOOST_ASSERT(m_queue != 0);
1024         BOOST_ASSERT(image.get_context() == this->get_context());
1025 
1026         cl_int ret = 0;
1027         void *pointer = clEnqueueMapImage(
1028             m_queue,
1029             image.get(),
1030             CL_TRUE,
1031             flags,
1032             origin,
1033             region,
1034             &output_row_pitch,
1035             &output_slice_pitch,
1036             events.size(),
1037             events.get_event_ptr(),
1038             &map_image_event.get(),
1039             &ret
1040         );
1041 
1042         if(ret != CL_SUCCESS){
1043             BOOST_THROW_EXCEPTION(opencl_error(ret));
1044         }
1045 
1046         return pointer;
1047     }
1048 
1049     /// \overload
enqueue_map_image(const image_object & image,cl_map_flags flags,const size_t * origin,const size_t * region,size_t & output_row_pitch,size_t & output_slice_pitch,const wait_list & events=wait_list ())1050     void* enqueue_map_image(const image_object &image,
1051                             cl_map_flags flags,
1052                             const size_t *origin,
1053                             const size_t *region,
1054                             size_t &output_row_pitch,
1055                             size_t &output_slice_pitch,
1056                             const wait_list &events = wait_list())
1057     {
1058         event event_;
1059         return enqueue_map_image(
1060             image, flags, origin, region,
1061             output_row_pitch, output_slice_pitch, event_, events
1062         );
1063     }
1064 
1065     /// \overload
1066     template<size_t N>
enqueue_map_image(image_object & image,cl_map_flags flags,const extents<N> origin,const extents<N> region,size_t & output_row_pitch,size_t & output_slice_pitch,event & map_image_event,const wait_list & events=wait_list ())1067     void* enqueue_map_image(image_object& image,
1068                             cl_map_flags flags,
1069                             const extents<N> origin,
1070                             const extents<N> region,
1071                             size_t &output_row_pitch,
1072                             size_t &output_slice_pitch,
1073                             event &map_image_event,
1074                             const wait_list &events = wait_list())
1075     {
1076         BOOST_ASSERT(image.get_context() == this->get_context());
1077 
1078         size_t origin3[3] = { 0, 0, 0 };
1079         size_t region3[3] = { 1, 1, 1 };
1080 
1081         std::copy(origin.data(), origin.data() + N, origin3);
1082         std::copy(region.data(), region.data() + N, region3);
1083 
1084         return enqueue_map_image(
1085             image, flags, origin3, region3,
1086             output_row_pitch, output_slice_pitch, map_image_event, events
1087         );
1088     }
1089 
1090     /// \overload
1091     template<size_t N>
enqueue_map_image(image_object & image,cl_map_flags flags,const extents<N> origin,const extents<N> region,size_t & output_row_pitch,size_t & output_slice_pitch,const wait_list & events=wait_list ())1092     void* enqueue_map_image(image_object& image,
1093                             cl_map_flags flags,
1094                             const extents<N> origin,
1095                             const extents<N> region,
1096                             size_t &output_row_pitch,
1097                             size_t &output_slice_pitch,
1098                             const wait_list &events = wait_list())
1099     {
1100         event event_;
1101         return enqueue_map_image(
1102             image, flags, origin, region,
1103             output_row_pitch, output_slice_pitch, event_, events
1104         );
1105     }
1106 
1107     /// Enqueues a command to map \p image into the host address space.
1108     /// Map operation is performed asynchronously. The pointer to the mapped
1109     /// region cannot be used until the map operation has completed.
1110     ///
1111     /// Event associated with map operation is returned through
1112     /// \p map_image_event parameter.
1113     ///
1114     /// \see_opencl_ref{clEnqueueMapImage}
enqueue_map_image_async(const image_object & image,cl_map_flags flags,const size_t * origin,const size_t * region,size_t & output_row_pitch,size_t & output_slice_pitch,event & map_image_event,const wait_list & events=wait_list ())1115     void* enqueue_map_image_async(const image_object &image,
1116                                   cl_map_flags flags,
1117                                   const size_t *origin,
1118                                   const size_t *region,
1119                                   size_t &output_row_pitch,
1120                                   size_t &output_slice_pitch,
1121                                   event &map_image_event,
1122                                   const wait_list &events = wait_list())
1123     {
1124         BOOST_ASSERT(m_queue != 0);
1125         BOOST_ASSERT(image.get_context() == this->get_context());
1126 
1127         cl_int ret = 0;
1128         void *pointer = clEnqueueMapImage(
1129             m_queue,
1130             image.get(),
1131             CL_FALSE,
1132             flags,
1133             origin,
1134             region,
1135             &output_row_pitch,
1136             &output_slice_pitch,
1137             events.size(),
1138             events.get_event_ptr(),
1139             &map_image_event.get(),
1140             &ret
1141         );
1142 
1143         if(ret != CL_SUCCESS){
1144             BOOST_THROW_EXCEPTION(opencl_error(ret));
1145         }
1146 
1147         return pointer;
1148     }
1149 
1150     /// \overload
1151     template<size_t N>
enqueue_map_image_async(image_object & image,cl_map_flags flags,const extents<N> origin,const extents<N> region,size_t & output_row_pitch,size_t & output_slice_pitch,event & map_image_event,const wait_list & events=wait_list ())1152     void* enqueue_map_image_async(image_object& image,
1153                                   cl_map_flags flags,
1154                                   const extents<N> origin,
1155                                   const extents<N> region,
1156                                   size_t &output_row_pitch,
1157                                   size_t &output_slice_pitch,
1158                                   event &map_image_event,
1159                                   const wait_list &events = wait_list())
1160     {
1161         BOOST_ASSERT(image.get_context() == this->get_context());
1162 
1163         size_t origin3[3] = { 0, 0, 0 };
1164         size_t region3[3] = { 1, 1, 1 };
1165 
1166         std::copy(origin.data(), origin.data() + N, origin3);
1167         std::copy(region.data(), region.data() + N, region3);
1168 
1169         return enqueue_map_image_async(
1170             image, flags, origin3, region3,
1171             output_row_pitch, output_slice_pitch, map_image_event, events
1172         );
1173     }
1174 
1175     /// Enqueues a command to unmap \p image from the host memory space.
1176     ///
1177     /// \see_opencl_ref{clEnqueueUnmapMemObject}
enqueue_unmap_image(const image_object & image,void * mapped_ptr,const wait_list & events=wait_list ())1178     event enqueue_unmap_image(const image_object &image,
1179                               void *mapped_ptr,
1180                               const wait_list &events = wait_list())
1181     {
1182         BOOST_ASSERT(image.get_context() == this->get_context());
1183 
1184         return enqueue_unmap_mem_object(image.get(), mapped_ptr, events);
1185     }
1186 
1187     /// Enqueues a command to copy data from \p src_image to \p dst_image.
1188     ///
1189     /// \see_opencl_ref{clEnqueueCopyImage}
enqueue_copy_image(const image_object & src_image,image_object & dst_image,const size_t * src_origin,const size_t * dst_origin,const size_t * region,const wait_list & events=wait_list ())1190     event enqueue_copy_image(const image_object& src_image,
1191                              image_object& dst_image,
1192                              const size_t *src_origin,
1193                              const size_t *dst_origin,
1194                              const size_t *region,
1195                              const wait_list &events = wait_list())
1196     {
1197         BOOST_ASSERT(m_queue != 0);
1198 
1199         event event_;
1200 
1201         cl_int ret = clEnqueueCopyImage(
1202             m_queue,
1203             src_image.get(),
1204             dst_image.get(),
1205             src_origin,
1206             dst_origin,
1207             region,
1208             events.size(),
1209             events.get_event_ptr(),
1210             &event_.get()
1211         );
1212 
1213         if(ret != CL_SUCCESS){
1214             BOOST_THROW_EXCEPTION(opencl_error(ret));
1215         }
1216 
1217         return event_;
1218     }
1219 
1220     /// \overload
1221     template<size_t N>
enqueue_copy_image(const image_object & src_image,image_object & dst_image,const extents<N> src_origin,const extents<N> dst_origin,const extents<N> region,const wait_list & events=wait_list ())1222     event enqueue_copy_image(const image_object& src_image,
1223                              image_object& dst_image,
1224                              const extents<N> src_origin,
1225                              const extents<N> dst_origin,
1226                              const extents<N> region,
1227                              const wait_list &events = wait_list())
1228     {
1229         BOOST_ASSERT(src_image.get_context() == this->get_context());
1230         BOOST_ASSERT(dst_image.get_context() == this->get_context());
1231         BOOST_ASSERT_MSG(src_image.format() == dst_image.format(),
1232                          "Source and destination image formats must match.");
1233 
1234         size_t src_origin3[3] = { 0, 0, 0 };
1235         size_t dst_origin3[3] = { 0, 0, 0 };
1236         size_t region3[3] = { 1, 1, 1 };
1237 
1238         std::copy(src_origin.data(), src_origin.data() + N, src_origin3);
1239         std::copy(dst_origin.data(), dst_origin.data() + N, dst_origin3);
1240         std::copy(region.data(), region.data() + N, region3);
1241 
1242         return enqueue_copy_image(
1243             src_image, dst_image, src_origin3, dst_origin3, region3, events
1244         );
1245     }
1246 
1247     /// Enqueues a command to copy data from \p src_image to \p dst_buffer.
1248     ///
1249     /// \see_opencl_ref{clEnqueueCopyImageToBuffer}
enqueue_copy_image_to_buffer(const image_object & src_image,memory_object & dst_buffer,const size_t * src_origin,const size_t * region,size_t dst_offset,const wait_list & events=wait_list ())1250     event enqueue_copy_image_to_buffer(const image_object& src_image,
1251                                        memory_object& dst_buffer,
1252                                        const size_t *src_origin,
1253                                        const size_t *region,
1254                                        size_t dst_offset,
1255                                        const wait_list &events = wait_list())
1256     {
1257         BOOST_ASSERT(m_queue != 0);
1258 
1259         event event_;
1260 
1261         cl_int ret = clEnqueueCopyImageToBuffer(
1262             m_queue,
1263             src_image.get(),
1264             dst_buffer.get(),
1265             src_origin,
1266             region,
1267             dst_offset,
1268             events.size(),
1269             events.get_event_ptr(),
1270             &event_.get()
1271         );
1272 
1273         if(ret != CL_SUCCESS){
1274             BOOST_THROW_EXCEPTION(opencl_error(ret));
1275         }
1276 
1277         return event_;
1278     }
1279 
1280     /// Enqueues a command to copy data from \p src_buffer to \p dst_image.
1281     ///
1282     /// \see_opencl_ref{clEnqueueCopyBufferToImage}
enqueue_copy_buffer_to_image(const memory_object & src_buffer,image_object & dst_image,size_t src_offset,const size_t * dst_origin,const size_t * region,const wait_list & events=wait_list ())1283     event enqueue_copy_buffer_to_image(const memory_object& src_buffer,
1284                                        image_object& dst_image,
1285                                        size_t src_offset,
1286                                        const size_t *dst_origin,
1287                                        const size_t *region,
1288                                        const wait_list &events = wait_list())
1289     {
1290         BOOST_ASSERT(m_queue != 0);
1291 
1292         event event_;
1293 
1294         cl_int ret = clEnqueueCopyBufferToImage(
1295             m_queue,
1296             src_buffer.get(),
1297             dst_image.get(),
1298             src_offset,
1299             dst_origin,
1300             region,
1301             events.size(),
1302             events.get_event_ptr(),
1303             &event_.get()
1304         );
1305 
1306         if(ret != CL_SUCCESS){
1307             BOOST_THROW_EXCEPTION(opencl_error(ret));
1308         }
1309 
1310         return event_;
1311     }
1312 
1313     #if defined(BOOST_COMPUTE_CL_VERSION_1_2) || defined(BOOST_COMPUTE_DOXYGEN_INVOKED)
1314     /// Enqueues a command to fill \p image with \p fill_color.
1315     ///
1316     /// \see_opencl_ref{clEnqueueFillImage}
1317     ///
1318     /// \opencl_version_warning{1,2}
enqueue_fill_image(image_object & image,const void * fill_color,const size_t * origin,const size_t * region,const wait_list & events=wait_list ())1319     event enqueue_fill_image(image_object& image,
1320                              const void *fill_color,
1321                              const size_t *origin,
1322                              const size_t *region,
1323                              const wait_list &events = wait_list())
1324     {
1325         BOOST_ASSERT(m_queue != 0);
1326 
1327         event event_;
1328 
1329         cl_int ret = clEnqueueFillImage(
1330             m_queue,
1331             image.get(),
1332             fill_color,
1333             origin,
1334             region,
1335             events.size(),
1336             events.get_event_ptr(),
1337             &event_.get()
1338         );
1339 
1340         if(ret != CL_SUCCESS){
1341             BOOST_THROW_EXCEPTION(opencl_error(ret));
1342         }
1343 
1344         return event_;
1345     }
1346 
1347     /// \overload
1348     template<size_t N>
enqueue_fill_image(image_object & image,const void * fill_color,const extents<N> origin,const extents<N> region,const wait_list & events=wait_list ())1349     event enqueue_fill_image(image_object& image,
1350                              const void *fill_color,
1351                              const extents<N> origin,
1352                              const extents<N> region,
1353                              const wait_list &events = wait_list())
1354     {
1355         BOOST_ASSERT(image.get_context() == this->get_context());
1356 
1357         size_t origin3[3] = { 0, 0, 0 };
1358         size_t region3[3] = { 1, 1, 1 };
1359 
1360         std::copy(origin.data(), origin.data() + N, origin3);
1361         std::copy(region.data(), region.data() + N, region3);
1362 
1363         return enqueue_fill_image(
1364             image, fill_color, origin3, region3, events
1365         );
1366     }
1367 
1368     /// Enqueues a command to migrate \p mem_objects.
1369     ///
1370     /// \see_opencl_ref{clEnqueueMigrateMemObjects}
1371     ///
1372     /// \opencl_version_warning{1,2}
enqueue_migrate_memory_objects(uint_ num_mem_objects,const cl_mem * mem_objects,cl_mem_migration_flags flags,const wait_list & events=wait_list ())1373     event enqueue_migrate_memory_objects(uint_ num_mem_objects,
1374                                          const cl_mem *mem_objects,
1375                                          cl_mem_migration_flags flags,
1376                                          const wait_list &events = wait_list())
1377     {
1378         BOOST_ASSERT(m_queue != 0);
1379 
1380         event event_;
1381 
1382         cl_int ret = clEnqueueMigrateMemObjects(
1383             m_queue,
1384             num_mem_objects,
1385             mem_objects,
1386             flags,
1387             events.size(),
1388             events.get_event_ptr(),
1389             &event_.get()
1390         );
1391 
1392         if(ret != CL_SUCCESS){
1393             BOOST_THROW_EXCEPTION(opencl_error(ret));
1394         }
1395 
1396         return event_;
1397     }
1398     #endif // BOOST_COMPUTE_CL_VERSION_1_2
1399 
1400     /// Enqueues a kernel for execution.
1401     ///
1402     /// \see_opencl_ref{clEnqueueNDRangeKernel}
enqueue_nd_range_kernel(const kernel & kernel,size_t work_dim,const size_t * global_work_offset,const size_t * global_work_size,const size_t * local_work_size,const wait_list & events=wait_list ())1403     event enqueue_nd_range_kernel(const kernel &kernel,
1404                                   size_t work_dim,
1405                                   const size_t *global_work_offset,
1406                                   const size_t *global_work_size,
1407                                   const size_t *local_work_size,
1408                                   const wait_list &events = wait_list())
1409     {
1410         BOOST_ASSERT(m_queue != 0);
1411         BOOST_ASSERT(kernel.get_context() == this->get_context());
1412 
1413         event event_;
1414 
1415         cl_int ret = clEnqueueNDRangeKernel(
1416             m_queue,
1417             kernel,
1418             static_cast<cl_uint>(work_dim),
1419             global_work_offset,
1420             global_work_size,
1421             local_work_size,
1422             events.size(),
1423             events.get_event_ptr(),
1424             &event_.get()
1425         );
1426 
1427         if(ret != CL_SUCCESS){
1428             BOOST_THROW_EXCEPTION(opencl_error(ret));
1429         }
1430 
1431         return event_;
1432     }
1433 
1434     /// \overload
1435     template<size_t N>
enqueue_nd_range_kernel(const kernel & kernel,const extents<N> & global_work_offset,const extents<N> & global_work_size,const extents<N> & local_work_size,const wait_list & events=wait_list ())1436     event enqueue_nd_range_kernel(const kernel &kernel,
1437                                   const extents<N> &global_work_offset,
1438                                   const extents<N> &global_work_size,
1439                                   const extents<N> &local_work_size,
1440                                   const wait_list &events = wait_list())
1441     {
1442         return enqueue_nd_range_kernel(
1443             kernel,
1444             N,
1445             global_work_offset.data(),
1446             global_work_size.data(),
1447             local_work_size.data(),
1448             events
1449         );
1450     }
1451 
1452     /// Convenience method which calls enqueue_nd_range_kernel() with a
1453     /// one-dimensional range.
enqueue_1d_range_kernel(const kernel & kernel,size_t global_work_offset,size_t global_work_size,size_t local_work_size,const wait_list & events=wait_list ())1454     event enqueue_1d_range_kernel(const kernel &kernel,
1455                                   size_t global_work_offset,
1456                                   size_t global_work_size,
1457                                   size_t local_work_size,
1458                                   const wait_list &events = wait_list())
1459     {
1460         return enqueue_nd_range_kernel(
1461             kernel,
1462             1,
1463             &global_work_offset,
1464             &global_work_size,
1465             local_work_size ? &local_work_size : 0,
1466             events
1467         );
1468     }
1469 
1470     /// Enqueues a kernel to execute using a single work-item.
1471     ///
1472     /// \see_opencl_ref{clEnqueueTask}
enqueue_task(const kernel & kernel,const wait_list & events=wait_list ())1473     event enqueue_task(const kernel &kernel, const wait_list &events = wait_list())
1474     {
1475         BOOST_ASSERT(m_queue != 0);
1476         BOOST_ASSERT(kernel.get_context() == this->get_context());
1477 
1478         event event_;
1479 
1480         // clEnqueueTask() was deprecated in OpenCL 2.0. In that case we
1481         // just forward to the equivalent clEnqueueNDRangeKernel() call.
1482         #ifdef BOOST_COMPUTE_CL_VERSION_2_0
1483         size_t one = 1;
1484         cl_int ret = clEnqueueNDRangeKernel(
1485             m_queue, kernel, 1, 0, &one, &one,
1486             events.size(), events.get_event_ptr(), &event_.get()
1487         );
1488         #else
1489         cl_int ret = clEnqueueTask(
1490             m_queue, kernel, events.size(), events.get_event_ptr(), &event_.get()
1491         );
1492         #endif
1493 
1494         if(ret != CL_SUCCESS){
1495             BOOST_THROW_EXCEPTION(opencl_error(ret));
1496         }
1497 
1498         return event_;
1499     }
1500 
1501     /// Enqueues a function to execute on the host.
enqueue_native_kernel(void (BOOST_COMPUTE_CL_CALLBACK * user_func)(void *),void * args,size_t cb_args,uint_ num_mem_objects,const cl_mem * mem_list,const void ** args_mem_loc,const wait_list & events=wait_list ())1502     event enqueue_native_kernel(void (BOOST_COMPUTE_CL_CALLBACK *user_func)(void *),
1503                                 void *args,
1504                                 size_t cb_args,
1505                                 uint_ num_mem_objects,
1506                                 const cl_mem *mem_list,
1507                                 const void **args_mem_loc,
1508                                 const wait_list &events = wait_list())
1509     {
1510         BOOST_ASSERT(m_queue != 0);
1511 
1512         event event_;
1513         cl_int ret = clEnqueueNativeKernel(
1514             m_queue,
1515             user_func,
1516             args,
1517             cb_args,
1518             num_mem_objects,
1519             mem_list,
1520             args_mem_loc,
1521             events.size(),
1522             events.get_event_ptr(),
1523             &event_.get()
1524         );
1525         if(ret != CL_SUCCESS){
1526             BOOST_THROW_EXCEPTION(opencl_error(ret));
1527         }
1528 
1529         return event_;
1530     }
1531 
1532     /// Convenience overload for enqueue_native_kernel() which enqueues a
1533     /// native kernel on the host with a nullary function.
enqueue_native_kernel(void (BOOST_COMPUTE_CL_CALLBACK * user_func)(void),const wait_list & events=wait_list ())1534     event enqueue_native_kernel(void (BOOST_COMPUTE_CL_CALLBACK *user_func)(void),
1535                                 const wait_list &events = wait_list())
1536     {
1537         return enqueue_native_kernel(
1538             detail::nullary_native_kernel_trampoline,
1539             reinterpret_cast<void *>(&user_func),
1540             sizeof(user_func),
1541             0,
1542             0,
1543             0,
1544             events
1545         );
1546     }
1547 
1548     /// Flushes the command queue.
1549     ///
1550     /// \see_opencl_ref{clFlush}
flush()1551     void flush()
1552     {
1553         BOOST_ASSERT(m_queue != 0);
1554 
1555         cl_int ret = clFlush(m_queue);
1556         if(ret != CL_SUCCESS){
1557             BOOST_THROW_EXCEPTION(opencl_error(ret));
1558         }
1559     }
1560 
1561     /// Blocks until all outstanding commands in the queue have finished.
1562     ///
1563     /// \see_opencl_ref{clFinish}
finish()1564     void finish()
1565     {
1566         BOOST_ASSERT(m_queue != 0);
1567 
1568         cl_int ret = clFinish(m_queue);
1569         if(ret != CL_SUCCESS){
1570             BOOST_THROW_EXCEPTION(opencl_error(ret));
1571         }
1572     }
1573 
1574     /// Enqueues a barrier in the queue.
enqueue_barrier()1575     void enqueue_barrier()
1576     {
1577         BOOST_ASSERT(m_queue != 0);
1578         cl_int ret = CL_SUCCESS;
1579 
1580         #ifdef BOOST_COMPUTE_CL_VERSION_1_2
1581         if(get_device().check_version(1, 2)){
1582             ret = clEnqueueBarrierWithWaitList(m_queue, 0, 0, 0);
1583         } else
1584         #endif // BOOST_COMPUTE_CL_VERSION_1_2
1585         {
1586             // Suppress deprecated declarations warning
1587             BOOST_COMPUTE_DISABLE_DEPRECATED_DECLARATIONS();
1588             ret = clEnqueueBarrier(m_queue);
1589             BOOST_COMPUTE_ENABLE_DEPRECATED_DECLARATIONS();
1590         }
1591 
1592         if(ret != CL_SUCCESS){
1593             BOOST_THROW_EXCEPTION(opencl_error(ret));
1594         }
1595     }
1596 
1597     #if defined(BOOST_COMPUTE_CL_VERSION_1_2) || defined(BOOST_COMPUTE_DOXYGEN_INVOKED)
1598     /// Enqueues a barrier in the queue after \p events.
1599     ///
1600     /// \opencl_version_warning{1,2}
enqueue_barrier(const wait_list & events)1601     event enqueue_barrier(const wait_list &events)
1602     {
1603         BOOST_ASSERT(m_queue != 0);
1604 
1605         event event_;
1606         cl_int ret = CL_SUCCESS;
1607 
1608         ret = clEnqueueBarrierWithWaitList(
1609             m_queue, events.size(), events.get_event_ptr(), &event_.get()
1610         );
1611 
1612         if(ret != CL_SUCCESS){
1613             BOOST_THROW_EXCEPTION(opencl_error(ret));
1614         }
1615 
1616         return event_;
1617     }
1618     #endif // BOOST_COMPUTE_CL_VERSION_1_2
1619 
1620     /// Enqueues a marker in the queue and returns an event that can be
1621     /// used to track its progress.
enqueue_marker()1622     event enqueue_marker()
1623     {
1624         event event_;
1625         cl_int ret = CL_SUCCESS;
1626 
1627         #ifdef BOOST_COMPUTE_CL_VERSION_1_2
1628         if(get_device().check_version(1, 2)){
1629             ret = clEnqueueMarkerWithWaitList(m_queue, 0, 0, &event_.get());
1630         } else
1631         #endif
1632         {
1633             // Suppress deprecated declarations warning
1634             BOOST_COMPUTE_DISABLE_DEPRECATED_DECLARATIONS();
1635             ret = clEnqueueMarker(m_queue, &event_.get());
1636             BOOST_COMPUTE_ENABLE_DEPRECATED_DECLARATIONS();
1637         }
1638 
1639         if(ret != CL_SUCCESS){
1640             BOOST_THROW_EXCEPTION(opencl_error(ret));
1641         }
1642 
1643         return event_;
1644     }
1645 
1646     #if defined(BOOST_COMPUTE_CL_VERSION_1_2) || defined(BOOST_COMPUTE_DOXYGEN_INVOKED)
1647     /// Enqueues a marker after \p events in the queue and returns an
1648     /// event that can be used to track its progress.
1649     ///
1650     /// \opencl_version_warning{1,2}
enqueue_marker(const wait_list & events)1651     event enqueue_marker(const wait_list &events)
1652     {
1653         event event_;
1654 
1655         cl_int ret = clEnqueueMarkerWithWaitList(
1656             m_queue, events.size(), events.get_event_ptr(), &event_.get()
1657         );
1658 
1659         if(ret != CL_SUCCESS){
1660             BOOST_THROW_EXCEPTION(opencl_error(ret));
1661         }
1662 
1663         return event_;
1664     }
1665     #endif // BOOST_COMPUTE_CL_VERSION_1_2
1666 
1667     #if defined(BOOST_COMPUTE_CL_VERSION_2_0) || defined(BOOST_COMPUTE_DOXYGEN_INVOKED)
1668     /// Enqueues a command to copy \p size bytes of data from \p src_ptr to
1669     /// \p dst_ptr.
1670     ///
1671     /// \opencl_version_warning{2,0}
1672     ///
1673     /// \see_opencl2_ref{clEnqueueSVMMemcpy}
enqueue_svm_memcpy(void * dst_ptr,const void * src_ptr,size_t size,const wait_list & events=wait_list ())1674     event enqueue_svm_memcpy(void *dst_ptr,
1675                              const void *src_ptr,
1676                              size_t size,
1677                              const wait_list &events = wait_list())
1678     {
1679         event event_;
1680 
1681         cl_int ret = clEnqueueSVMMemcpy(
1682             m_queue,
1683             CL_TRUE,
1684             dst_ptr,
1685             src_ptr,
1686             size,
1687             events.size(),
1688             events.get_event_ptr(),
1689             &event_.get()
1690         );
1691 
1692         if(ret != CL_SUCCESS){
1693             BOOST_THROW_EXCEPTION(opencl_error(ret));
1694         }
1695 
1696         return event_;
1697     }
1698 
1699     /// Enqueues a command to copy \p size bytes of data from \p src_ptr to
1700     /// \p dst_ptr. The operation is performed asynchronously.
1701     ///
1702     /// \opencl_version_warning{2,0}
1703     ///
1704     /// \see_opencl2_ref{clEnqueueSVMMemcpy}
enqueue_svm_memcpy_async(void * dst_ptr,const void * src_ptr,size_t size,const wait_list & events=wait_list ())1705     event enqueue_svm_memcpy_async(void *dst_ptr,
1706                                    const void *src_ptr,
1707                                    size_t size,
1708                                    const wait_list &events = wait_list())
1709     {
1710         event event_;
1711 
1712         cl_int ret = clEnqueueSVMMemcpy(
1713             m_queue,
1714             CL_FALSE,
1715             dst_ptr,
1716             src_ptr,
1717             size,
1718             events.size(),
1719             events.get_event_ptr(),
1720             &event_.get()
1721         );
1722 
1723         if(ret != CL_SUCCESS){
1724             BOOST_THROW_EXCEPTION(opencl_error(ret));
1725         }
1726 
1727         return event_;
1728     }
1729 
1730     /// Enqueues a command to fill \p size bytes of data at \p svm_ptr with
1731     /// \p pattern.
1732     ///
1733     /// \opencl_version_warning{2,0}
1734     ///
1735     /// \see_opencl2_ref{clEnqueueSVMMemFill}
enqueue_svm_fill(void * svm_ptr,const void * pattern,size_t pattern_size,size_t size,const wait_list & events=wait_list ())1736     event enqueue_svm_fill(void *svm_ptr,
1737                            const void *pattern,
1738                            size_t pattern_size,
1739                            size_t size,
1740                            const wait_list &events = wait_list())
1741 
1742     {
1743         event event_;
1744 
1745         cl_int ret = clEnqueueSVMMemFill(
1746             m_queue,
1747             svm_ptr,
1748             pattern,
1749             pattern_size,
1750             size,
1751             events.size(),
1752             events.get_event_ptr(),
1753             &event_.get()
1754         );
1755 
1756         if(ret != CL_SUCCESS){
1757             BOOST_THROW_EXCEPTION(opencl_error(ret));
1758         }
1759 
1760         return event_;
1761     }
1762 
1763     /// Enqueues a command to free \p svm_ptr.
1764     ///
1765     /// \opencl_version_warning{2,0}
1766     ///
1767     /// \see_opencl2_ref{clEnqueueSVMFree}
1768     ///
1769     /// \see svm_free()
enqueue_svm_free(void * svm_ptr,const wait_list & events=wait_list ())1770     event enqueue_svm_free(void *svm_ptr,
1771                            const wait_list &events = wait_list())
1772     {
1773         event event_;
1774 
1775         cl_int ret = clEnqueueSVMFree(
1776             m_queue,
1777             1,
1778             &svm_ptr,
1779             0,
1780             0,
1781             events.size(),
1782             events.get_event_ptr(),
1783             &event_.get()
1784         );
1785 
1786         if(ret != CL_SUCCESS){
1787             BOOST_THROW_EXCEPTION(opencl_error(ret));
1788         }
1789 
1790         return event_;
1791     }
1792 
1793     /// Enqueues a command to map \p svm_ptr to the host memory space.
1794     ///
1795     /// \opencl_version_warning{2,0}
1796     ///
1797     /// \see_opencl2_ref{clEnqueueSVMMap}
enqueue_svm_map(void * svm_ptr,size_t size,cl_map_flags flags,const wait_list & events=wait_list ())1798     event enqueue_svm_map(void *svm_ptr,
1799                           size_t size,
1800                           cl_map_flags flags,
1801                           const wait_list &events = wait_list())
1802     {
1803         event event_;
1804 
1805         cl_int ret = clEnqueueSVMMap(
1806             m_queue,
1807             CL_TRUE,
1808             flags,
1809             svm_ptr,
1810             size,
1811             events.size(),
1812             events.get_event_ptr(),
1813             &event_.get()
1814         );
1815 
1816         if(ret != CL_SUCCESS){
1817             BOOST_THROW_EXCEPTION(opencl_error(ret));
1818         }
1819 
1820         return event_;
1821     }
1822 
1823     /// Enqueues a command to unmap \p svm_ptr from the host memory space.
1824     ///
1825     /// \opencl_version_warning{2,0}
1826     ///
1827     /// \see_opencl2_ref{clEnqueueSVMUnmap}
enqueue_svm_unmap(void * svm_ptr,const wait_list & events=wait_list ())1828     event enqueue_svm_unmap(void *svm_ptr,
1829                             const wait_list &events = wait_list())
1830     {
1831         event event_;
1832 
1833         cl_int ret = clEnqueueSVMUnmap(
1834             m_queue,
1835             svm_ptr,
1836             events.size(),
1837             events.get_event_ptr(),
1838             &event_.get()
1839         );
1840 
1841         if(ret != CL_SUCCESS){
1842             BOOST_THROW_EXCEPTION(opencl_error(ret));
1843         }
1844 
1845         return event_;
1846     }
1847     #endif // BOOST_COMPUTE_CL_VERSION_2_0
1848 
1849     #if defined(BOOST_COMPUTE_CL_VERSION_2_1) || defined(BOOST_COMPUTE_DOXYGEN_INVOKED)
1850     /// Enqueues a command to indicate which device a set of ranges of SVM allocations
1851     /// should be associated with. The pair \p svm_ptrs[i] and \p sizes[i] together define
1852     /// the starting address and number of bytes in a range to be migrated.
1853     ///
1854     /// If \p sizes is empty, then that means every allocation containing any \p svm_ptrs[i]
1855     /// is to be migrated. Also, if \p sizes[i] is zero, then the entire allocation containing
1856     /// \p svm_ptrs[i] is migrated.
1857     ///
1858     /// \opencl_version_warning{2,1}
1859     ///
1860     /// \see_opencl21_ref{clEnqueueSVMMigrateMem}
enqueue_svm_migrate_memory(const std::vector<const void * > & svm_ptrs,const std::vector<size_t> & sizes,const cl_mem_migration_flags flags=0,const wait_list & events=wait_list ())1861     event enqueue_svm_migrate_memory(const std::vector<const void*> &svm_ptrs,
1862                                      const std::vector<size_t> &sizes,
1863                                      const cl_mem_migration_flags flags = 0,
1864                                      const wait_list &events = wait_list())
1865     {
1866         BOOST_ASSERT(svm_ptrs.size() == sizes.size() || sizes.size() == 0);
1867         event event_;
1868 
1869         cl_int ret = clEnqueueSVMMigrateMem(
1870             m_queue,
1871             static_cast<cl_uint>(svm_ptrs.size()),
1872             const_cast<void const **>(&svm_ptrs[0]),
1873             sizes.size() > 0 ? &sizes[0] : NULL,
1874             flags,
1875             events.size(),
1876             events.get_event_ptr(),
1877             &event_.get()
1878         );
1879 
1880         if(ret != CL_SUCCESS){
1881             BOOST_THROW_EXCEPTION(opencl_error(ret));
1882         }
1883 
1884         return event_;
1885     }
1886 
1887     /// Enqueues a command to indicate which device a range of SVM allocation
1888     /// should be associated with. The pair \p svm_ptr and \p size together define
1889     /// the starting address and number of bytes in a range to be migrated.
1890     ///
1891     /// If \p size is 0, then the entire allocation containing \p svm_ptr is
1892     /// migrated. The default value for \p size is 0.
1893     ///
1894     /// \opencl_version_warning{2,1}
1895     ///
1896     /// \see_opencl21_ref{clEnqueueSVMMigrateMem}
enqueue_svm_migrate_memory(const void * svm_ptr,const size_t size=0,const cl_mem_migration_flags flags=0,const wait_list & events=wait_list ())1897     event enqueue_svm_migrate_memory(const void* svm_ptr,
1898                                      const size_t size = 0,
1899                                      const cl_mem_migration_flags flags = 0,
1900                                      const wait_list &events = wait_list())
1901     {
1902         event event_;
1903 
1904         cl_int ret = clEnqueueSVMMigrateMem(
1905             m_queue,
1906             cl_uint(1),
1907             &svm_ptr,
1908             &size,
1909             flags,
1910             events.size(),
1911             events.get_event_ptr(),
1912             &event_.get()
1913         );
1914 
1915         if(ret != CL_SUCCESS){
1916             BOOST_THROW_EXCEPTION(opencl_error(ret));
1917         }
1918 
1919         return event_;
1920     }
1921     #endif // BOOST_COMPUTE_CL_VERSION_2_1
1922 
1923     /// Returns \c true if the command queue is the same at \p other.
operator ==(const command_queue & other) const1924     bool operator==(const command_queue &other) const
1925     {
1926         return m_queue == other.m_queue;
1927     }
1928 
1929     /// Returns \c true if the command queue is different from \p other.
operator !=(const command_queue & other) const1930     bool operator!=(const command_queue &other) const
1931     {
1932         return m_queue != other.m_queue;
1933     }
1934 
1935     /// \internal_
operator cl_command_queue() const1936     operator cl_command_queue() const
1937     {
1938         return m_queue;
1939     }
1940 
1941     /// \internal_
check_device_version(int major,int minor) const1942     bool check_device_version(int major, int minor) const
1943     {
1944         return get_device().check_version(major, minor);
1945     }
1946 
1947 private:
1948     cl_command_queue m_queue;
1949 };
1950 
clone(command_queue & queue) const1951 inline buffer buffer::clone(command_queue &queue) const
1952 {
1953     buffer copy(get_context(), size(), get_memory_flags());
1954     queue.enqueue_copy_buffer(*this, copy, 0, 0, size());
1955     return copy;
1956 }
1957 
clone(command_queue & queue) const1958 inline image1d image1d::clone(command_queue &queue) const
1959 {
1960     image1d copy(
1961         get_context(), width(), format(), get_memory_flags()
1962     );
1963 
1964     queue.enqueue_copy_image(*this, copy, origin(), copy.origin(), size());
1965 
1966     return copy;
1967 }
1968 
clone(command_queue & queue) const1969 inline image2d image2d::clone(command_queue &queue) const
1970 {
1971     image2d copy(
1972         get_context(), width(), height(), format(), get_memory_flags()
1973     );
1974 
1975     queue.enqueue_copy_image(*this, copy, origin(), copy.origin(), size());
1976 
1977     return copy;
1978 }
1979 
clone(command_queue & queue) const1980 inline image3d image3d::clone(command_queue &queue) const
1981 {
1982     image3d copy(
1983         get_context(), width(), height(), depth(), format(), get_memory_flags()
1984     );
1985 
1986     queue.enqueue_copy_image(*this, copy, origin(), copy.origin(), size());
1987 
1988     return copy;
1989 }
1990 
1991 /// \internal_ define get_info() specializations for command_queue
1992 BOOST_COMPUTE_DETAIL_DEFINE_GET_INFO_SPECIALIZATIONS(command_queue,
1993     ((cl_context, CL_QUEUE_CONTEXT))
1994     ((cl_device_id, CL_QUEUE_DEVICE))
1995     ((uint_, CL_QUEUE_REFERENCE_COUNT))
1996     ((cl_command_queue_properties, CL_QUEUE_PROPERTIES))
1997 )
1998 
1999 #ifdef BOOST_COMPUTE_CL_VERSION_2_1
2000 BOOST_COMPUTE_DETAIL_DEFINE_GET_INFO_SPECIALIZATIONS(command_queue,
2001     ((cl_command_queue, CL_QUEUE_DEVICE_DEFAULT))
2002 )
2003 #endif // BOOST_COMPUTE_CL_VERSION_2_1
2004 
2005 } // end compute namespace
2006 } // end boost namespace
2007 
2008 #endif // BOOST_COMPUTE_COMMAND_QUEUE_HPP
2009