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 
28 using namespace clover;
29 
30 namespace {
31    std::string
supported_il_versions_as_string(const device & dev)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 
47 CLOVER_API cl_int
clGetDeviceIDs(cl_platform_id d_platform,cl_device_type device_type,cl_uint num_entries,cl_device_id * rd_devices,cl_uint * rnum_devices)48 clGetDeviceIDs(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 
83 CLOVER_API cl_int
clCreateSubDevices(cl_device_id d_dev,const cl_device_partition_property * props,cl_uint num_devs,cl_device_id * rd_devs,cl_uint * rnum_devs)84 clCreateSubDevices(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 
92 CLOVER_API cl_int
clRetainDevice(cl_device_id d_dev)93 clRetainDevice(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 
103 CLOVER_API cl_int
clReleaseDevice(cl_device_id d_dev)104 clReleaseDevice(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 
114 CLOVER_API cl_int
clGetDeviceInfo(cl_device_id d_dev,cl_device_info param,size_t size,void * r_buf,size_t * r_size)115 clGetDeviceInfo(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