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_MEMORY_OBJECT_HPP
12 #define BOOST_COMPUTE_MEMORY_OBJECT_HPP
13 
14 #include <boost/compute/config.hpp>
15 #include <boost/compute/context.hpp>
16 #include <boost/compute/kernel.hpp>
17 #include <boost/compute/detail/get_object_info.hpp>
18 #include <boost/compute/detail/assert_cl_success.hpp>
19 
20 namespace boost {
21 namespace compute {
22 
23 /// \class memory_object
24 /// \brief Base-class for memory objects.
25 ///
26 /// The memory_object class is the base-class for memory objects on
27 /// compute devices.
28 ///
29 /// \see buffer, vector
30 class memory_object
31 {
32 public:
33     /// Flags for the creation of memory objects.
34     enum mem_flags {
35         read_write = CL_MEM_READ_WRITE,
36         read_only = CL_MEM_READ_ONLY,
37         write_only = CL_MEM_WRITE_ONLY,
38         use_host_ptr = CL_MEM_USE_HOST_PTR,
39         alloc_host_ptr = CL_MEM_ALLOC_HOST_PTR,
40         copy_host_ptr = CL_MEM_COPY_HOST_PTR
41         #ifdef BOOST_COMPUTE_CL_VERSION_1_2
42         ,
43         host_write_only = CL_MEM_HOST_WRITE_ONLY,
44         host_read_only = CL_MEM_HOST_READ_ONLY,
45         host_no_access = CL_MEM_HOST_NO_ACCESS
46         #endif
47     };
48 
49     /// Symbolic names for the OpenCL address spaces.
50     enum address_space {
51         global_memory,
52         local_memory,
53         private_memory,
54         constant_memory
55     };
56 
57     /// Returns the underlying OpenCL memory object.
58     cl_mem& get() const
59     {
60         return const_cast<cl_mem &>(m_mem);
61     }
62 
63     /// Returns the size of the memory object in bytes.
64     size_t get_memory_size() const
65     {
66         return get_memory_info<size_t>(CL_MEM_SIZE);
67     }
68 
69     /// Returns the type for the memory object.
70     cl_mem_object_type get_memory_type() const
71     {
72         return get_memory_info<cl_mem_object_type>(CL_MEM_TYPE);
73     }
74 
75     /// Returns the flags for the memory object.
76     cl_mem_flags get_memory_flags() const
77     {
78         return get_memory_info<cl_mem_flags>(CL_MEM_FLAGS);
79     }
80 
81     /// Returns the context for the memory object.
82     context get_context() const
83     {
84         return context(get_memory_info<cl_context>(CL_MEM_CONTEXT));
85     }
86 
87     /// Returns the host pointer associated with the memory object.
88     void* get_host_ptr() const
89     {
90         return get_memory_info<void *>(CL_MEM_HOST_PTR);
91     }
92 
93     /// Returns the reference count for the memory object.
94     uint_ reference_count() const
95     {
96         return get_memory_info<uint_>(CL_MEM_REFERENCE_COUNT);
97     }
98 
99     /// Returns information about the memory object.
100     ///
101     /// \see_opencl_ref{clGetMemObjectInfo}
102     template<class T>
103     T get_memory_info(cl_mem_info info) const
104     {
105         return detail::get_object_info<T>(clGetMemObjectInfo, m_mem, info);
106     }
107 
108     #if defined(BOOST_COMPUTE_CL_VERSION_1_1) || defined(BOOST_COMPUTE_DOXYGEN_INVOKED)
109     /// Registers a function to be called when the memory object is deleted
110     /// and its resources freed.
111     ///
112     /// \see_opencl_ref{clSetMemObjectDestructorCallback}
113     ///
114     /// \opencl_version_warning{1,1}
115     void set_destructor_callback(void (BOOST_COMPUTE_CL_CALLBACK *callback)(
116                                      cl_mem memobj, void *user_data
117                                  ),
118                                  void *user_data = 0)
119     {
120         cl_int ret = clSetMemObjectDestructorCallback(m_mem, callback, user_data);
121         if(ret != CL_SUCCESS){
122             BOOST_THROW_EXCEPTION(opencl_error(ret));
123         }
124     }
125     /// Registers a function to be called when the memory object is deleted
126     /// and its resources freed.
127     ///
128     /// The function specified by \p callback must be invokable with zero
129     /// arguments (e.g. \c callback()).
130     ///
131     /// \opencl_version_warning{1,1}
132     template<class Function>
133     void set_destructor_callback(Function callback)
134     {
135         set_destructor_callback(
136             destructor_callback_invoker,
137             new boost::function<void()>(callback)
138         );
139     }
140     #endif // BOOST_COMPUTE_CL_VERSION_1_1
141 
142     /// Returns \c true if the memory object is the same as \p other.
143     bool operator==(const memory_object &other) const
144     {
145         return m_mem == other.m_mem;
146     }
147 
148     /// Returns \c true if the memory object is different from \p other.
149     bool operator!=(const memory_object &other) const
150     {
151         return m_mem != other.m_mem;
152     }
153 
154 private:
155     #ifdef BOOST_COMPUTE_CL_VERSION_1_1
156     /// \internal_
157     static void BOOST_COMPUTE_CL_CALLBACK
158     destructor_callback_invoker(cl_mem, void *user_data)
159     {
160         boost::function<void()> *callback =
161             static_cast<boost::function<void()> *>(user_data);
162 
163         (*callback)();
164 
165         delete callback;
166     }
167     #endif // BOOST_COMPUTE_CL_VERSION_1_1
168 
169 protected:
170     /// \internal_
171     memory_object()
172         : m_mem(0)
173     {
174     }
175 
176     /// \internal_
177     explicit memory_object(cl_mem mem, bool retain = true)
178         : m_mem(mem)
179     {
180         if(m_mem && retain){
181             clRetainMemObject(m_mem);
182         }
183     }
184 
185     /// \internal_
186     memory_object(const memory_object &other)
187         : m_mem(other.m_mem)
188     {
189         if(m_mem){
190             clRetainMemObject(m_mem);
191         }
192     }
193 
194     /// \internal_
195     memory_object& operator=(const memory_object &other)
196     {
197         if(this != &other){
198             if(m_mem){
199                 clReleaseMemObject(m_mem);
200             }
201 
202             m_mem = other.m_mem;
203 
204             if(m_mem){
205                 clRetainMemObject(m_mem);
206             }
207         }
208 
209         return *this;
210     }
211 
212     #ifndef BOOST_COMPUTE_NO_RVALUE_REFERENCES
213     /// \internal_
214     memory_object(memory_object&& other) BOOST_NOEXCEPT
215         : m_mem(other.m_mem)
216     {
217         other.m_mem = 0;
218     }
219 
220     /// \internal_
221     memory_object& operator=(memory_object&& other) BOOST_NOEXCEPT
222     {
223         if(m_mem){
224             clReleaseMemObject(m_mem);
225         }
226 
227         m_mem = other.m_mem;
228         other.m_mem = 0;
229 
230         return *this;
231     }
232     #endif // BOOST_COMPUTE_NO_RVALUE_REFERENCES
233 
234     /// \internal_
235     ~memory_object()
236     {
237         if(m_mem){
238             BOOST_COMPUTE_ASSERT_CL_SUCCESS(
239                 clReleaseMemObject(m_mem)
240             );
241         }
242     }
243 
244 protected:
245     cl_mem m_mem;
246 };
247 
248 namespace detail {
249 
250 // set_kernel_arg specialization for memory_object
251 template<>
252 struct set_kernel_arg<memory_object>
253 {
254     void operator()(kernel &kernel_, size_t index, const memory_object &mem)
255     {
256         kernel_.set_arg(index, mem.get());
257     }
258 };
259 
260 } // end detail namespace
261 } // end compute namespace
262 } // end boost namespace
263 
264 #endif // BOOST_COMPUTE_MEMORY_OBJECT_HPP
265