У меня есть следующее простое ядро OpenCL, которое просто копирует все записи, указанные в a, в b
__kernel void mmcopy(__global float* a, __global float* b) {
unsigned pos = get_global_id(0);
b[pos] = a[pos];
}
В следующем фрагменте кода показаны вызовы функций opencl для создания объекта буферной памяти из четырех чисел с плавающей запятой, и установка первого аргумента в ядре с буферным объектом.
let mut v = [1f32, 1f32, 1f32, 1f32];
let size = mem::size_of_val(&v) as size_t;
let mut error_buffer = 0 as i32;
let buffer = unsafe {
clCreateBuffer(
context.id.unwrap(),
(CL_MEM_COPY_HOST_PTR | CL_MEM_READ_WRITE) as u64,
size,
v.as_mut_ptr() as *mut c_void,
&mut error_buffer,
)
};
let real_size = mem::size_of::<cl_mem>() as size_t;
let error = unsafe {
clSetKernelArg(
self.id.unwrap(), // here `self` is a wrapper. `id` is of type `cl_kernel`
0 as cl_uint,
real_size,
buffer as *const c_void,
)
};
Однако выполнение кода приводит к ошибке CL_INVALID_MEM_OBJECT
. похоже, что создание буфера не удалось, но вернулся без ошибки.
spe c также не очень точен, когда нужно более подробно описать ошибку:
для аргумента, объявленного как память объект, когда указанное arg_value не является допустимым объектом памяти.
note : функции и типы OpenCL были созданы с помощью rust-bindgen.
update 1
Чтобы прояснить, как непрозрачные типы представлены в ржавчине, вот представление cl_mem,
pub struct _cl_mem {
_unused: [u8; 0],
}
pub type cl_mem = *mut _cl_mem;
ffi для clSetKernelArg
extern "C" {
pub fn clSetKernelArg(
kernel: cl_kernel,
arg_index: cl_uint,
arg_size: size_t,
arg_value: *const ::std::os::raw::c_void,
) -> cl_int;
}
и clCreateBuffer
extern "C" {
pub fn clCreateBuffer(
context: cl_context,
flags: cl_mem_flags,
size: size_t,
host_ptr: *mut ::std::os::raw::c_void,
errcode_ret: *mut cl_int,
) -> cl_mem;
}
В моем понимании rust (-bindgen) использует типы нулевого размера (ZST) для представления внешних непрозрачных типов . Таким образом, в основном cl_mem уже является указателем.
update 2
Согласно ответу pmdj правильный путь - передать указатель на cl_mem buffer
let error = unsafe {
clSetKernelArg(
self.id.unwrap(), // here `self` is a wrapper. `id` is of type `cl_kernel`
0 as cl_uint,
real_size,
&buffer as *const _ as *const c_void,
)
};
Это фактически решает проблему и устанавливает возвращаемое значение на CL_SUCCESS
. В spe c для clSetKernelArg также упоминается указатель на данные
Указатель на данные, которые следует использовать в качестве значения аргумента для аргумента, указанного в arg_index. Данные аргумента, на которые указывает arg_value, копируются, и поэтому указатель arg_value может повторно использоваться приложением после возврата clSetKernelArg. Указанное значение аргумента - это значение, используемое всеми вызовами API, которые ставят ядро в очередь (clEnqueueNDRangeKernel), до тех пор, пока значение аргумента не будет изменено путем вызова clSetKernelArg для ядра [...]