1 //---------------------------------------------------------------------------//
2 // Copyright (c) 2013-2014 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_CONTAINER_MAPPED_VIEW_HPP
12 #define BOOST_COMPUTE_CONTAINER_MAPPED_VIEW_HPP
13 
14 #include <cstddef>
15 #include <exception>
16 
17 #include <boost/config.hpp>
18 #include <boost/throw_exception.hpp>
19 
20 #include <boost/compute/buffer.hpp>
21 #include <boost/compute/system.hpp>
22 #include <boost/compute/context.hpp>
23 #include <boost/compute/command_queue.hpp>
24 #include <boost/compute/iterator/buffer_iterator.hpp>
25 
26 namespace boost {
27 namespace compute {
28 
29 /// \class mapped_view
30 /// \brief A mapped view of host memory.
31 ///
32 /// The mapped_view class simplifies mapping host-memory to a compute
33 /// device. This allows for host-allocated memory to be used with the
34 /// Boost.Compute algorithms.
35 ///
36 /// The following example shows how to map a simple C-array containing
37 /// data on the host to the device and run the reduce() algorithm to
38 /// calculate the sum:
39 ///
40 /// \snippet test/test_mapped_view.cpp reduce
41 ///
42 /// \see buffer
43 template<class T>
44 class mapped_view
45 {
46 public:
47     typedef T value_type;
48     typedef size_t size_type;
49     typedef ptrdiff_t difference_type;
50     typedef buffer_iterator<T> iterator;
51     typedef buffer_iterator<T> const_iterator;
52 
53     /// Creates a null mapped_view object.
mapped_view()54     mapped_view()
55     {
56         m_mapped_ptr = 0;
57     }
58 
59     /// Creates a mapped_view for \p host_ptr with \p n elements. After
60     /// constructing a mapped_view the data is available for use by a
61     /// compute device. Use the \p unmap() method to make the updated data
62     /// available to the host.
mapped_view(T * host_ptr,size_type n,const context & context=system::default_context ())63     mapped_view(T *host_ptr,
64                 size_type n,
65                 const context &context = system::default_context())
66         : m_buffer(_make_mapped_buffer(host_ptr, n, context))
67     {
68         m_mapped_ptr = 0;
69     }
70 
71     /// Creates a read-only mapped_view for \p host_ptr with \p n elements.
72     /// After constructing a mapped_view the data is available for use by a
73     /// compute device. Use the \p unmap() method to make the updated data
74     /// available to the host.
mapped_view(const T * host_ptr,size_type n,const context & context=system::default_context ())75     mapped_view(const T *host_ptr,
76                 size_type n,
77                 const context &context = system::default_context())
78         : m_buffer(_make_mapped_buffer(host_ptr, n, context))
79     {
80         m_mapped_ptr = 0;
81     }
82 
83     /// Creates a copy of \p other.
mapped_view(const mapped_view<T> & other)84     mapped_view(const mapped_view<T> &other)
85         : m_buffer(other.m_buffer)
86     {
87         m_mapped_ptr = 0;
88     }
89 
90     /// Copies the mapped buffer from \p other.
operator =(const mapped_view<T> & other)91     mapped_view<T>& operator=(const mapped_view<T> &other)
92     {
93         if(this != &other){
94             m_buffer = other.m_buffer;
95             m_mapped_ptr = 0;
96         }
97 
98         return *this;
99     }
100 
101     /// Destroys the mapped_view object.
~mapped_view()102     ~mapped_view()
103     {
104     }
105 
106     /// Returns an iterator to the first element in the mapped_view.
begin()107     iterator begin()
108     {
109         return ::boost::compute::make_buffer_iterator<T>(m_buffer, 0);
110     }
111 
112     /// Returns a const_iterator to the first element in the mapped_view.
begin() const113     const_iterator begin() const
114     {
115         return ::boost::compute::make_buffer_iterator<T>(m_buffer, 0);
116     }
117 
118     /// Returns a const_iterator to the first element in the mapped_view.
cbegin() const119     const_iterator cbegin() const
120     {
121         return begin();
122     }
123 
124     /// Returns an iterator to one past the last element in the mapped_view.
end()125     iterator end()
126     {
127         return ::boost::compute::make_buffer_iterator<T>(m_buffer, size());
128     }
129 
130     /// Returns a const_iterator to one past the last element in the mapped_view.
end() const131     const_iterator end() const
132     {
133         return ::boost::compute::make_buffer_iterator<T>(m_buffer, size());
134     }
135 
136     /// Returns a const_iterator to one past the last element in the mapped_view.
cend() const137     const_iterator cend() const
138     {
139         return end();
140     }
141 
142     /// Returns the number of elements in the mapped_view.
size() const143     size_type size() const
144     {
145         return m_buffer.size() / sizeof(T);
146     }
147 
148     /// Returns the host data pointer.
get_host_ptr()149     T* get_host_ptr()
150     {
151         return static_cast<T *>(m_buffer.get_info<void *>(CL_MEM_HOST_PTR));
152     }
153 
154     /// Returns the host data pointer.
get_host_ptr() const155     const T* get_host_ptr() const
156     {
157         return static_cast<T *>(m_buffer.get_info<void *>(CL_MEM_HOST_PTR));
158     }
159 
160     /// Resizes the mapped_view to \p size elements.
resize(size_type size)161     void resize(size_type size)
162     {
163         T *old_ptr = get_host_ptr();
164 
165         m_buffer = _make_mapped_buffer(old_ptr, size, m_buffer.get_context());
166     }
167 
168     /// Returns \c true if the mapped_view is empty.
empty() const169     bool empty() const
170     {
171         return size() == 0;
172     }
173 
174     /// Returns the mapped buffer.
get_buffer() const175     const buffer& get_buffer() const
176     {
177         return m_buffer;
178     }
179 
180     /// Maps the buffer into the host address space.
181     ///
182     /// \see_opencl_ref{clEnqueueMapBuffer}
map(cl_map_flags flags,command_queue & queue)183     void map(cl_map_flags flags, command_queue &queue)
184     {
185         BOOST_ASSERT(m_mapped_ptr == 0);
186 
187         m_mapped_ptr = queue.enqueue_map_buffer(
188             m_buffer, flags, 0, m_buffer.size()
189         );
190     }
191 
192     /// Maps the buffer into the host address space for reading and writing.
193     ///
194     /// Equivalent to:
195     /// \code
196     /// map(CL_MAP_READ | CL_MAP_WRITE, queue);
197     /// \endcode
map(command_queue & queue)198     void map(command_queue &queue)
199     {
200         map(CL_MAP_READ | CL_MAP_WRITE, queue);
201     }
202 
203     /// Unmaps the buffer from the host address space.
204     ///
205     /// \see_opencl_ref{clEnqueueUnmapMemObject}
unmap(command_queue & queue)206     void unmap(command_queue &queue)
207     {
208         BOOST_ASSERT(m_mapped_ptr != 0);
209 
210         queue.enqueue_unmap_buffer(m_buffer, m_mapped_ptr);
211 
212         m_mapped_ptr = 0;
213     }
214 
215 private:
216     /// \internal_
_make_mapped_buffer(T * host_ptr,size_t n,const context & context)217     static buffer _make_mapped_buffer(T *host_ptr,
218                                       size_t n,
219                                       const context &context)
220     {
221         return buffer(
222             context,
223             n * sizeof(T),
224             buffer::read_write | buffer::use_host_ptr,
225             host_ptr
226         );
227     }
228 
229     /// \internal_
_make_mapped_buffer(const T * host_ptr,size_t n,const context & context)230     static buffer _make_mapped_buffer(const T *host_ptr,
231                                       size_t n,
232                                       const context &context)
233     {
234         return buffer(
235             context,
236             n * sizeof(T),
237             buffer::read_only | buffer::use_host_ptr,
238             const_cast<void *>(static_cast<const void *>(host_ptr))
239         );
240     }
241 
242 private:
243     buffer m_buffer;
244     void *m_mapped_ptr;
245 };
246 
247 } // end compute namespace
248 } // end boost namespace
249 
250 #endif // BOOST_COMPUTE_CONTAINER_MAPPED_VIEW_HPP
251