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
30namespace {
31   std::string
32   supported_il_versions_as_string(const device &dev) {
33      std::string il_versions_string;
34
35      for (const auto &il_version : dev.supported_il_versions()) {
36         if (!il_versions_string.empty())
37            il_versions_string += " ";
38
39         il_versions_string += std::string(il_version.name) + "_" +
40            std::to_string(CL_VERSION_MAJOR(il_version.version)) + "." +
41            std::to_string(CL_VERSION_MINOR(il_version.version));
42      }
43      return il_versions_string;
44   }
45}
46
47CLOVER_API cl_int
48clGetDeviceIDs(cl_platform_id d_platform, cl_device_type device_type,
49               cl_uint num_entries, cl_device_id *rd_devices,
50               cl_uint *rnum_devices) try {
51   auto &platform = obj(d_platform);
52   std::vector<cl_device_id> d_devs;
53
54   if ((!num_entries && rd_devices) ||
55       (!rnum_devices && !rd_devices))
56      throw error(CL_INVALID_VALUE);
57
58   // Collect matching devices
59   for (device &dev : platform) {
60      if (((device_type & CL_DEVICE_TYPE_DEFAULT) &&
61           dev == platform.front()) ||
62          (device_type & dev.type()))
63         d_devs.push_back(desc(dev));
64   }
65
66   if (d_devs.empty())
67      throw error(CL_DEVICE_NOT_FOUND);
68
69   // ...and return the requested data.
70   if (rnum_devices)
71      *rnum_devices = d_devs.size();
72   if (rd_devices)
73      copy(range(d_devs.begin(),
74                 std::min((unsigned)d_devs.size(), num_entries)),
75           rd_devices);
76
77   return CL_SUCCESS;
78
79} catch (error &e) {
80   return e.get();
81}
82
83CLOVER_API cl_int
84clCreateSubDevices(cl_device_id d_dev,
85                   const cl_device_partition_property *props,
86                   cl_uint num_devs, cl_device_id *rd_devs,
87                   cl_uint *rnum_devs) {
88   // There are no currently supported partitioning schemes.
89   return CL_INVALID_VALUE;
90}
91
92CLOVER_API cl_int
93clRetainDevice(cl_device_id d_dev) try {
94   obj(d_dev);
95
96   // The reference count doesn't change for root devices.
97   return CL_SUCCESS;
98
99} catch (error &e) {
100   return e.get();
101}
102
103CLOVER_API cl_int
104clReleaseDevice(cl_device_id d_dev) try {
105   obj(d_dev);
106
107   // The reference count doesn't change for root devices.
108   return CL_SUCCESS;
109
110} catch (error &e) {
111   return e.get();
112}
113
114CLOVER_API cl_int
115clGetDeviceInfo(cl_device_id d_dev, cl_device_info param,
116                size_t size, void *r_buf, size_t *r_size) try {
117   property_buffer buf { r_buf, size, r_size };
118   auto &dev = obj(d_dev);
119
120   switch (param) {
121   case CL_DEVICE_TYPE:
122      buf.as_scalar<cl_device_type>() = dev.type();
123      break;
124
125   case CL_DEVICE_VENDOR_ID:
126      buf.as_scalar<cl_uint>() = dev.vendor_id();
127      break;
128
129   case CL_DEVICE_MAX_COMPUTE_UNITS:
130      buf.as_scalar<cl_uint>() = dev.max_compute_units();
131      break;
132
133   case CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS:
134      buf.as_scalar<cl_uint>() = dev.max_block_size().size();
135      break;
136
137   case CL_DEVICE_MAX_WORK_ITEM_SIZES:
138      buf.as_vector<size_t>() = dev.max_block_size();
139      break;
140
141   case CL_DEVICE_MAX_WORK_GROUP_SIZE:
142      buf.as_scalar<size_t>() = dev.max_threads_per_block();
143      break;
144
145   case CL_DEVICE_PREFERRED_VECTOR_WIDTH_CHAR:
146      buf.as_scalar<cl_uint>() = 16;
147      break;
148
149   case CL_DEVICE_PREFERRED_VECTOR_WIDTH_SHORT:
150      buf.as_scalar<cl_uint>() = 8;
151      break;
152
153   case CL_DEVICE_PREFERRED_VECTOR_WIDTH_INT:
154      buf.as_scalar<cl_uint>() = 4;
155      break;
156
157   case CL_DEVICE_PREFERRED_VECTOR_WIDTH_LONG:
158      buf.as_scalar<cl_uint>() = 2;
159      break;
160
161   case CL_DEVICE_PREFERRED_VECTOR_WIDTH_FLOAT:
162      buf.as_scalar<cl_uint>() = 4;
163      break;
164
165   case CL_DEVICE_PREFERRED_VECTOR_WIDTH_DOUBLE:
166      buf.as_scalar<cl_uint>() = dev.has_doubles() ? 2 : 0;
167      break;
168
169   case CL_DEVICE_PREFERRED_VECTOR_WIDTH_HALF:
170      buf.as_scalar<cl_uint>() = dev.has_halves() ? 8 : 0;
171      break;
172
173   case CL_DEVICE_MAX_CLOCK_FREQUENCY:
174      buf.as_scalar<cl_uint>() = dev.max_clock_frequency();
175      break;
176
177   case CL_DEVICE_ADDRESS_BITS:
178      buf.as_scalar<cl_uint>() = dev.address_bits();
179      break;
180
181   case CL_DEVICE_MAX_READ_IMAGE_ARGS:
182      buf.as_scalar<cl_uint>() = dev.max_images_read();
183      break;
184
185   case CL_DEVICE_MAX_WRITE_IMAGE_ARGS:
186      buf.as_scalar<cl_uint>() = dev.max_images_write();
187      break;
188
189   case CL_DEVICE_MAX_MEM_ALLOC_SIZE:
190      buf.as_scalar<cl_ulong>() = dev.max_mem_alloc_size();
191      break;
192
193   case CL_DEVICE_IMAGE2D_MAX_WIDTH:
194   case CL_DEVICE_IMAGE2D_MAX_HEIGHT:
195      buf.as_scalar<size_t>() = dev.max_image_size();
196      break;
197
198   case CL_DEVICE_IMAGE3D_MAX_WIDTH:
199   case CL_DEVICE_IMAGE3D_MAX_HEIGHT:
200   case CL_DEVICE_IMAGE3D_MAX_DEPTH:
201      buf.as_scalar<size_t>() = dev.max_image_size_3d();
202      break;
203
204   case CL_DEVICE_IMAGE_MAX_BUFFER_SIZE:
205      buf.as_scalar<size_t>() = dev.max_image_buffer_size();
206      break;
207
208   case CL_DEVICE_IMAGE_MAX_ARRAY_SIZE:
209      buf.as_scalar<size_t>() = dev.max_image_array_number();
210      break;
211
212   case CL_DEVICE_IMAGE_SUPPORT:
213      buf.as_scalar<cl_bool>() = dev.image_support();
214      break;
215
216   case CL_DEVICE_MAX_PARAMETER_SIZE:
217      buf.as_scalar<size_t>() = dev.max_mem_input();
218      break;
219
220   case CL_DEVICE_MAX_SAMPLERS:
221      buf.as_scalar<cl_uint>() = dev.max_samplers();
222      break;
223
224   case CL_DEVICE_MEM_BASE_ADDR_ALIGN:
225      buf.as_scalar<cl_uint>() = 8 * dev.mem_base_addr_align();
226      break;
227
228   case CL_DEVICE_MIN_DATA_TYPE_ALIGN_SIZE:
229      buf.as_scalar<cl_uint>() = 128;
230      break;
231
232   case CL_DEVICE_HALF_FP_CONFIG:
233      // This is the "mandated minimum half precision floating-point
234      // capability" for OpenCL 1.x.
235      buf.as_scalar<cl_device_fp_config>() =
236         CL_FP_INF_NAN | CL_FP_ROUND_TO_NEAREST;
237      break;
238
239   case CL_DEVICE_SINGLE_FP_CONFIG:
240      // This is the "mandated minimum single precision floating-point
241      // capability" for OpenCL 1.1.  In OpenCL 1.2, nothing is required for
242      // custom devices.
243      buf.as_scalar<cl_device_fp_config>() =
244         CL_FP_INF_NAN | CL_FP_ROUND_TO_NEAREST;
245      break;
246
247   case CL_DEVICE_DOUBLE_FP_CONFIG:
248      if (dev.has_doubles())
249         // This is the "mandated minimum double precision floating-point
250         // capability"
251         buf.as_scalar<cl_device_fp_config>() =
252               CL_FP_FMA
253             | CL_FP_ROUND_TO_NEAREST
254             | CL_FP_ROUND_TO_ZERO
255             | CL_FP_ROUND_TO_INF
256             | CL_FP_INF_NAN
257             | CL_FP_DENORM;
258      else
259         buf.as_scalar<cl_device_fp_config>() = 0;
260      break;
261
262   case CL_DEVICE_GLOBAL_MEM_CACHE_TYPE:
263      buf.as_scalar<cl_device_mem_cache_type>() = CL_NONE;
264      break;
265
266   case CL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE:
267      buf.as_scalar<cl_uint>() = 0;
268      break;
269
270   case CL_DEVICE_GLOBAL_MEM_CACHE_SIZE:
271      buf.as_scalar<cl_ulong>() = 0;
272      break;
273
274   case CL_DEVICE_GLOBAL_MEM_SIZE:
275      buf.as_scalar<cl_ulong>() = dev.max_mem_global();
276      break;
277
278   case CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE:
279      buf.as_scalar<cl_ulong>() = dev.max_const_buffer_size();
280      break;
281
282   case CL_DEVICE_MAX_CONSTANT_ARGS:
283      buf.as_scalar<cl_uint>() = dev.max_const_buffers();
284      break;
285
286   case CL_DEVICE_LOCAL_MEM_TYPE:
287      buf.as_scalar<cl_device_local_mem_type>() = CL_LOCAL;
288      break;
289
290   case CL_DEVICE_LOCAL_MEM_SIZE:
291      buf.as_scalar<cl_ulong>() = dev.max_mem_local();
292      break;
293
294   case CL_DEVICE_ERROR_CORRECTION_SUPPORT:
295      buf.as_scalar<cl_bool>() = CL_FALSE;
296      break;
297
298   case CL_DEVICE_PROFILING_TIMER_RESOLUTION:
299      buf.as_scalar<size_t>() = 0;
300      break;
301
302   case CL_DEVICE_ENDIAN_LITTLE:
303      buf.as_scalar<cl_bool>() = (dev.endianness() == PIPE_ENDIAN_LITTLE);
304      break;
305
306   case CL_DEVICE_AVAILABLE:
307   case CL_DEVICE_COMPILER_AVAILABLE:
308   case CL_DEVICE_LINKER_AVAILABLE:
309      buf.as_scalar<cl_bool>() = CL_TRUE;
310      break;
311
312   case CL_DEVICE_EXECUTION_CAPABILITIES:
313      buf.as_scalar<cl_device_exec_capabilities>() = CL_EXEC_KERNEL;
314      break;
315
316   case CL_DEVICE_QUEUE_PROPERTIES:
317      buf.as_scalar<cl_command_queue_properties>() = CL_QUEUE_PROFILING_ENABLE;
318      break;
319
320   case CL_DEVICE_BUILT_IN_KERNELS:
321      buf.as_string() = "";
322      break;
323
324   case CL_DEVICE_NAME:
325      buf.as_string() = dev.device_name();
326      break;
327
328   case CL_DEVICE_VENDOR:
329      buf.as_string() = dev.vendor_name();
330      break;
331
332   case CL_DRIVER_VERSION:
333      buf.as_string() = PACKAGE_VERSION;
334      break;
335
336   case CL_DEVICE_PROFILE:
337      buf.as_string() = "FULL_PROFILE";
338      break;
339
340   case CL_DEVICE_VERSION:
341      buf.as_string() = "OpenCL " + dev.device_version_as_string() + " Mesa " PACKAGE_VERSION MESA_GIT_SHA1;
342      break;
343
344   case CL_DEVICE_EXTENSIONS:
345      buf.as_string() = dev.supported_extensions_as_string();
346      break;
347
348   case CL_DEVICE_PLATFORM:
349      buf.as_scalar<cl_platform_id>() = desc(dev.platform);
350      break;
351
352   case CL_DEVICE_HOST_UNIFIED_MEMORY:
353      buf.as_scalar<cl_bool>() = dev.has_unified_memory();
354      break;
355
356   case CL_DEVICE_NATIVE_VECTOR_WIDTH_CHAR:
357      buf.as_scalar<cl_uint>() = 16;
358      break;
359
360   case CL_DEVICE_NATIVE_VECTOR_WIDTH_SHORT:
361      buf.as_scalar<cl_uint>() = 8;
362      break;
363
364   case CL_DEVICE_NATIVE_VECTOR_WIDTH_INT:
365      buf.as_scalar<cl_uint>() = 4;
366      break;
367
368   case CL_DEVICE_NATIVE_VECTOR_WIDTH_LONG:
369      buf.as_scalar<cl_uint>() = 2;
370      break;
371
372   case CL_DEVICE_NATIVE_VECTOR_WIDTH_FLOAT:
373      buf.as_scalar<cl_uint>() = 4;
374      break;
375
376   case CL_DEVICE_NATIVE_VECTOR_WIDTH_DOUBLE:
377      buf.as_scalar<cl_uint>() = dev.has_doubles() ? 2 : 0;
378      break;
379
380   case CL_DEVICE_NATIVE_VECTOR_WIDTH_HALF:
381      buf.as_scalar<cl_uint>() = dev.has_halves() ? 8 : 0;
382      break;
383
384   case CL_DEVICE_OPENCL_C_VERSION:
385      buf.as_string() = "OpenCL C " + dev.device_clc_version_as_string() + " ";
386      break;
387
388   case CL_DEVICE_PRINTF_BUFFER_SIZE:
389      buf.as_scalar<size_t>() = dev.max_printf_buffer_size();
390      break;
391
392   case CL_DEVICE_PREFERRED_INTEROP_USER_SYNC:
393      buf.as_scalar<cl_bool>() = CL_TRUE;
394      break;
395
396   case CL_DEVICE_PARENT_DEVICE:
397      buf.as_scalar<cl_device_id>() = NULL;
398      break;
399
400   case CL_DEVICE_PARTITION_MAX_SUB_DEVICES:
401      buf.as_scalar<cl_uint>() = 0;
402      break;
403
404   case CL_DEVICE_PARTITION_PROPERTIES:
405      buf.as_vector<cl_device_partition_property>() =
406         desc(property_list<cl_device_partition_property>());
407      break;
408
409   case CL_DEVICE_PARTITION_AFFINITY_DOMAIN:
410      buf.as_scalar<cl_device_affinity_domain>() = 0;
411      break;
412
413   case CL_DEVICE_PARTITION_TYPE:
414      buf.as_vector<cl_device_partition_property>() =
415         desc(property_list<cl_device_partition_property>());
416      break;
417
418   case CL_DEVICE_REFERENCE_COUNT:
419      buf.as_scalar<cl_uint>() = 1;
420      break;
421
422   case CL_DEVICE_SVM_CAPABILITIES:
423   case CL_DEVICE_SVM_CAPABILITIES_ARM:
424      buf.as_scalar<cl_device_svm_capabilities>() = dev.svm_support();
425      break;
426
427   case CL_DEVICE_NUMERIC_VERSION:
428      buf.as_scalar<cl_version>() = dev.device_version();
429      break;
430
431   case CL_DEVICE_OPENCL_C_NUMERIC_VERSION_KHR:
432      buf.as_scalar<cl_version>() = dev.device_clc_version(true);
433      break;
434
435   case CL_DEVICE_OPENCL_C_ALL_VERSIONS:
436      buf.as_vector<cl_name_version>() = dev.opencl_c_all_versions();
437      break;
438
439   case CL_DEVICE_EXTENSIONS_WITH_VERSION:
440      buf.as_vector<cl_name_version>() = dev.supported_extensions();
441      break;
442
443   case CL_DEVICE_OPENCL_C_FEATURES:
444      buf.as_vector<cl_name_version>() = dev.opencl_c_features();
445      break;
446
447   case CL_DEVICE_IL_VERSION:
448      if (dev.supported_extensions_as_string().find("cl_khr_il_program") == std::string::npos)
449         throw error(CL_INVALID_VALUE);
450      buf.as_string() = supported_il_versions_as_string(dev);
451      break;
452
453   case CL_DEVICE_ILS_WITH_VERSION:
454      buf.as_vector<cl_name_version>() = dev.supported_il_versions();
455      break;
456
457   case CL_DEVICE_BUILT_IN_KERNELS_WITH_VERSION:
458      buf.as_vector<cl_name_version>() = std::vector<cl_name_version>{};
459      break;
460
461   case CL_DEVICE_MAX_READ_WRITE_IMAGE_ARGS:
462   case CL_DEVICE_IMAGE_PITCH_ALIGNMENT:
463   case CL_DEVICE_IMAGE_BASE_ADDRESS_ALIGNMENT:
464   case CL_DEVICE_PREFERRED_PLATFORM_ATOMIC_ALIGNMENT:
465   case CL_DEVICE_PREFERRED_GLOBAL_ATOMIC_ALIGNMENT:
466   case CL_DEVICE_PREFERRED_LOCAL_ATOMIC_ALIGNMENT:
467   case CL_DEVICE_MAX_NUM_SUB_GROUPS:
468   case CL_DEVICE_QUEUE_ON_DEVICE_PREFERRED_SIZE:
469   case CL_DEVICE_QUEUE_ON_DEVICE_MAX_SIZE:
470   case CL_DEVICE_MAX_ON_DEVICE_QUEUES:
471   case CL_DEVICE_MAX_ON_DEVICE_EVENTS:
472   case CL_DEVICE_MAX_PIPE_ARGS:
473   case CL_DEVICE_PIPE_MAX_ACTIVE_RESERVATIONS:
474   case CL_DEVICE_PIPE_MAX_PACKET_SIZE:
475      buf.as_scalar<cl_uint>() = 0;
476      break;
477
478   case CL_DEVICE_MAX_GLOBAL_VARIABLE_SIZE:
479   case CL_DEVICE_GLOBAL_VARIABLE_PREFERRED_TOTAL_SIZE:
480      buf.as_scalar<size_t>() = 0;
481      break;
482
483   case CL_DEVICE_SUB_GROUP_INDEPENDENT_FORWARD_PROGRESS:
484   case CL_DEVICE_NON_UNIFORM_WORK_GROUP_SUPPORT:
485   case CL_DEVICE_WORK_GROUP_COLLECTIVE_FUNCTIONS_SUPPORT:
486   case CL_DEVICE_GENERIC_ADDRESS_SPACE_SUPPORT:
487   case CL_DEVICE_PIPE_SUPPORT:
488      buf.as_scalar<cl_bool>() = CL_FALSE;
489      break;
490
491   case CL_DEVICE_QUEUE_ON_DEVICE_PROPERTIES:
492      buf.as_scalar<cl_command_queue_properties>() = 0;
493      break;
494
495   case CL_DEVICE_ATOMIC_MEMORY_CAPABILITIES:
496      buf.as_scalar<cl_device_atomic_capabilities>() = (CL_DEVICE_ATOMIC_ORDER_RELAXED |
497                                                        CL_DEVICE_ATOMIC_SCOPE_WORK_GROUP);
498      break;
499   case CL_DEVICE_ATOMIC_FENCE_CAPABILITIES:
500      buf.as_scalar<cl_device_atomic_capabilities>() = (CL_DEVICE_ATOMIC_ORDER_RELAXED |
501                                                        CL_DEVICE_ATOMIC_ORDER_ACQ_REL |
502                                                        CL_DEVICE_ATOMIC_SCOPE_WORK_GROUP);
503      break;
504
505   case CL_DEVICE_DEVICE_ENQUEUE_CAPABILITIES:
506      buf.as_scalar<cl_device_device_enqueue_capabilities>() = 0;
507      break;
508
509   case CL_DEVICE_PREFERRED_WORK_GROUP_SIZE_MULTIPLE:
510      buf.as_scalar<size_t>() = 1;
511      break;
512
513   case CL_DEVICE_LATEST_CONFORMANCE_VERSION_PASSED:
514      buf.as_string() = "";
515      break;
516
517   default:
518      throw error(CL_INVALID_VALUE);
519   }
520
521   return CL_SUCCESS;
522
523} catch (error &e) {
524   return e.get();
525}
526