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_BUFFER_HPP
12 #define BOOST_COMPUTE_BUFFER_HPP
13 
14 #include <boost/compute/config.hpp>
15 #include <boost/compute/context.hpp>
16 #include <boost/compute/exception.hpp>
17 #include <boost/compute/memory_object.hpp>
18 #include <boost/compute/detail/get_object_info.hpp>
19 
20 namespace boost {
21 namespace compute {
22 
23 // forward declarations
24 class command_queue;
25 
26 /// \class buffer
27 /// \brief A memory buffer on a compute device.
28 ///
29 /// The buffer class represents a memory buffer on a compute device.
30 ///
31 /// Buffers are allocated within a compute context. For example, to allocate
32 /// a memory buffer for 32 float's:
33 ///
34 /// \snippet test/test_buffer.cpp constructor
35 ///
36 /// Once created, data can be copied to and from the buffer using the
37 /// \c enqueue_*_buffer() methods in the command_queue class. For example, to
38 /// copy a set of \c int values from the host to the device:
39 /// \code
40 /// int data[] = { 1, 2, 3, 4 };
41 ///
42 /// queue.enqueue_write_buffer(buf, 0, 4 * sizeof(int), data);
43 /// \endcode
44 ///
45 /// Also see the copy() algorithm for a higher-level interface to copying data
46 /// between the host and the device. For a higher-level, dynamically-resizable,
47 /// type-safe container for data on a compute device, use the vector<T> class.
48 ///
49 /// Buffer objects have reference semantics. Creating a copy of a buffer
50 /// object simply creates another reference to the underlying OpenCL memory
51 /// object. To create an actual copy use the buffer::clone() method.
52 ///
53 /// \see context, command_queue
54 class buffer : public memory_object
55 {
56 public:
57     /// Creates a null buffer object.
buffer()58     buffer()
59         : memory_object()
60     {
61     }
62 
63     /// Creates a buffer object for \p mem. If \p retain is \c true, the
64     /// reference count for \p mem will be incremented.
buffer(cl_mem mem,bool retain=true)65     explicit buffer(cl_mem mem, bool retain = true)
66         : memory_object(mem, retain)
67     {
68     }
69 
70     /// Create a new memory buffer in of \p size with \p flags in
71     /// \p context.
72     ///
73     /// \see_opencl_ref{clCreateBuffer}
buffer(const context & context,size_t size,cl_mem_flags flags=read_write,void * host_ptr=0)74     buffer(const context &context,
75            size_t size,
76            cl_mem_flags flags = read_write,
77            void *host_ptr = 0)
78     {
79         cl_int error = 0;
80         m_mem = clCreateBuffer(context,
81                                flags,
82                                (std::max)(size, size_t(1)),
83                                host_ptr,
84                                &error);
85         if(!m_mem){
86             BOOST_THROW_EXCEPTION(opencl_error(error));
87         }
88     }
89 
90     /// Creates a new buffer object as a copy of \p other.
buffer(const buffer & other)91     buffer(const buffer &other)
92         : memory_object(other)
93     {
94     }
95 
96     /// Copies the buffer object from \p other to \c *this.
operator =(const buffer & other)97     buffer& operator=(const buffer &other)
98     {
99         if(this != &other){
100             memory_object::operator=(other);
101         }
102 
103         return *this;
104     }
105 
106     #ifndef BOOST_COMPUTE_NO_RVALUE_REFERENCES
107     /// Move-constructs a new buffer object from \p other.
buffer(buffer && other)108     buffer(buffer&& other) BOOST_NOEXCEPT
109         : memory_object(std::move(other))
110     {
111     }
112 
113     /// Move-assigns the buffer from \p other to \c *this.
operator =(buffer && other)114     buffer& operator=(buffer&& other) BOOST_NOEXCEPT
115     {
116         memory_object::operator=(std::move(other));
117 
118         return *this;
119     }
120     #endif // BOOST_COMPUTE_NO_RVALUE_REFERENCES
121 
122     /// Destroys the buffer object.
~buffer()123     ~buffer()
124     {
125     }
126 
127     /// Returns the size of the buffer in bytes.
size() const128     size_t size() const
129     {
130         return get_memory_size();
131     }
132 
133     /// \internal_
max_size() const134     size_t max_size() const
135     {
136         return get_context().get_device().max_memory_alloc_size();
137     }
138 
139     /// Returns information about the buffer.
140     ///
141     /// \see_opencl_ref{clGetMemObjectInfo}
142     template<class T>
get_info(cl_mem_info info) const143     T get_info(cl_mem_info info) const
144     {
145         return get_memory_info<T>(info);
146     }
147 
148     /// \overload
149     template<int Enum>
150     typename detail::get_object_info_type<buffer, Enum>::type
151     get_info() const;
152 
153     /// Creates a new buffer with a copy of the data in \c *this. Uses
154     /// \p queue to perform the copy.
155     buffer clone(command_queue &queue) const;
156 
157     #if defined(BOOST_COMPUTE_CL_VERSION_1_1) || defined(BOOST_COMPUTE_DOXYGEN_INVOKED)
158     /// Creates a new buffer out of this buffer.
159     /// The new buffer is a sub region of this buffer.
160     /// \p flags The mem_flags which should be used to create the new buffer
161     /// \p origin The start index in this buffer
162     /// \p size The size of the new sub buffer
163     ///
164     /// \see_opencl_ref{clCreateSubBuffer}
165     ///
166     /// \opencl_version_warning{1,1}
create_subbuffer(cl_mem_flags flags,size_t origin,size_t size)167     buffer create_subbuffer(cl_mem_flags flags, size_t origin,
168                             size_t size)
169     {
170         BOOST_ASSERT(origin + size <= this->size());
171         BOOST_ASSERT(origin % (get_context().
172                                get_device().
173                                get_info<CL_DEVICE_MEM_BASE_ADDR_ALIGN>() / 8) == 0);
174         cl_int error = 0;
175 
176         cl_buffer_region region = { origin, size };
177 
178         cl_mem mem = clCreateSubBuffer(m_mem,
179                                        flags,
180                                        CL_BUFFER_CREATE_TYPE_REGION,
181                                        &region,
182                                        &error);
183 
184         if(!mem){
185             BOOST_THROW_EXCEPTION(opencl_error(error));
186         }
187 
188         return buffer(mem, false);
189     }
190   #endif // BOOST_COMPUTE_CL_VERSION_1_1
191 };
192 
193 /// \internal_ define get_info() specializations for buffer
194 BOOST_COMPUTE_DETAIL_DEFINE_GET_INFO_SPECIALIZATIONS(buffer,
195     ((cl_mem_object_type, CL_MEM_TYPE))
196     ((cl_mem_flags, CL_MEM_FLAGS))
197     ((size_t, CL_MEM_SIZE))
198     ((void *, CL_MEM_HOST_PTR))
199     ((cl_uint, CL_MEM_MAP_COUNT))
200     ((cl_uint, CL_MEM_REFERENCE_COUNT))
201     ((cl_context, CL_MEM_CONTEXT))
202 )
203 
204 #ifdef BOOST_COMPUTE_CL_VERSION_1_1
205 BOOST_COMPUTE_DETAIL_DEFINE_GET_INFO_SPECIALIZATIONS(buffer,
206     ((cl_mem, CL_MEM_ASSOCIATED_MEMOBJECT))
207     ((size_t, CL_MEM_OFFSET))
208 )
209 #endif // BOOST_COMPUTE_CL_VERSION_1_1
210 
211 namespace detail {
212 
213 // set_kernel_arg specialization for buffer
214 template<>
215 struct set_kernel_arg<buffer>
216 {
operator ()boost::compute::detail::set_kernel_arg217     void operator()(kernel &kernel_, size_t index, const buffer &buffer_)
218     {
219         kernel_.set_arg(index, buffer_.get());
220     }
221 };
222 
223 } // end detail namespace
224 } // end compute namespace
225 } // end boost namespace
226 
227 #endif // BOOST_COMPUTE_BUFFER_HPP
228