1#![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#[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#[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#[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#[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#[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#[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#[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#[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
272pub 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
281pub 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#[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#[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
358pub 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
371pub 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#[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 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 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 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 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 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 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 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}