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_DETAIL_GET_OBJECT_INFO_HPP
12 #define BOOST_COMPUTE_DETAIL_GET_OBJECT_INFO_HPP
13 
14 #include <string>
15 #include <vector>
16 
17 #include <boost/preprocessor/seq/for_each.hpp>
18 #include <boost/preprocessor/tuple/elem.hpp>
19 
20 #include <boost/throw_exception.hpp>
21 
22 #include <boost/compute/cl.hpp>
23 #include <boost/compute/exception/opencl_error.hpp>
24 
25 namespace boost {
26 namespace compute {
27 namespace detail {
28 
29 template<class Function, class Object, class AuxInfo>
30 struct bound_info_function
31 {
bound_info_functionboost::compute::detail::bound_info_function32     bound_info_function(Function function, Object object, AuxInfo aux_info)
33         : m_function(function),
34           m_object(object),
35           m_aux_info(aux_info)
36     {
37     }
38 
39     template<class Info>
operator ()boost::compute::detail::bound_info_function40     cl_int operator()(Info info, size_t input_size, const void *input,
41                       size_t size, void *value, size_t *size_ret) const
42     {
43         return m_function(
44             m_object, m_aux_info, info,
45             input_size, input, size, value, size_ret
46         );
47     }
48 
49     template<class Info>
operator ()boost::compute::detail::bound_info_function50     cl_int operator()(Info info, size_t size, void *value, size_t *size_ret) const
51     {
52         return m_function(m_object, m_aux_info, info, size, value, size_ret);
53     }
54 
55     Function m_function;
56     Object m_object;
57     AuxInfo m_aux_info;
58 };
59 
60 template<class Function, class Object>
61 struct bound_info_function<Function, Object, void>
62 {
bound_info_functionboost::compute::detail::bound_info_function63     bound_info_function(Function function, Object object)
64         : m_function(function),
65           m_object(object)
66     {
67     }
68 
69     template<class Info>
operator ()boost::compute::detail::bound_info_function70     cl_int operator()(Info info, size_t size, void *value, size_t *size_ret) const
71     {
72         return m_function(m_object, info, size, value, size_ret);
73     }
74 
75     Function m_function;
76     Object m_object;
77 };
78 
79 template<class Function, class Object>
80 inline bound_info_function<Function, Object, void>
bind_info_function(Function f,Object o)81 bind_info_function(Function f, Object o)
82 {
83     return bound_info_function<Function, Object, void>(f, o);
84 }
85 
86 template<class Function, class Object, class AuxInfo>
87 inline bound_info_function<Function, Object, AuxInfo>
bind_info_function(Function f,Object o,AuxInfo j)88 bind_info_function(Function f, Object o, AuxInfo j)
89 {
90     return bound_info_function<Function, Object, AuxInfo>(f, o, j);
91 }
92 
93 // default implementation
94 template<class T>
95 struct get_object_info_impl
96 {
97     template<class Function, class Info>
operator ()boost::compute::detail::get_object_info_impl98     T operator()(Function function, Info info) const
99     {
100         T value;
101 
102         cl_int ret = function(info, sizeof(T), &value, 0);
103         if(ret != CL_SUCCESS){
104             BOOST_THROW_EXCEPTION(opencl_error(ret));
105         }
106 
107         return value;
108     }
109 
110     template<class Function, class Info>
operator ()boost::compute::detail::get_object_info_impl111     T operator()(Function function, Info info,
112                  const size_t input_size, const void* input) const
113     {
114         T value;
115 
116         cl_int ret = function(info, input_size, input, sizeof(T), &value, 0);
117         if(ret != CL_SUCCESS){
118             BOOST_THROW_EXCEPTION(opencl_error(ret));
119         }
120 
121         return value;
122     }
123 };
124 
125 // specialization for bool
126 template<>
127 struct get_object_info_impl<bool>
128 {
129     template<class Function, class Info>
operator ()boost::compute::detail::get_object_info_impl130     bool operator()(Function function, Info info) const
131     {
132         cl_bool value;
133 
134         cl_int ret = function(info, sizeof(cl_bool), &value, 0);
135         if(ret != CL_SUCCESS){
136             BOOST_THROW_EXCEPTION(opencl_error(ret));
137         }
138 
139         return value == CL_TRUE;
140     }
141 };
142 
143 // specialization for std::string
144 template<>
145 struct get_object_info_impl<std::string>
146 {
147     template<class Function, class Info>
operator ()boost::compute::detail::get_object_info_impl148     std::string operator()(Function function, Info info) const
149     {
150         size_t size = 0;
151 
152         cl_int ret = function(info, 0, 0, &size);
153         if(ret != CL_SUCCESS){
154             BOOST_THROW_EXCEPTION(opencl_error(ret));
155         }
156 
157         if(size == 0){
158             return std::string();
159         }
160 
161         std::string value(size - 1, 0);
162 
163         ret = function(info, size, &value[0], 0);
164         if(ret != CL_SUCCESS){
165             BOOST_THROW_EXCEPTION(opencl_error(ret));
166         }
167 
168         return value;
169     }
170 };
171 
172 // specialization for std::vector<T>
173 template<class T>
174 struct get_object_info_impl<std::vector<T> >
175 {
176     template<class Function, class Info>
operator ()boost::compute::detail::get_object_info_impl177     std::vector<T> operator()(Function function, Info info) const
178     {
179         size_t size = 0;
180 
181         cl_int ret = function(info, 0, 0, &size);
182         if(ret != CL_SUCCESS){
183             BOOST_THROW_EXCEPTION(opencl_error(ret));
184         }
185 
186         if(size == 0) return std::vector<T>();
187 
188         std::vector<T> vector(size / sizeof(T));
189         ret = function(info, size, &vector[0], 0);
190         if(ret != CL_SUCCESS){
191             BOOST_THROW_EXCEPTION(opencl_error(ret));
192         }
193 
194         return vector;
195     }
196 
197     template<class Function, class Info>
operator ()boost::compute::detail::get_object_info_impl198     std::vector<T> operator()(Function function, Info info,
199                               const size_t input_size, const void* input) const
200     {
201         #ifdef BOOST_COMPUTE_CL_VERSION_2_1
202         // For CL_KERNEL_LOCAL_SIZE_FOR_SUB_GROUP_COUNT in clGetKernelSubGroupInfo
203         // we can't get param_value_size using param_value_size_ret
204         if(info == CL_KERNEL_LOCAL_SIZE_FOR_SUB_GROUP_COUNT)
205         {
206             std::vector<T> vector(3);
207             cl_int ret = function(
208                 info, input_size, input,
209                 sizeof(T) * vector.size(), &vector[0], 0
210             );
211             if(ret != CL_SUCCESS){
212                 BOOST_THROW_EXCEPTION(opencl_error(ret));
213             }
214             return vector;
215         }
216         #endif
217         size_t size = 0;
218 
219         cl_int ret = function(info, input_size, input, 0, 0, &size);
220         if(ret != CL_SUCCESS){
221             BOOST_THROW_EXCEPTION(opencl_error(ret));
222         }
223 
224         std::vector<T> vector(size / sizeof(T));
225         ret = function(info, input_size, input, size, &vector[0], 0);
226         if(ret != CL_SUCCESS){
227             BOOST_THROW_EXCEPTION(opencl_error(ret));
228         }
229 
230         return vector;
231     }
232 };
233 
234 // returns the value (of type T) from the given clGet*Info() function call.
235 template<class T, class Function, class Object, class Info>
get_object_info(Function f,Object o,Info i)236 inline T get_object_info(Function f, Object o, Info i)
237 {
238     return get_object_info_impl<T>()(bind_info_function(f, o), i);
239 }
240 
241 template<class T, class Function, class Object, class Info, class AuxInfo>
get_object_info(Function f,Object o,Info i,AuxInfo j)242 inline T get_object_info(Function f, Object o, Info i, AuxInfo j)
243 {
244     return get_object_info_impl<T>()(bind_info_function(f, o, j), i);
245 }
246 
247 template<class T, class Function, class Object, class Info, class AuxInfo>
get_object_info(Function f,Object o,Info i,AuxInfo j,const size_t k,const void * l)248 inline T get_object_info(Function f, Object o, Info i, AuxInfo j, const size_t k, const void * l)
249 {
250     return get_object_info_impl<T>()(bind_info_function(f, o, j), i, k, l);
251 }
252 
253 // returns the value type for the clGet*Info() call on Object with Enum.
254 template<class Object, int Enum>
255 struct get_object_info_type;
256 
257 // defines the object::get_info<Enum>() specialization
258 #define BOOST_COMPUTE_DETAIL_DEFINE_GET_INFO_SPECIALIZATION(object_type, result_type, value) \
259     namespace detail { \
260         template<> struct get_object_info_type<object_type, value> { typedef result_type type; }; \
261     } \
262     template<> inline result_type object_type::get_info<value>() const \
263     { \
264         return get_info<result_type>(value); \
265     }
266 
267 // used by BOOST_COMPUTE_DETAIL_DEFINE_GET_INFO_SPECIALIZATIONS()
268 #define BOOST_COMPUTE_DETAIL_DEFINE_GET_INFO_IMPL(r, data, elem) \
269     BOOST_COMPUTE_DETAIL_DEFINE_GET_INFO_SPECIALIZATION( \
270         data, BOOST_PP_TUPLE_ELEM(2, 0, elem), BOOST_PP_TUPLE_ELEM(2, 1, elem) \
271     )
272 
273 // defines the object::get_info<Enum>() specialization for each
274 // (result_type, value) tuple in seq for object_type.
275 #define BOOST_COMPUTE_DETAIL_DEFINE_GET_INFO_SPECIALIZATIONS(object_type, seq) \
276     BOOST_PP_SEQ_FOR_EACH( \
277         BOOST_COMPUTE_DETAIL_DEFINE_GET_INFO_IMPL, object_type, seq \
278     )
279 
280 } // end detail namespace
281 } // end compute namespace
282 } // end boost namespace
283 
284 #endif // BOOST_COMPUTE_DETAIL_GET_OBJECT_INFO_HPP
285