xref: /aosp_15_r20/external/mesa3d/src/gallium/frontends/clover/core/device.cpp (revision 6104692788411f58d303aa86923a9ff6ecaded22)
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 <algorithm>
24 #include "core/device.hpp"
25 #include "core/platform.hpp"
26 #include "pipe/p_screen.h"
27 #include "pipe/p_state.h"
28 #include "util/bitscan.h"
29 #include "util/disk_cache.h"
30 #include "util/u_debug.h"
31 #include "nir.h"
32 #include <fstream>
33 
34 #ifdef HAVE_CLOVER_SPIRV
35 #include "spirv/invocation.hpp"
36 #include "nir/invocation.hpp"
37 #endif
38 
39 using namespace clover;
40 
41 namespace {
42    template<typename T>
43    std::vector<T>
get_compute_param(pipe_screen * pipe,pipe_shader_ir ir_format,pipe_compute_cap cap)44    get_compute_param(pipe_screen *pipe, pipe_shader_ir ir_format,
45                      pipe_compute_cap cap) {
46       int sz = pipe->get_compute_param(pipe, ir_format, cap, NULL);
47       std::vector<T> v(sz / sizeof(T));
48 
49       pipe->get_compute_param(pipe, ir_format, cap, &v.front());
50       return v;
51    }
52 
53    cl_version
get_highest_supported_version(const device & dev)54    get_highest_supported_version(const device &dev) {
55       // All the checks below assume that the device supports FULL_PROFILE
56       // (which is the only profile support by clover) and that a device is
57       // not CUSTOM.
58       assert(dev.type() != CL_DEVICE_TYPE_CUSTOM);
59 
60       cl_version version = CL_MAKE_VERSION(0, 0, 0);
61 
62       const auto has_extension =
63          [extensions = dev.supported_extensions()](const char *extension_name){
64             return std::find_if(extensions.begin(), extensions.end(),
65                   [extension_name](const cl_name_version &extension){
66                      return strcmp(extension.name, extension_name) == 0;
67                }) != extensions.end();
68       };
69       const bool supports_images = dev.image_support();
70 
71       // Check requirements for OpenCL 1.0
72       if (dev.max_compute_units() < 1 ||
73           dev.max_block_size().size() < 3 ||
74           // TODO: Check CL_DEVICE_MAX_WORK_ITEM_SIZES
75           dev.max_threads_per_block() < 1 ||
76           (dev.address_bits() != 32 && dev.address_bits() != 64) ||
77           dev.max_mem_alloc_size() < std::max(dev.max_mem_global() / 4,
78                                               (cl_ulong)128 * 1024 * 1024) ||
79           dev.max_mem_input() < 256 ||
80           dev.max_const_buffer_size() < 64 * 1024 ||
81           dev.max_const_buffers() < 8 ||
82           dev.max_mem_local() < 16 * 1024 ||
83           dev.clc_version < CL_MAKE_VERSION(1, 0, 0)) {
84          return version;
85       }
86       version = CL_MAKE_VERSION(1, 0, 0);
87 
88       // Check requirements for OpenCL 1.1
89       if (!has_extension("cl_khr_byte_addressable_store") ||
90           !has_extension("cl_khr_global_int32_base_atomics") ||
91           !has_extension("cl_khr_global_int32_extended_atomics") ||
92           !has_extension("cl_khr_local_int32_base_atomics") ||
93           !has_extension("cl_khr_local_int32_extended_atomics") ||
94           // OpenCL 1.1 increased the minimum value for
95           // CL_DEVICE_MAX_PARAMETER_SIZE to 1024 bytes.
96           dev.max_mem_input() < 1024 ||
97           dev.mem_base_addr_align() < sizeof(cl_long16) ||
98           // OpenCL 1.1 increased the minimum value for
99           // CL_DEVICE_LOCAL_MEM_SIZE to 32 KB.
100           dev.max_mem_local() < 32 * 1024 ||
101           dev.clc_version < CL_MAKE_VERSION(1, 1, 0)) {
102          return version;
103       }
104       version = CL_MAKE_VERSION(1, 1, 0);
105 
106       // Check requirements for OpenCL 1.2
107       if ((dev.has_doubles() && !has_extension("cl_khr_fp64")) ||
108           dev.clc_version < CL_MAKE_VERSION(1, 2, 0) ||
109           dev.max_printf_buffer_size() < 1 * 1024 * 1024 ||
110           (supports_images &&
111            (dev.max_image_buffer_size()  < 65536 ||
112             dev.max_image_array_number() < 2048))) {
113          return version;
114       }
115       version = CL_MAKE_VERSION(1, 2, 0);
116 
117       // Check requirements for OpenCL 3.0
118       if (dev.max_mem_alloc_size() < std::max(std::min((cl_ulong)1024 * 1024 * 1024,
119                                                        dev.max_mem_global() / 4),
120                                               (cl_ulong)128 * 1024 * 1024) ||
121           // TODO: If pipes are supported, check:
122           //       * CL_DEVICE_MAX_PIPE_ARGS
123           //       * CL_DEVICE_PIPE_MAX_ACTIVE_RESERVATIONS
124           //       * CL_DEVICE_PIPE_MAX_PACKET_SIZE
125           // TODO: If on-device queues are supported, check:
126           //       * CL_DEVICE_QUEUE_ON_DEVICE_PROPERTIES
127           //       * CL_DEVICE_QUEUE_ON_DEVICE_PREFERRED_SIZE
128           //       * CL_DEVICE_QUEUE_ON_DEVICE_MAX_SIZE
129           //       * CL_DEVICE_MAX_ON_DEVICE_QUEUES
130           //       * CL_DEVICE_MAX_ON_DEVICE_EVENTS
131           dev.clc_version < CL_MAKE_VERSION(3, 0, 0) ||
132           (supports_images &&
133            (dev.max_images_write() < 64 ||
134             dev.max_image_size() < 16384))) {
135          return version;
136       }
137       version = CL_MAKE_VERSION(3, 0, 0);
138 
139       return version;
140    }
141 
142    static cl_device_type
parse_env_device_type()143    parse_env_device_type() {
144       const char* val = getenv("CLOVER_DEVICE_TYPE");
145       if (!val) {
146          return 0;
147       }
148       if (strcmp(val, "cpu") == 0) {
149          return CL_DEVICE_TYPE_CPU;
150       }
151       if (strcmp(val, "gpu") == 0) {
152          return CL_DEVICE_TYPE_GPU;
153       }
154       if (strcmp(val, "accelerator") == 0) {
155          return CL_DEVICE_TYPE_ACCELERATOR;
156       }
157       /* CL_DEVICE_TYPE_CUSTOM isn't implemented
158       because CL_DEVICE_TYPE_CUSTOM is OpenCL 1.2
159       and Clover is OpenCL 1.1. */
160       return 0;
161    }
162 }
163 
device(clover::platform & platform,pipe_loader_device * ldev)164 device::device(clover::platform &platform, pipe_loader_device *ldev) :
165    platform(platform), clc_cache(NULL), ldev(ldev) {
166    pipe = pipe_loader_create_screen(ldev, false);
167    if (pipe && pipe->get_param(pipe, PIPE_CAP_COMPUTE)) {
168       const bool has_supported_ir = supports_ir(PIPE_SHADER_IR_NATIVE) ||
169                                     supports_ir(PIPE_SHADER_IR_NIR_SERIALIZED);
170       if (has_supported_ir) {
171          unsigned major = 1, minor = 1;
172          debug_get_version_option("CLOVER_DEVICE_CLC_VERSION_OVERRIDE",
173                                   &major, &minor);
174          clc_version = CL_MAKE_VERSION(major, minor, 0);
175 
176          version = get_highest_supported_version(*this);
177          major = CL_VERSION_MAJOR(version);
178          minor = CL_VERSION_MINOR(version);
179          debug_get_version_option("CLOVER_DEVICE_VERSION_OVERRIDE", &major,
180                                   &minor);
181          version = CL_MAKE_VERSION(major, minor, 0);
182 
183       }
184 
185       if (supports_ir(PIPE_SHADER_IR_NATIVE))
186          return;
187 #ifdef HAVE_CLOVER_SPIRV
188       if (supports_ir(PIPE_SHADER_IR_NIR_SERIALIZED)) {
189          nir::check_for_libclc(*this);
190          clc_cache = nir::create_clc_disk_cache();
191          clc_nir = lazy<std::shared_ptr<nir_shader>>([&] () { std::string log; return std::shared_ptr<nir_shader>(nir::load_libclc_nir(*this, log), ralloc_free); });
192          return;
193       }
194 #endif
195    }
196    if (pipe)
197       pipe->destroy(pipe);
198    throw error(CL_INVALID_DEVICE);
199 }
200 
~device()201 device::~device() {
202    if (clc_cache)
203       disk_cache_destroy(clc_cache);
204    if (pipe)
205       pipe->destroy(pipe);
206    if (ldev)
207       pipe_loader_release(&ldev, 1);
208 }
209 
210 bool
operator ==(const device & dev) const211 device::operator==(const device &dev) const {
212    return this == &dev;
213 }
214 
215 cl_device_type
type() const216 device::type() const {
217    cl_device_type type = parse_env_device_type();
218    if (type != 0) {
219       return type;
220    }
221 
222    switch (ldev->type) {
223    case PIPE_LOADER_DEVICE_SOFTWARE:
224       return CL_DEVICE_TYPE_CPU;
225    case PIPE_LOADER_DEVICE_PCI:
226    case PIPE_LOADER_DEVICE_PLATFORM:
227       return CL_DEVICE_TYPE_GPU;
228    default:
229       unreachable("Unknown device type.");
230    }
231 }
232 
233 cl_uint
vendor_id() const234 device::vendor_id() const {
235    switch (ldev->type) {
236    case PIPE_LOADER_DEVICE_SOFTWARE:
237    case PIPE_LOADER_DEVICE_PLATFORM:
238       return 0;
239    case PIPE_LOADER_DEVICE_PCI:
240       return ldev->u.pci.vendor_id;
241    default:
242       unreachable("Unknown device type.");
243    }
244 }
245 
246 size_t
max_images_read() const247 device::max_images_read() const {
248    return pipe->get_shader_param(pipe, PIPE_SHADER_COMPUTE,
249                                  PIPE_SHADER_CAP_MAX_SAMPLER_VIEWS);
250 }
251 
252 size_t
max_images_write() const253 device::max_images_write() const {
254    return pipe->get_shader_param(pipe, PIPE_SHADER_COMPUTE,
255                                  PIPE_SHADER_CAP_MAX_SHADER_IMAGES);
256 }
257 
258 size_t
max_image_buffer_size() const259 device::max_image_buffer_size() const {
260    return pipe->get_param(pipe, PIPE_CAP_MAX_TEXEL_BUFFER_ELEMENTS_UINT);
261 }
262 
263 cl_uint
max_image_size() const264 device::max_image_size() const {
265    return pipe->get_param(pipe, PIPE_CAP_MAX_TEXTURE_2D_SIZE);
266 }
267 
268 cl_uint
max_image_size_3d() const269 device::max_image_size_3d() const {
270    return 1 << (pipe->get_param(pipe, PIPE_CAP_MAX_TEXTURE_3D_LEVELS) - 1);
271 }
272 
273 size_t
max_image_array_number() const274 device::max_image_array_number() const {
275    return pipe->get_param(pipe, PIPE_CAP_MAX_TEXTURE_ARRAY_LAYERS);
276 }
277 
278 cl_uint
max_samplers() const279 device::max_samplers() const {
280    return pipe->get_shader_param(pipe, PIPE_SHADER_COMPUTE,
281                                  PIPE_SHADER_CAP_MAX_TEXTURE_SAMPLERS);
282 }
283 
284 cl_ulong
max_mem_global() const285 device::max_mem_global() const {
286    return get_compute_param<uint64_t>(pipe, ir_format(),
287                                       PIPE_COMPUTE_CAP_MAX_GLOBAL_SIZE)[0];
288 }
289 
290 cl_ulong
max_mem_local() const291 device::max_mem_local() const {
292    return get_compute_param<uint64_t>(pipe, ir_format(),
293                                       PIPE_COMPUTE_CAP_MAX_LOCAL_SIZE)[0];
294 }
295 
296 cl_ulong
max_mem_input() const297 device::max_mem_input() const {
298    return get_compute_param<uint64_t>(pipe, ir_format(),
299                                       PIPE_COMPUTE_CAP_MAX_INPUT_SIZE)[0];
300 }
301 
302 cl_ulong
max_const_buffer_size() const303 device::max_const_buffer_size() const {
304    return pipe->get_shader_param(pipe, PIPE_SHADER_COMPUTE,
305                                  PIPE_SHADER_CAP_MAX_CONST_BUFFER0_SIZE);
306 }
307 
308 cl_uint
max_const_buffers() const309 device::max_const_buffers() const {
310    return pipe->get_shader_param(pipe, PIPE_SHADER_COMPUTE,
311                                  PIPE_SHADER_CAP_MAX_CONST_BUFFERS);
312 }
313 
314 size_t
max_threads_per_block() const315 device::max_threads_per_block() const {
316    return get_compute_param<uint64_t>(
317       pipe, ir_format(), PIPE_COMPUTE_CAP_MAX_THREADS_PER_BLOCK)[0];
318 }
319 
320 cl_ulong
max_mem_alloc_size() const321 device::max_mem_alloc_size() const {
322    return get_compute_param<uint64_t>(pipe, ir_format(),
323                                       PIPE_COMPUTE_CAP_MAX_MEM_ALLOC_SIZE)[0];
324 }
325 
326 cl_uint
max_clock_frequency() const327 device::max_clock_frequency() const {
328    return get_compute_param<uint32_t>(pipe, ir_format(),
329                                       PIPE_COMPUTE_CAP_MAX_CLOCK_FREQUENCY)[0];
330 }
331 
332 cl_uint
max_compute_units() const333 device::max_compute_units() const {
334    return get_compute_param<uint32_t>(pipe, ir_format(),
335                                       PIPE_COMPUTE_CAP_MAX_COMPUTE_UNITS)[0];
336 }
337 
338 cl_uint
max_printf_buffer_size() const339 device::max_printf_buffer_size() const {
340    return 1024 * 1024;
341 }
342 
343 bool
image_support() const344 device::image_support() const {
345    bool supports_images = get_compute_param<uint32_t>(pipe, ir_format(),
346                                                       PIPE_COMPUTE_CAP_IMAGES_SUPPORTED)[0];
347    if (!supports_images)
348       return false;
349 
350    /* If the gallium driver supports images, but does not support the
351     * minimum requirements for opencl 1.0 images, then don't claim to
352     * support images.
353     */
354    if (max_images_read() < 128 ||
355        max_images_write() < 8 ||
356        max_image_size() < 8192 ||
357        max_image_size_3d() < 2048 ||
358        max_samplers() < 16)
359       return false;
360 
361    return true;
362 }
363 
364 bool
has_doubles() const365 device::has_doubles() const {
366    nir_shader_compiler_options *options =
367          (nir_shader_compiler_options *)pipe->get_compiler_options(pipe,
368                                                                    PIPE_SHADER_IR_NIR,
369                                                                    PIPE_SHADER_COMPUTE);
370    return pipe->get_param(pipe, PIPE_CAP_DOUBLES) &&
371          !(options->lower_doubles_options & nir_lower_fp64_full_software);
372 }
373 
374 bool
has_halves() const375 device::has_halves() const {
376    return pipe->get_shader_param(pipe, PIPE_SHADER_COMPUTE,
377                                  PIPE_SHADER_CAP_FP16);
378 }
379 
380 bool
has_int64_atomics() const381 device::has_int64_atomics() const {
382    return pipe->get_shader_param(pipe, PIPE_SHADER_COMPUTE,
383                                  PIPE_SHADER_CAP_INT64_ATOMICS);
384 }
385 
386 bool
has_unified_memory() const387 device::has_unified_memory() const {
388    return pipe->get_param(pipe, PIPE_CAP_UMA);
389 }
390 
391 size_t
mem_base_addr_align() const392 device::mem_base_addr_align() const {
393    uint64_t page_size = 0;
394    os_get_page_size(&page_size);
395    return std::max((size_t)page_size, sizeof(cl_long) * 16);
396 }
397 
398 cl_device_svm_capabilities
svm_support() const399 device::svm_support() const {
400    // Without CAP_RESOURCE_FROM_USER_MEMORY SVM and CL_MEM_USE_HOST_PTR
401    // interactions won't work according to spec as clover manages a GPU side
402    // copy of the host data.
403    //
404    // The biggest problem are memory buffers created with CL_MEM_USE_HOST_PTR,
405    // but the application and/or the kernel updates the memory via SVM and not
406    // the cl_mem buffer.
407    // We can't even do proper tracking on what memory might have been accessed
408    // as the host ptr to the buffer could be within a SVM region, where through
409    // the CL API there is no reliable way of knowing if a certain cl_mem buffer
410    // was accessed by a kernel or not and the runtime can't reliably know from
411    // which side the GPU buffer content needs to be updated.
412    //
413    // Another unsolvable scenario is a cl_mem object passed by cl_mem reference
414    // and SVM pointer into the same kernel at the same time.
415    if (allows_user_pointers() && pipe->get_param(pipe, PIPE_CAP_SYSTEM_SVM))
416       // we can emulate all lower levels if we support fine grain system
417       return CL_DEVICE_SVM_FINE_GRAIN_SYSTEM |
418              CL_DEVICE_SVM_COARSE_GRAIN_BUFFER |
419              CL_DEVICE_SVM_FINE_GRAIN_BUFFER;
420    return 0;
421 }
422 
423 bool
allows_user_pointers() const424 device::allows_user_pointers() const {
425    return pipe->get_param(pipe, PIPE_CAP_RESOURCE_FROM_USER_MEMORY) ||
426           pipe->get_param(pipe, PIPE_CAP_RESOURCE_FROM_USER_MEMORY_COMPUTE_ONLY);
427 }
428 
429 std::vector<size_t>
max_block_size() const430 device::max_block_size() const {
431    auto v = get_compute_param<uint64_t>(pipe, ir_format(),
432                                         PIPE_COMPUTE_CAP_MAX_BLOCK_SIZE);
433    return { v.begin(), v.end() };
434 }
435 
436 cl_uint
subgroup_size() const437 device::subgroup_size() const {
438    cl_uint subgroup_sizes =
439       get_compute_param<uint32_t>(pipe, ir_format(), PIPE_COMPUTE_CAP_SUBGROUP_SIZES)[0];
440    if (!subgroup_sizes)
441       return 0;
442    return 1 << (util_last_bit(subgroup_sizes) - 1);
443 }
444 
445 cl_uint
address_bits() const446 device::address_bits() const {
447    return get_compute_param<uint32_t>(pipe, ir_format(),
448                                       PIPE_COMPUTE_CAP_ADDRESS_BITS)[0];
449 }
450 
451 std::string
device_name() const452 device::device_name() const {
453    return pipe->get_name(pipe);
454 }
455 
456 std::string
vendor_name() const457 device::vendor_name() const {
458    return pipe->get_device_vendor(pipe);
459 }
460 
461 enum pipe_shader_ir
ir_format() const462 device::ir_format() const {
463    if (supports_ir(PIPE_SHADER_IR_NATIVE))
464       return PIPE_SHADER_IR_NATIVE;
465 
466    assert(supports_ir(PIPE_SHADER_IR_NIR_SERIALIZED));
467    return PIPE_SHADER_IR_NIR_SERIALIZED;
468 }
469 
470 std::string
ir_target() const471 device::ir_target() const {
472    std::vector<char> target = get_compute_param<char>(
473       pipe, ir_format(), PIPE_COMPUTE_CAP_IR_TARGET);
474    return { target.data() };
475 }
476 
477 enum pipe_endian
endianness() const478 device::endianness() const {
479    return (enum pipe_endian)pipe->get_param(pipe, PIPE_CAP_ENDIANNESS);
480 }
481 
482 std::string
device_version_as_string() const483 device::device_version_as_string() const {
484    static const std::string version_string =
485       std::to_string(CL_VERSION_MAJOR(version)) + "." +
486       std::to_string(CL_VERSION_MINOR(version));
487    return version_string;
488 }
489 
490 std::string
device_clc_version_as_string() const491 device::device_clc_version_as_string() const {
492    int major = CL_VERSION_MAJOR(clc_version);
493    int minor = CL_VERSION_MINOR(clc_version);
494 
495    /* for CL 3.0 we need this to be 1.2 until we support 2.0. */
496    if (major == 3) {
497       major = 1;
498       minor = 2;
499    }
500    static const std::string version_string =
501       std::to_string(major) + "." +
502       std::to_string(minor);
503    return version_string;
504 }
505 
506 bool
supports_ir(enum pipe_shader_ir ir) const507 device::supports_ir(enum pipe_shader_ir ir) const {
508    return pipe->get_shader_param(pipe, PIPE_SHADER_COMPUTE,
509                                  PIPE_SHADER_CAP_SUPPORTED_IRS) & (1 << ir);
510 }
511 
512 std::vector<cl_name_version>
supported_extensions() const513 device::supported_extensions() const {
514    std::vector<cl_name_version> vec;
515 
516    vec.push_back( cl_name_version{ CL_MAKE_VERSION(1, 0, 0), "cl_khr_byte_addressable_store" } );
517    vec.push_back( cl_name_version{ CL_MAKE_VERSION(1, 0, 0), "cl_khr_global_int32_base_atomics" } );
518    vec.push_back( cl_name_version{ CL_MAKE_VERSION(1, 0, 0), "cl_khr_global_int32_extended_atomics" } );
519    vec.push_back( cl_name_version{ CL_MAKE_VERSION(1, 0, 0), "cl_khr_local_int32_base_atomics" } );
520    vec.push_back( cl_name_version{ CL_MAKE_VERSION(1, 0, 0), "cl_khr_local_int32_extended_atomics" } );
521    if (has_int64_atomics()) {
522       vec.push_back( cl_name_version{ CL_MAKE_VERSION(1, 0, 0), "cl_khr_int64_base_atomics" } );
523       vec.push_back( cl_name_version{ CL_MAKE_VERSION(1, 0, 0), "cl_khr_int64_extended_atomics" } );
524    }
525    if (has_doubles())
526       vec.push_back( cl_name_version{ CL_MAKE_VERSION(1, 0, 0), "cl_khr_fp64" } );
527    if (has_halves())
528       vec.push_back( cl_name_version{ CL_MAKE_VERSION(1, 0, 0), "cl_khr_fp16" } );
529    if (svm_support())
530       vec.push_back( cl_name_version{ CL_MAKE_VERSION(1, 0, 0), "cl_arm_shared_virtual_memory" } );
531 #ifdef HAVE_CLOVER_SPIRV
532    if (!clover::spirv::supported_versions().empty() &&
533        supports_ir(PIPE_SHADER_IR_NIR_SERIALIZED))
534       vec.push_back( cl_name_version{ CL_MAKE_VERSION(1, 0, 0), "cl_khr_il_program" } );
535 #endif
536    vec.push_back( cl_name_version{ CL_MAKE_VERSION(1, 0, 0), "cl_khr_extended_versioning" } );
537    return vec;
538 }
539 
540 std::string
supported_extensions_as_string() const541 device::supported_extensions_as_string() const {
542    static std::string extensions_string;
543 
544    if (!extensions_string.empty())
545       return extensions_string;
546 
547    const auto extension_list = supported_extensions();
548    for (const auto &extension : extension_list) {
549       if (!extensions_string.empty())
550          extensions_string += " ";
551       extensions_string += extension.name;
552    }
553    return extensions_string;
554 }
555 
556 std::vector<cl_name_version>
supported_il_versions() const557 device::supported_il_versions() const {
558 #ifdef HAVE_CLOVER_SPIRV
559    return clover::spirv::supported_versions();
560 #else
561    return {};
562 #endif
563 }
564 
565 const void *
get_compiler_options(enum pipe_shader_ir ir) const566 device::get_compiler_options(enum pipe_shader_ir ir) const {
567    return pipe->get_compiler_options(pipe, ir, PIPE_SHADER_COMPUTE);
568 }
569 
570 cl_version
device_version() const571 device::device_version() const {
572    return version;
573 }
574 
575 cl_version
device_clc_version(bool api) const576 device::device_clc_version(bool api) const {
577    /*
578     * For the API we have to limit this to 1.2,
579     * but internally we want 3.0 if it works.
580     */
581    if (!api)
582       return clc_version;
583 
584    int major = CL_VERSION_MAJOR(clc_version);
585    /* for CL 3.0 we need this to be 1.2 until we support 2.0. */
586    if (major == 3) {
587       return CL_MAKE_VERSION(1, 2, 0);
588    }
589    return clc_version;
590 }
591 
592 std::vector<cl_name_version>
opencl_c_all_versions() const593 device::opencl_c_all_versions() const {
594    std::vector<cl_name_version> vec;
595    vec.push_back( cl_name_version{ CL_MAKE_VERSION(1, 0, 0), "OpenCL C" } );
596    vec.push_back( cl_name_version{ CL_MAKE_VERSION(1, 1, 0), "OpenCL C" } );
597 
598    if (CL_VERSION_MAJOR(clc_version) == 1 &&
599        CL_VERSION_MINOR(clc_version) == 2)
600       vec.push_back( cl_name_version{ CL_MAKE_VERSION(1, 2, 0), "OpenCL C" } );
601    if (CL_VERSION_MAJOR(clc_version) == 3) {
602       vec.push_back( cl_name_version{ CL_MAKE_VERSION(1, 2, 0), "OpenCL C" } );
603       vec.push_back( cl_name_version{ CL_MAKE_VERSION(3, 0, 0), "OpenCL C" } );
604    }
605    return vec;
606 }
607 
608 std::vector<cl_name_version>
opencl_c_features() const609 device::opencl_c_features() const {
610    std::vector<cl_name_version> vec;
611 
612    vec.push_back( cl_name_version {CL_MAKE_VERSION(3, 0, 0), "__opencl_c_int64" });
613    if (has_doubles())
614       vec.push_back( cl_name_version {CL_MAKE_VERSION(3, 0, 0), "__opencl_c_fp64" });
615 
616    return vec;
617 }
618