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