1//
2// Copyright 2012 Francisco Jerez
3//
4// Permission is hereby granted, free of charge, to any person obtaining a
5// copy of this software and associated documentation files (the "Software"),
6// to deal in the Software without restriction, including without limitation
7// the rights to use, copy, modify, merge, publish, distribute, sublicense,
8// and/or sell copies of the Software, and to permit persons to whom the
9// Software is furnished to do so, subject to the following conditions:
10//
11// The above copyright notice and this permission notice shall be included in
12// all copies or substantial portions of the Software.
13//
14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
18// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20// OTHER DEALINGS IN THE SOFTWARE.
21//
22
23#include "api/util.hpp"
24#include "core/platform.hpp"
25#include "core/device.hpp"
26#include "git_sha1.h"
27
28using namespace clover;
29
30CLOVER_API cl_int
31clGetDeviceIDs(cl_platform_id d_platform, cl_device_type device_type,
32               cl_uint num_entries, cl_device_id *rd_devices,
33               cl_uint *rnum_devices) try {
34   auto &platform = obj(d_platform);
35   std::vector<cl_device_id> d_devs;
36
37   if ((!num_entries && rd_devices) ||
38       (!rnum_devices && !rd_devices))
39      throw error(CL_INVALID_VALUE);
40
41   // Collect matching devices
42   for (device &dev : platform) {
43      if (((device_type & CL_DEVICE_TYPE_DEFAULT) &&
44           dev == platform.front()) ||
45          (device_type & dev.type()))
46         d_devs.push_back(desc(dev));
47   }
48
49   if (d_devs.empty())
50      throw error(CL_DEVICE_NOT_FOUND);
51
52   // ...and return the requested data.
53   if (rnum_devices)
54      *rnum_devices = d_devs.size();
55   if (rd_devices)
56      copy(range(d_devs.begin(),
57                 std::min((unsigned)d_devs.size(), num_entries)),
58           rd_devices);
59
60   return CL_SUCCESS;
61
62} catch (error &e) {
63   return e.get();
64}
65
66CLOVER_API cl_int
67clCreateSubDevices(cl_device_id d_dev,
68                   const cl_device_partition_property *props,
69                   cl_uint num_devs, cl_device_id *rd_devs,
70                   cl_uint *rnum_devs) {
71   // There are no currently supported partitioning schemes.
72   return CL_INVALID_VALUE;
73}
74
75CLOVER_API cl_int
76clRetainDevice(cl_device_id d_dev) try {
77   obj(d_dev);
78
79   // The reference count doesn't change for root devices.
80   return CL_SUCCESS;
81
82} catch (error &e) {
83   return e.get();
84}
85
86CLOVER_API cl_int
87clReleaseDevice(cl_device_id d_dev) try {
88   obj(d_dev);
89
90   // The reference count doesn't change for root devices.
91   return CL_SUCCESS;
92
93} catch (error &e) {
94   return e.get();
95}
96
97CLOVER_API cl_int
98clGetDeviceInfo(cl_device_id d_dev, cl_device_info param,
99                size_t size, void *r_buf, size_t *r_size) try {
100   property_buffer buf { r_buf, size, r_size };
101   auto &dev = obj(d_dev);
102
103   switch (param) {
104   case CL_DEVICE_TYPE:
105      buf.as_scalar<cl_device_type>() = dev.type();
106      break;
107
108   case CL_DEVICE_VENDOR_ID:
109      buf.as_scalar<cl_uint>() = dev.vendor_id();
110      break;
111
112   case CL_DEVICE_MAX_COMPUTE_UNITS:
113      buf.as_scalar<cl_uint>() = dev.max_compute_units();
114      break;
115
116   case CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS:
117      buf.as_scalar<cl_uint>() = dev.max_block_size().size();
118      break;
119
120   case CL_DEVICE_MAX_WORK_ITEM_SIZES:
121      buf.as_vector<size_t>() = dev.max_block_size();
122      break;
123
124   case CL_DEVICE_MAX_WORK_GROUP_SIZE:
125      buf.as_scalar<size_t>() = dev.max_threads_per_block();
126      break;
127
128   case CL_DEVICE_PREFERRED_VECTOR_WIDTH_CHAR:
129      buf.as_scalar<cl_uint>() = 16;
130      break;
131
132   case CL_DEVICE_PREFERRED_VECTOR_WIDTH_SHORT:
133      buf.as_scalar<cl_uint>() = 8;
134      break;
135
136   case CL_DEVICE_PREFERRED_VECTOR_WIDTH_INT:
137      buf.as_scalar<cl_uint>() = 4;
138      break;
139
140   case CL_DEVICE_PREFERRED_VECTOR_WIDTH_LONG:
141      buf.as_scalar<cl_uint>() = 2;
142      break;
143
144   case CL_DEVICE_PREFERRED_VECTOR_WIDTH_FLOAT:
145      buf.as_scalar<cl_uint>() = 4;
146      break;
147
148   case CL_DEVICE_PREFERRED_VECTOR_WIDTH_DOUBLE:
149      buf.as_scalar<cl_uint>() = dev.has_doubles() ? 2 : 0;
150      break;
151
152   case CL_DEVICE_PREFERRED_VECTOR_WIDTH_HALF:
153      buf.as_scalar<cl_uint>() = dev.has_halves() ? 8 : 0;
154      break;
155
156   case CL_DEVICE_MAX_CLOCK_FREQUENCY:
157      buf.as_scalar<cl_uint>() = dev.max_clock_frequency();
158      break;
159
160   case CL_DEVICE_ADDRESS_BITS:
161      buf.as_scalar<cl_uint>() = dev.address_bits();
162      break;
163
164   case CL_DEVICE_MAX_READ_IMAGE_ARGS:
165      buf.as_scalar<cl_uint>() = dev.max_images_read();
166      break;
167
168   case CL_DEVICE_MAX_WRITE_IMAGE_ARGS:
169      buf.as_scalar<cl_uint>() = dev.max_images_write();
170      break;
171
172   case CL_DEVICE_MAX_MEM_ALLOC_SIZE:
173      buf.as_scalar<cl_ulong>() = dev.max_mem_alloc_size();
174      break;
175
176   case CL_DEVICE_IMAGE2D_MAX_WIDTH:
177   case CL_DEVICE_IMAGE2D_MAX_HEIGHT:
178      buf.as_scalar<size_t>() = 1 << dev.max_image_levels_2d();
179      break;
180
181   case CL_DEVICE_IMAGE3D_MAX_WIDTH:
182   case CL_DEVICE_IMAGE3D_MAX_HEIGHT:
183   case CL_DEVICE_IMAGE3D_MAX_DEPTH:
184      buf.as_scalar<size_t>() = 1 << dev.max_image_levels_3d();
185      break;
186
187   case CL_DEVICE_IMAGE_MAX_BUFFER_SIZE:
188      buf.as_scalar<size_t>() = dev.max_image_buffer_size();
189      break;
190
191   case CL_DEVICE_IMAGE_MAX_ARRAY_SIZE:
192      buf.as_scalar<size_t>() = dev.max_image_array_number();
193      break;
194
195   case CL_DEVICE_IMAGE_SUPPORT:
196      buf.as_scalar<cl_bool>() = dev.image_support();
197      break;
198
199   case CL_DEVICE_MAX_PARAMETER_SIZE:
200      buf.as_scalar<size_t>() = dev.max_mem_input();
201      break;
202
203   case CL_DEVICE_MAX_SAMPLERS:
204      buf.as_scalar<cl_uint>() = dev.max_samplers();
205      break;
206
207   case CL_DEVICE_MEM_BASE_ADDR_ALIGN:
208      buf.as_scalar<cl_uint>() = 8 *
209         std::max(dev.mem_base_addr_align(), (cl_uint) sizeof(cl_long) * 16);
210      break;
211
212   case CL_DEVICE_MIN_DATA_TYPE_ALIGN_SIZE:
213      buf.as_scalar<cl_uint>() = 128;
214      break;
215
216   case CL_DEVICE_HALF_FP_CONFIG:
217      // This is the "mandated minimum half precision floating-point
218      // capability" for OpenCL 1.x.
219      buf.as_scalar<cl_device_fp_config>() =
220         CL_FP_INF_NAN | CL_FP_ROUND_TO_NEAREST;
221      break;
222
223   case CL_DEVICE_SINGLE_FP_CONFIG:
224      // This is the "mandated minimum single precision floating-point
225      // capability" for OpenCL 1.1.  In OpenCL 1.2, nothing is required for
226      // custom devices.
227      buf.as_scalar<cl_device_fp_config>() =
228         CL_FP_INF_NAN | CL_FP_ROUND_TO_NEAREST;
229      break;
230
231   case CL_DEVICE_DOUBLE_FP_CONFIG:
232      if (dev.has_doubles())
233         // This is the "mandated minimum double precision floating-point
234         // capability"
235         buf.as_scalar<cl_device_fp_config>() =
236               CL_FP_FMA
237             | CL_FP_ROUND_TO_NEAREST
238             | CL_FP_ROUND_TO_ZERO
239             | CL_FP_ROUND_TO_INF
240             | CL_FP_INF_NAN
241             | CL_FP_DENORM;
242      else
243         buf.as_scalar<cl_device_fp_config>() = 0;
244      break;
245
246   case CL_DEVICE_GLOBAL_MEM_CACHE_TYPE:
247      buf.as_scalar<cl_device_mem_cache_type>() = CL_NONE;
248      break;
249
250   case CL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE:
251      buf.as_scalar<cl_uint>() = 0;
252      break;
253
254   case CL_DEVICE_GLOBAL_MEM_CACHE_SIZE:
255      buf.as_scalar<cl_ulong>() = 0;
256      break;
257
258   case CL_DEVICE_GLOBAL_MEM_SIZE:
259      buf.as_scalar<cl_ulong>() = dev.max_mem_global();
260      break;
261
262   case CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE:
263      buf.as_scalar<cl_ulong>() = dev.max_const_buffer_size();
264      break;
265
266   case CL_DEVICE_MAX_CONSTANT_ARGS:
267      buf.as_scalar<cl_uint>() = dev.max_const_buffers();
268      break;
269
270   case CL_DEVICE_LOCAL_MEM_TYPE:
271      buf.as_scalar<cl_device_local_mem_type>() = CL_LOCAL;
272      break;
273
274   case CL_DEVICE_LOCAL_MEM_SIZE:
275      buf.as_scalar<cl_ulong>() = dev.max_mem_local();
276      break;
277
278   case CL_DEVICE_ERROR_CORRECTION_SUPPORT:
279      buf.as_scalar<cl_bool>() = CL_FALSE;
280      break;
281
282   case CL_DEVICE_PROFILING_TIMER_RESOLUTION:
283      buf.as_scalar<size_t>() = 0;
284      break;
285
286   case CL_DEVICE_ENDIAN_LITTLE:
287      buf.as_scalar<cl_bool>() = (dev.endianness() == PIPE_ENDIAN_LITTLE);
288      break;
289
290   case CL_DEVICE_AVAILABLE:
291   case CL_DEVICE_COMPILER_AVAILABLE:
292   case CL_DEVICE_LINKER_AVAILABLE:
293      buf.as_scalar<cl_bool>() = CL_TRUE;
294      break;
295
296   case CL_DEVICE_EXECUTION_CAPABILITIES:
297      buf.as_scalar<cl_device_exec_capabilities>() = CL_EXEC_KERNEL;
298      break;
299
300   case CL_DEVICE_QUEUE_PROPERTIES:
301      buf.as_scalar<cl_command_queue_properties>() = CL_QUEUE_PROFILING_ENABLE;
302      break;
303
304   case CL_DEVICE_BUILT_IN_KERNELS:
305      buf.as_string() = "";
306      break;
307
308   case CL_DEVICE_NAME:
309      buf.as_string() = dev.device_name();
310      break;
311
312   case CL_DEVICE_VENDOR:
313      buf.as_string() = dev.vendor_name();
314      break;
315
316   case CL_DRIVER_VERSION:
317      buf.as_string() = PACKAGE_VERSION;
318      break;
319
320   case CL_DEVICE_PROFILE:
321      buf.as_string() = "FULL_PROFILE";
322      break;
323
324   case CL_DEVICE_VERSION:
325      buf.as_string() = "OpenCL " + dev.device_version() + " Mesa " PACKAGE_VERSION MESA_GIT_SHA1;
326      break;
327
328   case CL_DEVICE_EXTENSIONS:
329      buf.as_string() = dev.supported_extensions();
330      break;
331
332   case CL_DEVICE_PLATFORM:
333      buf.as_scalar<cl_platform_id>() = desc(dev.platform);
334      break;
335
336   case CL_DEVICE_HOST_UNIFIED_MEMORY:
337      buf.as_scalar<cl_bool>() = dev.has_unified_memory();
338      break;
339
340   case CL_DEVICE_NATIVE_VECTOR_WIDTH_CHAR:
341      buf.as_scalar<cl_uint>() = 16;
342      break;
343
344   case CL_DEVICE_NATIVE_VECTOR_WIDTH_SHORT:
345      buf.as_scalar<cl_uint>() = 8;
346      break;
347
348   case CL_DEVICE_NATIVE_VECTOR_WIDTH_INT:
349      buf.as_scalar<cl_uint>() = 4;
350      break;
351
352   case CL_DEVICE_NATIVE_VECTOR_WIDTH_LONG:
353      buf.as_scalar<cl_uint>() = 2;
354      break;
355
356   case CL_DEVICE_NATIVE_VECTOR_WIDTH_FLOAT:
357      buf.as_scalar<cl_uint>() = 4;
358      break;
359
360   case CL_DEVICE_NATIVE_VECTOR_WIDTH_DOUBLE:
361      buf.as_scalar<cl_uint>() = dev.has_doubles() ? 2 : 0;
362      break;
363
364   case CL_DEVICE_NATIVE_VECTOR_WIDTH_HALF:
365      buf.as_scalar<cl_uint>() = dev.has_halves() ? 8 : 0;
366      break;
367
368   case CL_DEVICE_OPENCL_C_VERSION:
369      buf.as_string() = "OpenCL C " + dev.device_clc_version() + " ";
370      break;
371
372   case CL_DEVICE_PRINTF_BUFFER_SIZE:
373      // Per the spec, the minimum value for the FULL profile is 1 MB.
374      // However, clover is not ready yet to support it
375      buf.as_scalar<size_t>() = 0 /* 1024 */;
376      break;
377
378   case CL_DEVICE_PREFERRED_INTEROP_USER_SYNC:
379      buf.as_scalar<cl_bool>() = CL_TRUE;
380      break;
381
382   case CL_DEVICE_PARENT_DEVICE:
383      buf.as_scalar<cl_device_id>() = NULL;
384      break;
385
386   case CL_DEVICE_PARTITION_MAX_SUB_DEVICES:
387      buf.as_scalar<cl_uint>() = 0;
388      break;
389
390   case CL_DEVICE_PARTITION_PROPERTIES:
391      buf.as_vector<cl_device_partition_property>() =
392         desc(property_list<cl_device_partition_property>());
393      break;
394
395   case CL_DEVICE_PARTITION_AFFINITY_DOMAIN:
396      buf.as_scalar<cl_device_affinity_domain>() = 0;
397      break;
398
399   case CL_DEVICE_PARTITION_TYPE:
400      buf.as_vector<cl_device_partition_property>() =
401         desc(property_list<cl_device_partition_property>());
402      break;
403
404   case CL_DEVICE_REFERENCE_COUNT:
405      buf.as_scalar<cl_uint>() = 1;
406      break;
407
408   default:
409      throw error(CL_INVALID_VALUE);
410   }
411
412   return CL_SUCCESS;
413
414} catch (error &e) {
415   return e.get();
416}
417