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_ALGORITHM_DETAIL_COPY_TO_HOST_HPP
12 #define BOOST_COMPUTE_ALGORITHM_DETAIL_COPY_TO_HOST_HPP
13 
14 #include <iterator>
15 
16 #include <boost/utility/addressof.hpp>
17 
18 #include <boost/compute/command_queue.hpp>
19 #include <boost/compute/async/future.hpp>
20 #include <boost/compute/iterator/buffer_iterator.hpp>
21 #include <boost/compute/memory/svm_ptr.hpp>
22 #include <boost/compute/detail/iterator_plus_distance.hpp>
23 
24 namespace boost {
25 namespace compute {
26 namespace detail {
27 
28 template<class DeviceIterator, class HostIterator>
copy_to_host(DeviceIterator first,DeviceIterator last,HostIterator result,command_queue & queue,const wait_list & events)29 inline HostIterator copy_to_host(DeviceIterator first,
30                                  DeviceIterator last,
31                                  HostIterator result,
32                                  command_queue &queue,
33                                  const wait_list &events)
34 {
35     typedef typename
36         std::iterator_traits<DeviceIterator>::value_type
37         value_type;
38 
39     size_t count = iterator_range_size(first, last);
40     if(count == 0){
41         return result;
42     }
43 
44     const buffer &buffer = first.get_buffer();
45     size_t offset = first.get_index();
46 
47     queue.enqueue_read_buffer(buffer,
48                               offset * sizeof(value_type),
49                               count * sizeof(value_type),
50                               ::boost::addressof(*result),
51                               events);
52 
53     return iterator_plus_distance(result, count);
54 }
55 
56 template<class DeviceIterator, class HostIterator>
copy_to_host_map(DeviceIterator first,DeviceIterator last,HostIterator result,command_queue & queue,const wait_list & events)57 inline HostIterator copy_to_host_map(DeviceIterator first,
58                                      DeviceIterator last,
59                                      HostIterator result,
60                                      command_queue &queue,
61                                      const wait_list &events)
62 {
63     typedef typename
64         std::iterator_traits<DeviceIterator>::value_type
65         value_type;
66     typedef typename
67         std::iterator_traits<DeviceIterator>::difference_type
68         difference_type;
69 
70     size_t count = iterator_range_size(first, last);
71     if(count == 0){
72         return result;
73     }
74 
75     size_t offset = first.get_index();
76 
77     // map [first; last) buffer to host
78     value_type *pointer = static_cast<value_type*>(
79         queue.enqueue_map_buffer(
80             first.get_buffer(),
81             CL_MAP_READ,
82             offset * sizeof(value_type),
83             count * sizeof(value_type),
84             events
85         )
86     );
87 
88     // copy [first; last) to result buffer
89     std::copy(
90         pointer,
91         pointer + static_cast<difference_type>(count),
92         result
93     );
94 
95     // unmap [first; last)
96     boost::compute::event unmap_event = queue.enqueue_unmap_buffer(
97         first.get_buffer(),
98         static_cast<void*>(pointer)
99     );
100     unmap_event.wait();
101 
102     return iterator_plus_distance(result, count);
103 }
104 
105 template<class DeviceIterator, class HostIterator>
copy_to_host_async(DeviceIterator first,DeviceIterator last,HostIterator result,command_queue & queue,const wait_list & events)106 inline future<HostIterator> copy_to_host_async(DeviceIterator first,
107                                                DeviceIterator last,
108                                                HostIterator result,
109                                                command_queue &queue,
110                                                const wait_list &events)
111 {
112     typedef typename
113         std::iterator_traits<DeviceIterator>::value_type
114         value_type;
115 
116     size_t count = iterator_range_size(first, last);
117     if(count == 0){
118         return future<HostIterator>();
119     }
120 
121     const buffer &buffer = first.get_buffer();
122     size_t offset = first.get_index();
123 
124     event event_ =
125         queue.enqueue_read_buffer_async(buffer,
126                                         offset * sizeof(value_type),
127                                         count * sizeof(value_type),
128                                         ::boost::addressof(*result),
129                                         events);
130 
131     return make_future(iterator_plus_distance(result, count), event_);
132 }
133 
134 #ifdef BOOST_COMPUTE_CL_VERSION_2_0
135 // copy_to_host() specialization for svm_ptr
136 template<class T, class HostIterator>
copy_to_host(svm_ptr<T> first,svm_ptr<T> last,HostIterator result,command_queue & queue,const wait_list & events)137 inline HostIterator copy_to_host(svm_ptr<T> first,
138                                  svm_ptr<T> last,
139                                  HostIterator result,
140                                  command_queue &queue,
141                                  const wait_list &events)
142 {
143     size_t count = iterator_range_size(first, last);
144     if(count == 0){
145         return result;
146     }
147 
148     queue.enqueue_svm_memcpy(
149         ::boost::addressof(*result), first.get(), count * sizeof(T), events
150     );
151 
152     return result + count;
153 }
154 
155 template<class T, class HostIterator>
copy_to_host_async(svm_ptr<T> first,svm_ptr<T> last,HostIterator result,command_queue & queue,const wait_list & events)156 inline future<HostIterator> copy_to_host_async(svm_ptr<T> first,
157                                                svm_ptr<T> last,
158                                                HostIterator result,
159                                                command_queue &queue,
160                                                const wait_list &events)
161 {
162     size_t count = iterator_range_size(first, last);
163     if(count == 0){
164         return future<HostIterator>();
165     }
166 
167     event event_ = queue.enqueue_svm_memcpy_async(
168         ::boost::addressof(*result), first.get(), count * sizeof(T), events
169     );
170 
171     return make_future(iterator_plus_distance(result, count), event_);
172 }
173 
174 template<class T, class HostIterator>
copy_to_host_map(svm_ptr<T> first,svm_ptr<T> last,HostIterator result,command_queue & queue,const wait_list & events)175 inline HostIterator copy_to_host_map(svm_ptr<T> first,
176                                      svm_ptr<T> last,
177                                      HostIterator result,
178                                      command_queue &queue,
179                                      const wait_list &events)
180 {
181     size_t count = iterator_range_size(first, last);
182     if(count == 0){
183         return result;
184     }
185 
186     // map
187     queue.enqueue_svm_map(first.get(), count * sizeof(T), CL_MAP_READ, events);
188 
189     // copy [first; last) to result
190     std::copy(
191         static_cast<T*>(first.get()),
192         static_cast<T*>(last.get()),
193         result
194     );
195 
196     // unmap [first; last)
197     queue.enqueue_svm_unmap(first.get()).wait();
198 
199     return iterator_plus_distance(result, count);
200 }
201 #endif // BOOST_COMPUTE_CL_VERSION_2_0
202 
203 } // end detail namespace
204 } // end compute namespace
205 } // end boost namespace
206 
207 #endif // BOOST_COMPUTE_ALGORITHM_DETAIL_COPY_TO_HOST_HPP
208