cl3/
kernel.rs

1// Copyright (c) 2020-2025 Via Technology Ltd.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//    http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! `OpenCL` Kernel Object API.
16
17#![allow(unused_unsafe)]
18#![allow(non_camel_case_types)]
19#![allow(
20    clippy::not_unsafe_ptr_arg_deref,
21    clippy::too_many_lines,
22    clippy::wildcard_in_or_patterns
23)]
24
25pub use opencl_sys::{
26    CL_INVALID_VALUE, CL_KERNEL_ARG_ACCESS_NONE, CL_KERNEL_ARG_ACCESS_QUALIFIER,
27    CL_KERNEL_ARG_ACCESS_READ_ONLY, CL_KERNEL_ARG_ACCESS_READ_WRITE,
28    CL_KERNEL_ARG_ACCESS_WRITE_ONLY, CL_KERNEL_ARG_ADDRESS_CONSTANT, CL_KERNEL_ARG_ADDRESS_GLOBAL,
29    CL_KERNEL_ARG_ADDRESS_LOCAL, CL_KERNEL_ARG_ADDRESS_PRIVATE, CL_KERNEL_ARG_ADDRESS_QUALIFIER,
30    CL_KERNEL_ARG_NAME, CL_KERNEL_ARG_TYPE_CONST, CL_KERNEL_ARG_TYPE_NAME, CL_KERNEL_ARG_TYPE_NONE,
31    CL_KERNEL_ARG_TYPE_PIPE, CL_KERNEL_ARG_TYPE_QUALIFIER, CL_KERNEL_ARG_TYPE_RESTRICT,
32    CL_KERNEL_ARG_TYPE_VOLATILE, CL_KERNEL_ATTRIBUTES, CL_KERNEL_COMPILE_NUM_SUB_GROUPS,
33    CL_KERNEL_COMPILE_WORK_GROUP_SIZE, CL_KERNEL_CONTEXT,
34    CL_KERNEL_EXEC_INFO_SVM_FINE_GRAIN_SYSTEM, CL_KERNEL_EXEC_INFO_SVM_PTRS,
35    CL_KERNEL_FUNCTION_NAME, CL_KERNEL_GLOBAL_WORK_SIZE, CL_KERNEL_LOCAL_MEM_SIZE,
36    CL_KERNEL_LOCAL_SIZE_FOR_SUB_GROUP_COUNT, CL_KERNEL_MAX_NUM_SUB_GROUPS,
37    CL_KERNEL_MAX_SUB_GROUP_SIZE_FOR_NDRANGE, CL_KERNEL_NUM_ARGS,
38    CL_KERNEL_PREFERRED_WORK_GROUP_SIZE_MULTIPLE, CL_KERNEL_PRIVATE_MEM_SIZE, CL_KERNEL_PROGRAM,
39    CL_KERNEL_REFERENCE_COUNT, CL_KERNEL_SUB_GROUP_COUNT_FOR_NDRANGE, CL_KERNEL_WORK_GROUP_SIZE,
40    CL_SUCCESS, cl_device_id, cl_int, cl_kernel, cl_kernel_arg_access_qualifier,
41    cl_kernel_arg_info, cl_kernel_exec_info, cl_kernel_info, cl_kernel_sub_group_info,
42    cl_kernel_work_group_info, cl_program, cl_uint, cl_ulong,
43};
44
45use super::info_type::InfoType;
46use super::{
47    api_info_size, api_info_value, api_info_vector, api2_info_size, api2_info_value,
48    api2_info_vector,
49};
50use libc::{c_void, intptr_t, size_t};
51use std::ffi::CStr;
52use std::mem;
53use std::ptr;
54
55/// Create an `OpenCL` kernel object for a program with a successfully built executable.
56/// Calls clCreateKernel to create an `OpenCL` kernel object.
57///
58/// * `program` - a valid `OpenCL` program.
59/// * `kernel_name` - a kernel function name in the program.
60///
61/// returns a Result containing the new `OpenCL` kernel object
62/// or the error code from the `OpenCL` C API function.
63#[inline]
64pub fn create_kernel(program: cl_program, kernel_name: &CStr) -> Result<cl_kernel, cl_int> {
65    let mut status: cl_int = CL_INVALID_VALUE;
66    let kernel: cl_kernel = unsafe {
67        cl_call!(clCreateKernel(
68            program,
69            kernel_name.as_ptr(),
70            &raw mut status
71        ))
72    };
73    if CL_SUCCESS == status {
74        Ok(kernel)
75    } else {
76        Err(status)
77    }
78}
79
80fn count_kernels_in_program(program: cl_program) -> Result<cl_uint, cl_int> {
81    let mut count: cl_uint = 0;
82    let status: cl_int = unsafe {
83        cl_call!(clCreateKernelsInProgram(
84            program,
85            0,
86            ptr::null_mut(),
87            &raw mut count
88        ))
89    };
90    if CL_SUCCESS == status {
91        Ok(count)
92    } else {
93        Err(status)
94    }
95}
96
97/// Create `OpenCL` kernel objects for all kernel functions in a program.
98/// Calls clCreateKernelsInProgram to create `OpenCL` kernel objects.
99///
100/// * `program` - a valid `OpenCL` program.
101///
102/// returns a Result containing the new `OpenCL` kernel objects
103/// or the error code from the `OpenCL` C API function.
104#[inline]
105pub fn create_kernels_in_program(program: cl_program) -> Result<Vec<cl_kernel>, cl_int> {
106    let count: cl_uint = count_kernels_in_program(program)?;
107    let mut kernels: Vec<cl_kernel> = Vec::with_capacity(count as size_t);
108    let status: cl_int = unsafe {
109        kernels.set_len(count as size_t);
110        cl_call!(clCreateKernelsInProgram(
111            program,
112            count,
113            kernels.as_mut_ptr().cast::<cl_kernel>(),
114            ptr::null_mut(),
115        ))
116    };
117    if CL_SUCCESS == status {
118        Ok(kernels)
119    } else {
120        Err(status)
121    }
122}
123
124/// Clone an `OpenCL` kernel object.
125/// Calls clCloneKernel to clone an `OpenCL` kernel object.
126/// `CL_VERSION_2_1`
127///
128/// * `source_kernel` - a valid `OpenCL` `cl_kernel` object that will be copied.
129///
130/// returns a Result containing the new `OpenCL` kernel object
131/// or the error code from the `OpenCL` C API function.
132#[cfg(any(feature = "CL_VERSION_2_1", feature = "dynamic"))]
133#[inline]
134pub fn clone_kernel(source_kernel: cl_kernel) -> Result<cl_kernel, cl_int> {
135    let mut status: cl_int = CL_INVALID_VALUE;
136    let kernel: cl_kernel = unsafe { cl_call!(clCloneKernel(source_kernel, &raw mut status)) };
137    if CL_SUCCESS == status {
138        Ok(kernel)
139    } else {
140        Err(status)
141    }
142}
143
144/// Retain an `OpenCL` kernel.
145/// Calls clRetainKernel to increment the kernel reference count.
146///
147/// * `program` - the `OpenCL` kernel.
148///
149/// returns an empty Result or the error code from the `OpenCL` C API function.
150///
151/// # Safety
152///
153/// This function is unsafe because it changes the `OpenCL` object reference count.
154#[inline]
155pub unsafe fn retain_kernel(kernel: cl_kernel) -> Result<(), cl_int> {
156    let status: cl_int = cl_call!(clRetainKernel(kernel));
157    if CL_SUCCESS == status {
158        Ok(())
159    } else {
160        Err(status)
161    }
162}
163
164/// Release an `OpenCL` kernel.
165/// Calls clReleaseKernel to decrement the kernel reference count.
166///
167/// * `kernel` - the `OpenCL` kernel.
168///
169/// returns an empty Result or the error code from the `OpenCL` C API function.
170///
171/// # Safety
172///
173/// This function is unsafe because it changes the `OpenCL` object reference count.
174#[inline]
175pub unsafe fn release_kernel(kernel: cl_kernel) -> Result<(), cl_int> {
176    let status: cl_int = cl_call!(clReleaseKernel(kernel));
177    if CL_SUCCESS == status {
178        Ok(())
179    } else {
180        Err(status)
181    }
182}
183
184/// Set the argument value for a specific argument of a kernel.
185/// Calls clSetKernelArg.
186///
187/// * `kernel` - the `OpenCL` kernel.
188/// * `arg_index` - the kernel argument index.
189/// * `arg_ptr` - pointer to the data for the argument at `arg_index`.
190///
191/// returns an empty Result or the error code from the `OpenCL` C API function.
192///
193/// # Safety
194///
195/// This function is unsafe because arg must match the kernel argument.
196#[inline]
197pub unsafe fn set_kernel_arg(
198    kernel: cl_kernel,
199    arg_index: cl_uint,
200    arg_size: size_t,
201    arg_value: *const c_void,
202) -> Result<(), cl_int> {
203    let status: cl_int = cl_call!(clSetKernelArg(kernel, arg_index, arg_size, arg_value));
204    if CL_SUCCESS == status {
205        Ok(())
206    } else {
207        Err(status)
208    }
209}
210
211/// Set set a SVM pointer as the argument value for a specific argument of a kernel.
212/// Calls clSetKernelArgSVMPointer.
213///
214/// * `kernel` - the `OpenCL` kernel.
215/// * `arg_index` - the kernel argument index.
216/// * `arg_ptr` - the SVM pointer to the data for the argument at `arg_index`.
217///
218/// returns an empty Result or the error code from the `OpenCL` C API function.
219///
220/// # Safety
221///
222/// This function is unsafe because arg must match the kernel argument.
223#[cfg(any(feature = "CL_VERSION_2_0", feature = "dynamic"))]
224#[inline]
225pub unsafe fn set_kernel_arg_svm_pointer(
226    kernel: cl_kernel,
227    arg_index: cl_uint,
228    arg_ptr: *const c_void,
229) -> Result<(), cl_int> {
230    let status: cl_int = cl_call!(clSetKernelArgSVMPointer(kernel, arg_index, arg_ptr));
231    if CL_SUCCESS == status {
232        Ok(())
233    } else {
234        Err(status)
235    }
236}
237
238/// Pass additional information other than argument values to a kernel.
239/// Calls clSetKernelExecInfo.
240///
241/// * `kernel` - the `OpenCL` kernel.
242/// * `param_name` - the information to be passed to kernel, see:
243///   [Kernel Execution Properties](https://www.khronos.org/registry/OpenCL/specs/3.0-unified/html/OpenCL_API.html#kernel-exec-info-table).
244/// * `param_ptr` - pointer to the data for the `param_name`.
245///
246/// returns an empty Result or the error code from the `OpenCL` C API function.
247///
248/// # Safety
249///
250/// This function is unsafe because param must match the kernel argument.
251#[cfg(any(feature = "CL_VERSION_2_0", feature = "dynamic"))]
252#[inline]
253pub unsafe fn set_kernel_exec_info(
254    kernel: cl_kernel,
255    param_name: cl_kernel_exec_info,
256    param_value_size: size_t,
257    param_value: *const c_void,
258) -> Result<(), cl_int> {
259    let status: cl_int = cl_call!(clSetKernelExecInfo(
260        kernel,
261        param_name,
262        param_value_size,
263        param_value
264    ));
265    if CL_SUCCESS == status {
266        Ok(())
267    } else {
268        Err(status)
269    }
270}
271
272/// Get data about an `OpenCL` kernel.
273/// Calls clGetKernelInfo to get the desired data about the kernel.
274pub fn get_kernel_data(kernel: cl_kernel, param_name: cl_kernel_info) -> Result<Vec<u8>, cl_int> {
275    api_info_size!(get_size, clGetKernelInfo);
276    let size = get_size(kernel, param_name)?;
277    api_info_vector!(get_vector, u8, clGetKernelInfo);
278    get_vector(kernel, param_name, size)
279}
280
281/// Get specific information about an `OpenCL` kernel.
282/// Calls clGetKernelInfo to get the desired information about the kernel.
283///
284/// * `kernel` - the `OpenCL` kernel.
285/// * `param_name` - the type of kernel information being queried, see:
286///   [Kernel Object Queries](https://www.khronos.org/registry/OpenCL/specs/3.0-unified/html/OpenCL_API.html#kernel-info-table).
287///
288/// returns a Result containing the desired information in an `InfoType` enum
289/// or the error code from the `OpenCL` C API function.
290pub fn get_kernel_info(kernel: cl_kernel, param_name: cl_kernel_info) -> Result<InfoType, cl_int> {
291    match param_name {
292        CL_KERNEL_NUM_ARGS | CL_KERNEL_REFERENCE_COUNT => {
293            api_info_value!(get_value, cl_uint, clGetKernelInfo);
294            Ok(InfoType::Uint(get_value(kernel, param_name)?))
295        }
296
297        CL_KERNEL_CONTEXT | CL_KERNEL_PROGRAM => {
298            api_info_value!(get_value, intptr_t, clGetKernelInfo);
299            Ok(InfoType::Ptr(get_value(kernel, param_name)?))
300        }
301        CL_KERNEL_FUNCTION_NAME | CL_KERNEL_ATTRIBUTES | _ => {
302            Ok(InfoType::VecUchar(get_kernel_data(kernel, param_name)?))
303        }
304    }
305}
306
307/// Get data about arguments of an `OpenCL` kernel.
308/// Calls clGetKernelArgInfo to get the desired data about arguments of the kernel.
309#[cfg(any(feature = "CL_VERSION_1_2", feature = "dynamic"))]
310pub fn get_kernel_arg_data(
311    kernel: cl_kernel,
312    arg_indx: cl_uint,
313    param_name: cl_kernel_arg_info,
314) -> Result<Vec<u8>, cl_int> {
315    api2_info_size!(get_size, cl_uint, clGetKernelArgInfo);
316    let size = get_size(kernel, arg_indx, param_name)?;
317    api2_info_vector!(get_vector, cl_uint, u8, clGetKernelArgInfo);
318    get_vector(kernel, arg_indx, param_name, size)
319}
320
321/// Get specific information about arguments of an `OpenCL` kernel.
322/// Calls clGetKernelArgInfo to get the desired information about the kernel.
323///
324/// * `kernel` - the `OpenCL` kernel.
325/// * `arg_index` - the kernel argument index.
326/// * `param_name` - the type of kernel information being queried, see:
327///   [Kernel Argument Queries](https://www.khronos.org/registry/OpenCL/specs/3.0-unified/html/OpenCL_API.html#kernel-argument-info-table).
328///
329/// returns a Result containing the desired information in an `InfoType` enum
330/// or the error code from the `OpenCL` C API function.
331#[cfg(any(feature = "CL_VERSION_1_2", feature = "dynamic"))]
332pub fn get_kernel_arg_info(
333    kernel: cl_kernel,
334    arg_indx: cl_uint,
335    param_name: cl_kernel_arg_info,
336) -> Result<InfoType, cl_int> {
337    match param_name {
338        CL_KERNEL_ARG_ADDRESS_QUALIFIER | CL_KERNEL_ARG_ACCESS_QUALIFIER => {
339            api2_info_value!(get_index_value, cl_uint, cl_uint, clGetKernelArgInfo);
340            Ok(InfoType::Uint(get_index_value(
341                kernel, arg_indx, param_name,
342            )?))
343        }
344
345        CL_KERNEL_ARG_TYPE_QUALIFIER => {
346            api2_info_value!(get_index_value, cl_uint, cl_ulong, clGetKernelArgInfo);
347            Ok(InfoType::Ulong(get_index_value(
348                kernel, arg_indx, param_name,
349            )?))
350        }
351
352        CL_KERNEL_ARG_TYPE_NAME | CL_KERNEL_ARG_NAME | _ => Ok(InfoType::VecUchar(
353            get_kernel_arg_data(kernel, arg_indx, param_name)?,
354        )),
355    }
356}
357
358/// Get data about work groups of an `OpenCL` kernel.
359/// Calls clGetKernelArgInfo to get the desired data about work groups of the kernel.
360pub fn get_kernel_work_group_data(
361    kernel: cl_kernel,
362    device: cl_device_id,
363    param_name: cl_kernel_work_group_info,
364) -> Result<Vec<u8>, cl_int> {
365    api2_info_size!(get_size, cl_device_id, clGetKernelWorkGroupInfo);
366    let size = get_size(kernel, device, param_name)?;
367    api2_info_vector!(get_vector, cl_device_id, u8, clGetKernelWorkGroupInfo);
368    get_vector(kernel, device, param_name, size)
369}
370
371/// Get specific information about work groups of an `OpenCL` kernel.
372/// Calls clGetKernelWorkGroupInfo to get the desired information about the kernel.
373///
374/// * `kernel` - the `OpenCL` kernel.
375/// * `device` - a specific device in the list of devices associated with kernel.
376/// * `param_name` - the type of kernel information being queried, see:
377///   [Kernel Object Device Queries](https://www.khronos.org/registry/OpenCL/specs/3.0-unified/html/OpenCL_API.html#kernel-workgroup-info-table).
378///
379/// returns a Result containing the desired information in an `InfoType` enum
380/// or the error code from the `OpenCL` C API function.
381pub fn get_kernel_work_group_info(
382    kernel: cl_kernel,
383    device: cl_device_id,
384    param_name: cl_kernel_work_group_info,
385) -> Result<InfoType, cl_int> {
386    match param_name {
387        CL_KERNEL_WORK_GROUP_SIZE | CL_KERNEL_PREFERRED_WORK_GROUP_SIZE_MULTIPLE => {
388            api2_info_value!(
389                get_index_value,
390                cl_device_id,
391                size_t,
392                clGetKernelWorkGroupInfo
393            );
394            Ok(InfoType::Size(get_index_value(kernel, device, param_name)?))
395        }
396
397        CL_KERNEL_COMPILE_WORK_GROUP_SIZE | CL_KERNEL_GLOBAL_WORK_SIZE => {
398            api2_info_size!(get_device_size, cl_device_id, clGetKernelWorkGroupInfo);
399            api2_info_vector!(
400                get_device_vec,
401                cl_device_id,
402                size_t,
403                clGetKernelWorkGroupInfo
404            );
405            let size = get_device_size(kernel, device, param_name)?;
406            Ok(InfoType::VecSize(get_device_vec(
407                kernel, device, param_name, size,
408            )?))
409        }
410
411        CL_KERNEL_LOCAL_MEM_SIZE | CL_KERNEL_PRIVATE_MEM_SIZE => {
412            api2_info_value!(
413                get_index_value,
414                cl_device_id,
415                cl_ulong,
416                clGetKernelWorkGroupInfo
417            );
418            Ok(InfoType::Ulong(get_index_value(
419                kernel, device, param_name,
420            )?))
421        }
422
423        _ => Ok(InfoType::VecUchar(get_kernel_work_group_data(
424            kernel, device, param_name,
425        )?)),
426    }
427}
428
429/// Get specific information about sub groups of an `OpenCL` kernel.
430/// Calls clGetKernelSubGroupInfo to get the desired information about the kernel.
431/// `CL_VERSION_2_1`
432///
433/// * `kernel` - the `OpenCL` kernel.
434/// * `device` - a specific device in the list of devices associated with kernel.
435/// * `param_name` - the type of kernel information being queried, see:
436///   [Kernel Object Subgroup Queries](https://www.khronos.org/registry/OpenCL/specs/3.0-unified/html/OpenCL_API.html#kernel-subgroup-info-table).
437/// * `input_value_size` - the size in bytes of memory pointed to by `input_value`.
438/// * `input_value` -  pointer to memory where the appropriate parameterization
439///   of the query is passed from.
440///
441/// returns a Result containing the desired information in an `InfoType` enum
442/// or the error code from the `OpenCL` C API function.
443#[cfg(any(feature = "CL_VERSION_2_1", feature = "dynamic"))]
444pub fn get_kernel_sub_group_info(
445    kernel: cl_kernel,
446    device: cl_device_id,
447    param_name: cl_kernel_sub_group_info,
448    input_value_size: size_t,
449    input_value: *const c_void,
450) -> Result<InfoType, cl_int> {
451    let mut size: size_t = mem::size_of::<size_t>();
452    match param_name {
453        CL_KERNEL_MAX_SUB_GROUP_SIZE_FOR_NDRANGE
454        | CL_KERNEL_SUB_GROUP_COUNT_FOR_NDRANGE
455        | CL_KERNEL_MAX_NUM_SUB_GROUPS
456        | CL_KERNEL_COMPILE_NUM_SUB_GROUPS => {
457            // get the value
458            let mut data: size_t = 0;
459            let data_ptr: *mut size_t = &raw mut data;
460            let status = unsafe {
461                cl_call!(clGetKernelSubGroupInfo(
462                    kernel,
463                    device,
464                    param_name,
465                    input_value_size,
466                    input_value,
467                    size,
468                    data_ptr.cast::<c_void>(),
469                    ptr::null_mut(),
470                ))
471            };
472            if CL_SUCCESS == status {
473                Ok(InfoType::Size(data))
474            } else {
475                Err(status)
476            }
477        }
478
479        CL_KERNEL_LOCAL_SIZE_FOR_SUB_GROUP_COUNT => {
480            // get the size
481            let status: cl_int = unsafe {
482                cl_call!(clGetKernelSubGroupInfo(
483                    kernel,
484                    device,
485                    param_name,
486                    input_value_size,
487                    input_value,
488                    0,
489                    ptr::null_mut(),
490                    &raw mut size,
491                ))
492            };
493            if CL_SUCCESS == status {
494                // Get the information.
495                let count = size / mem::size_of::<size_t>();
496                let mut data: Vec<size_t> = Vec::with_capacity(count);
497                let status = unsafe {
498                    data.set_len(count);
499                    cl_call!(clGetKernelSubGroupInfo(
500                        kernel,
501                        device,
502                        param_name,
503                        input_value_size,
504                        input_value,
505                        size,
506                        data.as_mut_ptr().cast::<c_void>(),
507                        ptr::null_mut(),
508                    ))
509                };
510                if CL_SUCCESS == status {
511                    Ok(InfoType::VecSize(data))
512                } else {
513                    Err(status)
514                }
515            } else {
516                Err(status)
517            }
518        }
519
520        _ => {
521            // get the size
522            let status: cl_int = unsafe {
523                cl_call!(clGetKernelSubGroupInfo(
524                    kernel,
525                    device,
526                    param_name,
527                    input_value_size,
528                    input_value,
529                    0,
530                    ptr::null_mut(),
531                    &raw mut size,
532                ))
533            };
534            if CL_SUCCESS == status {
535                // Get the information.
536                let count = size / mem::size_of::<u8>();
537                let mut data: Vec<u8> = Vec::with_capacity(count);
538                let status = unsafe {
539                    data.set_len(count);
540                    cl_call!(clGetKernelSubGroupInfo(
541                        kernel,
542                        device,
543                        param_name,
544                        input_value_size,
545                        input_value,
546                        size,
547                        data.as_mut_ptr().cast::<c_void>(),
548                        ptr::null_mut(),
549                    ))
550                };
551                if CL_SUCCESS == status {
552                    Ok(InfoType::VecUchar(data))
553                } else {
554                    Err(status)
555                }
556            } else {
557                Err(status)
558            }
559        }
560    }
561}
562
563#[cfg(test)]
564mod tests {
565    use super::*;
566    use crate::context::{create_context, release_context};
567    use crate::device::{CL_DEVICE_TYPE_GPU, get_device_ids};
568    use crate::error_codes::error_text;
569    use crate::platform::get_platform_ids;
570    use crate::program::{build_program, create_program_with_source, release_program};
571    use std::ffi::CString;
572
573    #[test]
574    fn test_kernel() {
575        let platform_ids = get_platform_ids().unwrap();
576
577        // Choose the first platform
578        let platform_id = platform_ids[0];
579
580        let device_ids = get_device_ids(platform_id, CL_DEVICE_TYPE_GPU).unwrap();
581        assert!(0 < device_ids.len());
582
583        let device_id = device_ids[0];
584
585        let context = create_context(&device_ids, ptr::null(), None, ptr::null_mut());
586        let context = context.unwrap();
587
588        let source = r#"
589            kernel void saxpy_float (global float* z,
590                global float const* x,
591                global float const* y,
592                float a)
593            {
594            size_t i = get_global_id(0);
595            z[i] = a*x[i] + y[i];
596            }
597        "#;
598
599        // Convert source to an array
600        let sources = [source];
601        let program = create_program_with_source(context, &sources).unwrap();
602
603        let options = CString::new("-cl-kernel-arg-info").unwrap();
604        build_program(program, &device_ids, &options, None, ptr::null_mut()).unwrap();
605
606        let kernel_name = "saxpy_float";
607        let name = CString::new(kernel_name).unwrap();
608        let kernel = create_kernel(program, &name).unwrap();
609
610        let value = get_kernel_info(kernel, CL_KERNEL_FUNCTION_NAME).unwrap();
611        let value = String::from(value);
612        println!("CL_KERNEL_FUNCTION_NAME: {}", value);
613        assert!(0 < value.len());
614
615        let value = get_kernel_info(kernel, CL_KERNEL_NUM_ARGS).unwrap();
616        let value = cl_uint::from(value);
617        println!("CL_KERNEL_NUM_ARGS: {}", value);
618        assert!(0 < value);
619
620        let value = get_kernel_info(kernel, CL_KERNEL_REFERENCE_COUNT).unwrap();
621        let value = cl_uint::from(value);
622        println!("CL_KERNEL_REFERENCE_COUNT: {}", value);
623        assert!(0 < value);
624
625        let value = get_kernel_info(kernel, CL_KERNEL_CONTEXT).unwrap();
626        let value = intptr_t::from(value);
627        println!("CL_KERNEL_CONTEXT: {}", value);
628        assert!(0 < value);
629
630        let value = get_kernel_info(kernel, CL_KERNEL_PROGRAM).unwrap();
631        let value = intptr_t::from(value);
632        println!("CL_KERNEL_PROGRAM: {}", value);
633        assert!(0 < value);
634
635        let value = get_kernel_info(kernel, CL_KERNEL_ATTRIBUTES).unwrap();
636        let value = String::from(value);
637        println!("CL_KERNEL_ATTRIBUTES: {}", value);
638
639        #[cfg(any(feature = "CL_VERSION_1_2", feature = "dynamic"))]
640        match get_kernel_arg_info(kernel, 0, CL_KERNEL_ARG_ADDRESS_QUALIFIER) {
641            Ok(value) => {
642                let value = cl_uint::from(value);
643                println!("CL_KERNEL_ARG_ADDRESS_QUALIFIER: {:X}", value)
644            }
645            Err(e) => println!(
646                "OpenCL error, CL_KERNEL_ARG_ADDRESS_QUALIFIER: {}",
647                error_text(e)
648            ),
649        }
650
651        #[cfg(any(feature = "CL_VERSION_1_2", feature = "dynamic"))]
652        match get_kernel_arg_info(kernel, 0, CL_KERNEL_ARG_ACCESS_QUALIFIER) {
653            Ok(value) => {
654                let value = cl_uint::from(value);
655                println!("CL_KERNEL_ARG_ACCESS_QUALIFIER: {:X}", value)
656            }
657            Err(e) => println!(
658                "OpenCL error, CL_KERNEL_ARG_ACCESS_QUALIFIER: {}",
659                error_text(e)
660            ),
661        }
662
663        #[cfg(any(feature = "CL_VERSION_1_2", feature = "dynamic"))]
664        match get_kernel_arg_info(kernel, 0, CL_KERNEL_ARG_TYPE_NAME) {
665            Ok(value) => {
666                let value = String::from(value);
667                println!("CL_KERNEL_ARG_TYPE_NAME: {}", value);
668                assert!(0 < value.len())
669            }
670            Err(e) => println!("OpenCL error, CL_KERNEL_ARG_TYPE_NAME: {}", error_text(e)),
671        }
672
673        #[cfg(any(feature = "CL_VERSION_1_2", feature = "dynamic"))]
674        match get_kernel_arg_info(kernel, 0, CL_KERNEL_ARG_TYPE_QUALIFIER) {
675            Ok(value) => {
676                let value = cl_ulong::from(value);
677                println!("CL_KERNEL_ARG_TYPE_QUALIFIER: {:X}", value)
678            }
679            Err(e) => println!(
680                "OpenCL error, CL_KERNEL_ARG_TYPE_QUALIFIER: {}",
681                error_text(e)
682            ),
683        }
684
685        #[cfg(any(feature = "CL_VERSION_1_2", feature = "dynamic"))]
686        match get_kernel_arg_info(kernel, 0, CL_KERNEL_ARG_NAME) {
687            Ok(value) => {
688                let value = String::from(value);
689                println!("CL_KERNEL_ARG_NAME: {}", value);
690                assert!(0 < value.len())
691            }
692            Err(e) => println!("OpenCL error, CL_KERNEL_ARG_NAME: {}", error_text(e)),
693        }
694
695        let value =
696            get_kernel_work_group_info(kernel, device_id, CL_KERNEL_WORK_GROUP_SIZE).unwrap();
697        let value = size_t::from(value);
698        println!("CL_KERNEL_WORK_GROUP_SIZE: {}", value);
699
700        let value =
701            get_kernel_work_group_info(kernel, device_id, CL_KERNEL_COMPILE_WORK_GROUP_SIZE)
702                .unwrap();
703        let value = Vec::<size_t>::from(value);
704        println!("CL_KERNEL_COMPILE_WORK_GROUP_SIZE: {}", value.len());
705
706        let value =
707            get_kernel_work_group_info(kernel, device_id, CL_KERNEL_LOCAL_MEM_SIZE).unwrap();
708        let value = cl_ulong::from(value);
709        println!("CL_KERNEL_LOCAL_MEM_SIZE: {}", value);
710
711        let value = get_kernel_work_group_info(
712            kernel,
713            device_id,
714            CL_KERNEL_PREFERRED_WORK_GROUP_SIZE_MULTIPLE,
715        )
716        .unwrap();
717        let value = size_t::from(value);
718        println!("CL_KERNEL_PREFERRED_WORK_GROUP_SIZE_MULTIPLE: {}", value);
719
720        let value =
721            get_kernel_work_group_info(kernel, device_id, CL_KERNEL_PRIVATE_MEM_SIZE).unwrap();
722        let value = cl_ulong::from(value);
723        println!("CL_KERNEL_PRIVATE_MEM_SIZE: {}", value);
724
725        match get_kernel_work_group_info(kernel, device_id, CL_KERNEL_GLOBAL_WORK_SIZE) {
726            Ok(value) => {
727                let value = Vec::<size_t>::from(value);
728                println!("CL_KERNEL_GLOBAL_WORK_SIZE: {}", value.len())
729            }
730            Err(e) => println!(
731                "OpenCL error, CL_KERNEL_GLOBAL_WORK_SIZE: {}",
732                error_text(e)
733            ),
734        }
735
736        unsafe {
737            release_kernel(kernel).unwrap();
738            release_program(program).unwrap();
739            release_context(context).unwrap();
740        }
741    }
742}