This crate introduces zero-cost wrapper types for safe OpenCL. There are 2 wrapper types it introduces...
MapKernel
wrapper for ocl::Kernel
MapProgram
wrapper for ocl::Program
Currently, this is quite a limited set of types. Some of its limitations...
This is really just a skeleton for adding new things like generics, new wrapper types, subtypes that can eliminate undefined behavior in OpenCL usage.
This is how you would normally implement an adding map operation.
```rust let src = r#" kernel void add(global float* buffer, float scalar) { buffer[getglobalid(0)] += scalar; } "#;
// (1) Define which platform and device(s) to use. Create a context,
// queue, and program then define some dims (compare to step 1 above).
let platform = Platform::default();
let device = Device::first(platform).unwrap();
let context = Context::builder()
.platform(platform)
.devices(device.clone())
.build().unwrap();
let program = Program::builder()
.devices(device)
.src(src)
.build(&context).unwrap();
let queue = Queue::new(&context, device, None).unwrap();
let dims = 1 << 20;
// [NOTE]: At this point we could manually assemble a ProQue by calling:
// ProQue::new(context, queue, program, Some(dims))
. One might want to
// do this when only one program and queue are all that's needed. Wrapping
// it up into a single struct makes passing it around simpler.
// (2) Create a Buffer
:
let buffer = Buffer::
// (3) Create a kernel with arguments matching those in the source above: let kernel = Kernel::builder() .program(&program) .name("add") .queue(queue.clone()) .globalworksize(dims) .arg(&buffer) .arg(&10.0f32) .build().unwrap();
// (4) Run the kernel (default parameters shown for demonstration purposes): unsafe { kernel.cmd() .queue(&queue) .globalworkoffset(kernel.defaultglobalworkoffset()) .globalworksize(dims) .localworksize(kernel.defaultlocalworksize()) .enq().unwrap(); }
// (5) Read results from the device into a vector (::block
not shown):
let mut vec = vec![0.0f32; dims];
buffer.cmd()
.queue(&queue)
.offset(0)
.read(&mut vec)
.enq().unwrap();
assert_eq!(vec, vec![10.0f32; dims]); ```
This is how you do it with the above types.
``rust
// (1) Define which platform and device(s) to use. Create a context,
// queue, and program then define some dims (compare to step 1 above).
let platform = Platform::default();
let device = Device::first(platform).unwrap();
let context = Context::builder()
.platform(platform)
.devices(device.clone())
.build().unwrap();
let program = MapProgram::from(device, Op::Add, &context).unwrap();
let queue = Queue::new(&context, device, None).unwrap();
let dims = 1 << 20;
// [NOTE]: At this point we could manually assemble a ProQue by calling:
//
ProQue::new(context, queue, program, Some(dims))`. One might want to
// do this when only one program and queue are all that's needed. Wrapping
// it up into a single struct makes passing it around simpler.
// (2) Create a Buffer
:
let buffer = Buffer::
// (3) Create a kernel with arguments matching those in the source above: let kernel = MapKernel::from(&program, queue.clone(), &buffer, &10.0f32).unwrap();
// (4) Run the kernel (default parameters shown for demonstration purposes): kernel.cmd_enq(&queue);
// (5) Read results from the device into a vector (::block
not shown):
let mut vec = vec![0.0f32; dims];
buffer.cmd()
.queue(&queue)
.offset(0)
.read(&mut vec)
.enq().unwrap();
assert_eq!(vec, vec![10.0f32; dims]); ```