use std::ptr;
use std::mem;
use std::io::Read;
use std::ffi::CString;
use std::iter;
use std::thread;
use std::time::Duration;
use std::env;
use std::fmt::Debug;
use libc::{size_t, c_void};
use num::FromPrimitive;
use cl_h::{self, cl_bool, cl_int, cl_uint, cl_platform_id, cl_device_id, cl_device_type,
cl_device_info, cl_platform_info, cl_context, cl_context_info, cl_context_properties,
cl_image_format, cl_image_desc, cl_kernel, cl_program_build_info, cl_mem, cl_mem_info,
cl_mem_flags, cl_mem_object_type, cl_buffer_create_type, cl_event, cl_program,
cl_addressing_mode, cl_filter_mode, cl_command_queue_info, cl_command_queue, cl_image_info,
cl_sampler, cl_sampler_info, cl_program_info, cl_kernel_info, cl_kernel_arg_info,
cl_kernel_work_group_info, cl_event_info, cl_profiling_info};
use error::{Error as OclError, Result as OclResult};
use core::{self, OclPrm, PlatformId, DeviceId, Context, ContextProperties, ContextInfo,
ContextInfoResult, MemFlags, CommandQueue, Mem, MemObjectType, Program, Kernel,
ClEventPtrNew, Event, EventList, Sampler, KernelArg, DeviceType, ImageFormat,
ImageDescriptor, CommandExecutionStatus, AddressingMode, FilterMode, PlatformInfo,
PlatformInfoResult, DeviceInfo, DeviceInfoResult, CommandQueueInfo, CommandQueueInfoResult,
MemInfo, MemInfoResult, ImageInfo, ImageInfoResult, SamplerInfo, SamplerInfoResult,
ProgramInfo, ProgramInfoResult, ProgramBuildInfo, ProgramBuildInfoResult, KernelInfo,
KernelInfoResult, KernelArgInfo, KernelArgInfoResult, KernelWorkGroupInfo,
KernelWorkGroupInfoResult, ClEventRef, EventInfo, EventInfoResult, ProfilingInfo,
ProfilingInfoResult, CreateContextCallbackFn, UserDataPtr, ClPlatformIdPtr, ClDeviceIdPtr,
EventCallbackFn, BuildProgramCallbackFn, MemMigrationFlags, MapFlags, BufferRegion,
BufferCreateType};
const KERNEL_DEBUG_SLEEP_DURATION_MS: u64 = 150;
fn errcode_try(cl_fn_name: &'static str, fn_info: &str, errcode: cl_int) -> OclResult<()> {
OclError::err_status(errcode, cl_fn_name, fn_info)
}
fn resolve_event_ptrs<L: AsRef<EventList>>(wait_list: Option<L>,
new_event: Option<&mut ClEventPtrNew>) -> OclResult<(cl_uint, *const cl_event, *mut cl_event)>
{
let (wait_list_len, wait_list_ptr) = match wait_list {
Some(wl) => {
let wl = wl.as_ref();
if wl.count() > 0 {
(wl.count(), unsafe { wl.as_ptr_ptr() } )
} else {
(0, ptr::null_mut() as *const cl_event)
}
},
None => (0, ptr::null_mut() as *const cl_event),
};
let new_event_ptr = match new_event {
Some(ne) => try!(ne.ptr_mut_ptr_new()),
None => ptr::null_mut() as *mut cl_event,
};
Ok((wait_list_len, wait_list_ptr, new_event_ptr))
}
fn resolve_work_dims(work_dims: &Option<[usize; 3]>) -> *const size_t {
match work_dims {
&Some(ref w) => w as *const [usize; 3] as *const size_t,
&None => 0 as *const size_t,
}
}
pub fn program_build_err<D: ClDeviceIdPtr + Debug>(program: &Program, device_ids: &[D]) -> OclResult<()> {
if device_ids.len() == 0 {
return OclError::err("ocl::core::program_build_err(): Device list is empty. Aborting.");
}
for device_id in device_ids.iter() {
match get_program_build_info(program, device_id, ProgramBuildInfo::BuildLog) {
ProgramBuildInfoResult::BuildLog(log) => {
if log.len() > 1 {
let log_readable = format!(
"\n\n\
###################### OPENCL PROGRAM BUILD DEBUG OUTPUT ######################\
\n\n{}\n\
###############################################################################\
\n\n",
log);
return OclError::err(log_readable);
}
},
ProgramBuildInfoResult::Error(err) => return Err(*err),
_ => panic!("ocl::core::program_build_err(): Unexpected 'ProgramBuildInfoResult' variant."),
}
}
Ok(())
}
pub fn get_platform_ids() -> OclResult<Vec<PlatformId>> {
let mut num_platforms = 0 as cl_uint;
let mut errcode: cl_int = unsafe {
cl_h::clGetPlatformIDs(0, ptr::null_mut(), &mut num_platforms)
};
if cfg!(target_os = "windows") && errcode == cl_h::Status::CL_PLATFORM_NOT_FOUND_KHR as i32 {
let sleep_ms = 2000;
let mut iters_rmng = 5;
while errcode == cl_h::Status::CL_PLATFORM_NOT_FOUND_KHR as i32 {
if iters_rmng == 0 {
return OclError::err(format!("core::get_platform_ids(): \
CL_PLATFORM_NOT_FOUND_KHR... Unable to get platform id list after {} \
seconds of waiting.", (iters_rmng * sleep_ms) / 1000));
}
if cfg!(target_os="windows") {
thread::sleep(Duration::from_millis(sleep_ms));
}
errcode = unsafe {
cl_h::clGetPlatformIDs(0, ptr::null_mut(), &mut num_platforms)
};
iters_rmng -= 1;
}
}
try!(errcode_try("clGetPlatformIDs", "", errcode));
if num_platforms == 0 {
return Ok(vec![]);
}
let mut null_vec: Vec<usize> = iter::repeat(0).take(num_platforms as usize).collect();
let (ptr, len, cap) = (null_vec.as_mut_ptr(), null_vec.len(), null_vec.capacity());
let mut platforms: Vec<PlatformId> = unsafe {
mem::forget(null_vec);
Vec::from_raw_parts(ptr as *mut PlatformId, len, cap)
};
errcode = unsafe {
cl_h::clGetPlatformIDs(
num_platforms,
platforms.as_mut_ptr() as *mut cl_platform_id,
ptr::null_mut()
)
};
try!(errcode_try("clGetPlatformIDs", "", errcode));
Ok(platforms)
}
pub fn get_platform_info<P: ClPlatformIdPtr>(platform: Option<P>, request: PlatformInfo,
) -> PlatformInfoResult
{
let platform_ptr: cl_platform_id = match platform {
Some(p) => unsafe { p.as_ptr() },
None => ptr::null_mut() as cl_platform_id,
};
let mut result_size = 0 as size_t;
let errcode = unsafe {
cl_h::clGetPlatformInfo(
platform_ptr,
request as cl_platform_info,
0 as size_t,
ptr::null_mut(),
&mut result_size as *mut size_t,
)
};
if let Err(err) = errcode_try("clGetPlatformInfo", "", errcode) {
return PlatformInfoResult::Error(Box::new(err));
}
if result_size == 0 {
return PlatformInfoResult::from_bytes(request, Ok(vec![]));
}
let mut result: Vec<u8> = iter::repeat(32u8).take(result_size as usize).collect();
let errcode = unsafe {
cl_h::clGetPlatformInfo(
platform_ptr,
request as cl_platform_info,
result_size as size_t,
result.as_mut_ptr() as *mut c_void,
ptr::null_mut() as *mut size_t,
)
};
let result = errcode_try("clGetPlatformInfo", "", errcode).and(Ok(result));
PlatformInfoResult::from_bytes(request, result)
}
pub fn get_device_ids(
platform: &PlatformId,
device_types: Option<DeviceType>,
devices_max: Option<u32>,
) -> OclResult<Vec<DeviceId>>
{
let device_types = device_types.unwrap_or(try!(default_device_type()));
let mut devices_available: cl_uint = 0;
let devices_max = match devices_max {
Some(d) => {
if d == 0 {
return OclError::err("ocl::core::get_device_ids(): `devices_max` can not be zero.");
} else {
d
}
},
None => core::DEVICES_MAX,
};
let mut device_ids: Vec<DeviceId> = iter::repeat(unsafe { DeviceId::null() } )
.take(devices_max as usize).collect();
let errcode = unsafe { cl_h::clGetDeviceIDs(
platform.as_ptr(),
device_types.bits() as cl_device_type,
devices_max,
device_ids.as_mut_ptr() as *mut cl_device_id,
&mut devices_available,
) };
try!(errcode_try("clGetDeviceIDs", "", errcode));
unsafe { device_ids.set_len(devices_available as usize); }
device_ids.shrink_to_fit();
Ok(device_ids)
}
#[allow(unused_variables)]
pub fn get_device_info<D: ClDeviceIdPtr>(device: &D, request: DeviceInfo,
) -> DeviceInfoResult
{
let mut result_size: size_t = 0;
let errcode = unsafe { cl_h::clGetDeviceInfo(
device.as_ptr() as cl_device_id,
request as cl_device_info,
0 as size_t,
0 as *mut c_void,
&mut result_size as *mut size_t,
) };
if let Err(err) = errcode_try("clGetDeviceInfo", "", errcode) {
return DeviceInfoResult::Error(Box::new(err));
}
if result_size == 0 {
return DeviceInfoResult::from_bytes(request, Ok(vec![]));
}
let mut result: Vec<u8> = iter::repeat(0u8).take(result_size).collect();
let errcode = unsafe { cl_h::clGetDeviceInfo(
device.as_ptr() as cl_device_id,
request as cl_device_info,
result_size as size_t,
result.as_mut_ptr() as *mut _ as *mut c_void,
0 as *mut size_t,
) };
let result = errcode_try("clGetDeviceInfo", "", errcode).and(Ok(result));
DeviceInfoResult::from_bytes(request, result)
}
pub fn create_sub_devices() -> OclResult<()> {
unimplemented!();
}
pub unsafe fn retain_device(device: &DeviceId) -> OclResult<()> {
errcode_try("clRetainDevice", "", cl_h::clRetainDevice(device.as_ptr()))
}
pub unsafe fn release_device(device: &DeviceId) -> OclResult<()> {
errcode_try("clReleaseDevice", "", cl_h::clReleaseDevice(device.as_ptr()))
}
pub fn create_context<D: ClDeviceIdPtr>(properties: &Option<ContextProperties>, device_ids: &[D],
pfn_notify: Option<CreateContextCallbackFn>, user_data: Option<UserDataPtr>
) -> OclResult<Context>
{
if device_ids.len() == 0 {
return OclError::err("ocl::core::create_context(): No devices specified.");
}
let properties_bytes: Vec<u8> = match properties {
&Some(ref props) => props.to_bytes(),
&None => Vec::<u8>::with_capacity(0),
};
let properties_ptr = if properties_bytes.len() == 0 {
ptr::null() as *const cl_context_properties
} else {
ptr::null() as *const cl_context_properties
};
let user_data_ptr = match user_data {
Some(_) => ptr::null_mut(),
None => ptr::null_mut(),
};
let mut errcode: cl_int = 0;
let context = unsafe { Context::from_fresh_ptr(cl_h::clCreateContext(
properties_ptr,
device_ids.len() as cl_uint,
device_ids.as_ptr() as *const cl_device_id,
pfn_notify,
user_data_ptr,
&mut errcode,
)) };
errcode_try("clCreateContext", "", errcode).and(Ok(context))
}
pub fn create_context_from_type() -> OclResult<()> {
unimplemented!();
}
pub unsafe fn retain_context(context: &Context) -> OclResult<()> {
errcode_try("clRetainContext", "", cl_h::clRetainContext(context.as_ptr()))
}
pub unsafe fn release_context(context: &Context) -> OclResult<()> {
errcode_try("clReleaseContext", "", cl_h::clReleaseContext(context.as_ptr()))
}
pub fn get_context_info(context: &Context, request: ContextInfo)
-> ContextInfoResult
{
let mut result_size: size_t = 0;
let errcode = unsafe { cl_h::clGetContextInfo(
context.as_ptr() as cl_context,
request as cl_context_info,
0 as size_t,
0 as *mut c_void,
&mut result_size as *mut usize,
) };
if let Err(err) = errcode_try("clGetContextInfo", "", errcode) {
return ContextInfoResult::Error(Box::new(err));
}
if !cfg!(release) {
let err_if_zero_result_size = request as cl_context_info == cl_h::CL_CONTEXT_DEVICES;
if result_size > 10000 || (result_size == 0 && err_if_zero_result_size) {
return ContextInfoResult::Error(Box::new(OclError::new("\n\nocl::core::context_info(): \
Possible invalid context detected. \n\
Context info result size is either '> 10k bytes' or '== 0'. Almost certainly an \n\
invalid context object. If not, please file an issue at: \n\
https://github.com/cogciprocate/ocl/issues.\n\n")));
}
}
if result_size == 0 {
return ContextInfoResult::from_bytes(request, Ok(vec![]));
}
let mut result: Vec<u8> = iter::repeat(0).take(result_size).collect();
let errcode = unsafe { cl_h::clGetContextInfo(
context.as_ptr() as cl_context,
request as cl_context_info,
result_size as size_t,
result.as_mut_ptr() as *mut c_void,
0 as *mut usize,
) };
let result = errcode_try("clGetContextInfo", "", errcode).and(Ok(result));
ContextInfoResult::from_bytes(request, result)
}
pub fn create_command_queue<D: ClDeviceIdPtr>(
context: &Context,
device: &D,
) -> OclResult<CommandQueue>
{
try!(verify_context(context));
let mut errcode: cl_int = 0;
let cq = unsafe { CommandQueue::from_fresh_ptr(cl_h::clCreateCommandQueue(
context.as_ptr(),
device.as_ptr(),
cl_h::CL_QUEUE_PROFILING_ENABLE,
&mut errcode
)) };
errcode_try("clCreateCommandQueue", "", errcode).and(Ok(cq))
}
pub unsafe fn retain_command_queue(queue: &CommandQueue) -> OclResult<()> {
errcode_try("clRetainCommandQueue", "", cl_h::clRetainCommandQueue(queue.as_ptr()))
}
pub unsafe fn release_command_queue(queue: &CommandQueue) -> OclResult<()> {
errcode_try("clReleaseCommandQueue", "",
cl_h::clReleaseCommandQueue(queue.as_ptr()))
}
pub fn get_command_queue_info(queue: &CommandQueue, request: CommandQueueInfo,
) -> CommandQueueInfoResult
{
let mut result_size: size_t = 0;
let errcode = unsafe { cl_h::clGetCommandQueueInfo(
queue.as_ptr() as cl_command_queue,
request as cl_command_queue_info,
0 as size_t,
0 as *mut c_void,
&mut result_size as *mut size_t,
) };
if let Err(err) = errcode_try("clGetCommandQueueInfo", "", errcode) {
return CommandQueueInfoResult::Error(Box::new(err));
}
if result_size == 0 {
return CommandQueueInfoResult::from_bytes(request, Ok(vec![]));
}
let mut result: Vec<u8> = iter::repeat(0u8).take(result_size).collect();
let errcode = unsafe { cl_h::clGetCommandQueueInfo(
queue.as_ptr() as cl_command_queue,
request as cl_command_queue_info,
result_size,
result.as_mut_ptr() as *mut _ as *mut c_void,
0 as *mut size_t,
) };
let result = errcode_try("clGetCommandQueueInfo", "", errcode).and(Ok(result));
CommandQueueInfoResult::from_bytes(request, result)
}
pub unsafe fn create_buffer<T: OclPrm>(
context: &Context,
flags: MemFlags,
len: usize,
data: Option<&[T]>,
) -> OclResult<Mem>
{
try!(verify_context(context));
let mut errcode: cl_int = 0;
let host_ptr = match data {
Some(d) => {
if d.len() != len {
return OclError::err("ocl::create_buffer(): Data length mismatch.");
}
d.as_ptr() as cl_mem
},
None => ptr::null_mut(),
};
let buf_ptr = cl_h::clCreateBuffer(
context.as_ptr(),
flags.bits() as cl_mem_flags,
len * mem::size_of::<T>(),
host_ptr,
&mut errcode,
);
try!(errcode_try("clCreateBuffer", "", errcode));
debug_assert!(!buf_ptr.is_null());
Ok(Mem::from_fresh_ptr(buf_ptr))
}
pub fn create_sub_buffer(
buffer: &Mem,
flags: MemFlags,
buffer_create_info: &BufferRegion,
) -> OclResult<Mem>
{
let buffer_create_type = BufferCreateType::Region;
let mut errcode = 0i32;
let sub_buf_ptr = unsafe { cl_h::clCreateSubBuffer(
buffer.as_ptr(),
flags.bits(),
buffer_create_type as cl_buffer_create_type,
buffer_create_info as *const _ as *const c_void,
&mut errcode,
) };
try!(errcode_try("clCreateSubBuffer", "", errcode));
debug_assert!(!sub_buf_ptr.is_null());
unsafe { Ok(Mem::from_fresh_ptr(sub_buf_ptr)) }
}
pub unsafe fn create_image<T>(
context: &Context,
flags: MemFlags,
format: &ImageFormat,
desc: &ImageDescriptor,
data: Option<&[T]>,
) -> OclResult<Mem>
{
try!(verify_context(context));
let mut errcode: cl_int = 0;
let host_ptr = match data {
Some(d) => {
d.as_ptr() as cl_mem
},
None => ptr::null_mut(),
};
let image_ptr = cl_h::clCreateImage(
context.as_ptr(),
flags.bits() as cl_mem_flags,
&format.to_raw() as *const cl_image_format,
&desc.to_raw() as *const cl_image_desc,
host_ptr,
&mut errcode as *mut cl_int,
);
try!(errcode_try("clCreateImage", "", errcode));
debug_assert!(!image_ptr.is_null());
Ok(Mem::from_fresh_ptr(image_ptr))
}
pub unsafe fn retain_mem_object(mem: &Mem) -> OclResult<()> {
errcode_try("clRetainMemObject", "", cl_h::clRetainMemObject(mem.as_ptr()))
}
pub unsafe fn release_mem_object(mem: &Mem) -> OclResult<()> {
errcode_try("clReleaseMemObject", "", cl_h::clReleaseMemObject(mem.as_ptr()))
}
pub fn get_supported_image_formats(
context: &Context,
flags: MemFlags,
image_type: MemObjectType,
) -> OclResult<Vec<ImageFormat>>
{
let mut num_image_formats = 0 as cl_uint;
let errcode = unsafe { cl_h::clGetSupportedImageFormats(
context.as_ptr(),
flags.bits() as cl_mem_flags,
image_type as cl_mem_object_type,
0 as cl_uint,
ptr::null_mut() as *mut cl_image_format,
&mut num_image_formats as *mut cl_uint,
) };
try!(errcode_try("clGetSupportedImageFormats", "", errcode));
if num_image_formats == 0 {
return Ok(vec![]);
}
let mut image_formats: Vec<cl_image_format> = (0..(num_image_formats as usize)).map(|_| {
ImageFormat::new_raw()
} ).collect();
debug_assert!(image_formats.len() == num_image_formats as usize && image_formats.len() > 0);
let errcode = unsafe { cl_h::clGetSupportedImageFormats(
context.as_ptr(),
flags.bits() as cl_mem_flags,
image_type as cl_mem_object_type,
num_image_formats,
image_formats.as_mut_ptr() as *mut _ as *mut cl_image_format,
0 as *mut cl_uint,
) };
try!(errcode_try("clGetSupportedImageFormats", "", errcode));
ImageFormat::list_from_raw(image_formats)
}
pub fn get_mem_object_info(obj: &Mem, request: MemInfo) -> MemInfoResult {
let mut result_size: size_t = 0;
let errcode = unsafe { cl_h::clGetMemObjectInfo(
obj.as_ptr() as cl_mem,
request as cl_mem_info,
0 as size_t,
0 as *mut c_void,
&mut result_size as *mut size_t,
) };
if let Err(err) = errcode_try("clGetMemObjectInfo", "", errcode) {
return MemInfoResult::Error(Box::new(err));
}
if result_size == 0 {
return MemInfoResult::from_bytes(request, Ok(vec![]));
}
let mut result: Vec<u8> = iter::repeat(0u8).take(result_size).collect();
let errcode = unsafe { cl_h::clGetMemObjectInfo(
obj.as_ptr() as cl_mem,
request as cl_mem_info,
result_size,
result.as_mut_ptr() as *mut _ as *mut c_void,
0 as *mut size_t,
) };
let result = errcode_try("clGetMemObjectInfo", "", errcode).and(Ok(result));
MemInfoResult::from_bytes(request, result)
}
pub fn get_image_info(obj: &Mem, request: ImageInfo) -> ImageInfoResult {
let mut result_size: size_t = 0;
let errcode = unsafe { cl_h::clGetImageInfo(
obj.as_ptr() as cl_mem,
request as cl_image_info,
0 as size_t,
0 as *mut c_void,
&mut result_size as *mut size_t,
) };
if let Err(err) = errcode_try("clGetImageInfo", "", errcode) {
return ImageInfoResult::Error(Box::new(err));
}
if result_size == 0 {
return ImageInfoResult::from_bytes(request, Ok(vec![]));
}
let mut result: Vec<u8> = iter::repeat(0u8).take(result_size).collect();
let errcode = unsafe { cl_h::clGetImageInfo(
obj.as_ptr() as cl_mem,
request as cl_image_info,
result_size,
result.as_mut_ptr() as *mut _ as *mut c_void,
0 as *mut size_t,
) };
let result = errcode_try("clGetImageInfo", "", errcode).and(Ok(result));
ImageInfoResult::from_bytes(request, result)
}
pub fn set_mem_object_destructor_callback() -> OclResult<()> {
unimplemented!();
}
pub fn create_sampler(context: &Context, normalize_coords: bool, addressing_mode: AddressingMode,
filter_mode: FilterMode) -> OclResult<Sampler>
{
let mut errcode = 0;
let sampler = unsafe { Sampler::from_fresh_ptr(cl_h::clCreateSampler(
context.as_ptr(),
normalize_coords as cl_bool,
addressing_mode as cl_addressing_mode,
filter_mode as cl_filter_mode,
&mut errcode,
)) };
errcode_try("clCreateSampler", "", errcode).and(Ok(sampler))
}
pub unsafe fn retain_sampler(sampler: &Sampler) -> OclResult<()> {
errcode_try("clRetainSampler", "", cl_h::clRetainSampler(sampler.as_ptr()))
}
pub unsafe fn release_sampler(sampler: &Sampler) -> OclResult<()> {
errcode_try("clReleaseSampler", "", cl_h::clReleaseSampler(sampler.as_ptr()))
}
pub fn get_sampler_info(obj: &Sampler, request: SamplerInfo,
) -> SamplerInfoResult
{
let mut result_size: size_t = 0;
let errcode = unsafe { cl_h::clGetSamplerInfo(
obj.as_ptr() as cl_sampler,
request as cl_sampler_info,
0 as size_t,
0 as *mut c_void,
&mut result_size as *mut size_t,
) };
if let Err(err) = errcode_try("clGetSamplerInfo", "", errcode) {
return SamplerInfoResult::Error(Box::new(err));
}
if result_size == 0 {
return SamplerInfoResult::from_bytes(request, Ok(vec![]));
}
let mut result: Vec<u8> = iter::repeat(0u8).take(result_size).collect();
let errcode = unsafe { cl_h::clGetSamplerInfo(
obj.as_ptr() as cl_sampler,
request as cl_sampler_info,
result_size,
result.as_mut_ptr() as *mut _ as *mut c_void,
0 as *mut size_t,
) };
let result = errcode_try("clGetSamplerInfo", "", errcode).and(Ok(result));
SamplerInfoResult::from_bytes(request, result)
}
pub fn create_program_with_source(
context: &Context,
src_strings: &[CString],
) -> OclResult<Program>
{
try!(verify_context(context));
let ks_lens: Vec<usize> = src_strings.iter().map(|cs| cs.as_bytes().len()).collect();
let kern_string_ptrs: Vec<*const i8> = src_strings.iter().map(|cs| cs.as_ptr()).collect();
let mut errcode: cl_int = 0;
let program = unsafe { cl_h::clCreateProgramWithSource(
context.as_ptr(),
kern_string_ptrs.len() as cl_uint,
kern_string_ptrs.as_ptr() as *const *const i8,
ks_lens.as_ptr() as *const usize,
&mut errcode,
) };
try!(errcode_try("clCreateProgramWithSource", "", errcode));
unsafe { Ok(Program::from_fresh_ptr(program)) }
}
pub fn create_program_with_binary<D: ClDeviceIdPtr>(
context: &Context,
devices: &[D],
binaries: &[&[u8]],
) -> OclResult<(Program)>
{
if devices.len() == 0 { return OclError::err("ocl::create_program_with_binary: \
Length of 'devices' must be greater than zero."); }
if devices.len() != binaries.len() { return OclError::err("ocl::create_program_with_binary: \
Length of 'devices' must equal the length of 'binaries' (e.g. one binary per device)."); }
let lengths: Vec<usize> = binaries.iter().map(|bin| bin.len()).collect();
let mut binary_status: Vec<i32> = iter::repeat(0).take(devices.len()).collect();
let mut errcode: cl_int = 0;
let program = unsafe { cl_h::clCreateProgramWithBinary(
context.as_ptr(),
devices.len() as u32,
devices.as_ptr() as *const _ as *const cl_device_id,
lengths.as_ptr(),
binaries.as_ptr() as *const *const u8,
binary_status.as_mut_ptr(),
&mut errcode,
) };
try!(errcode_try("clCreateProgramWithBinary", "", errcode));
for i in 0..binary_status.len() {
try!(errcode_try("clCreateProgramWithBinary", &format!("(): Device [{}]", i), binary_status[i]));
}
unsafe { Ok(Program::from_fresh_ptr(program)) }
}
pub fn create_program_with_built_in_kernels() -> OclResult<()> {
unimplemented!();
}
pub unsafe fn retain_program(program: &Program) -> OclResult<()> {
errcode_try("clRetainProgram", "", cl_h::clRetainProgram(program.as_ptr()))
}
pub unsafe fn release_program(program: &Program) -> OclResult<()> {
errcode_try("clReleaseKernel", "", cl_h::clReleaseProgram(program.as_ptr()))
}
pub struct UserDataPh(usize);
impl UserDataPh {
fn unwrapped(&self) -> *mut c_void {
ptr::null_mut()
}
}
pub fn build_program<D: ClDeviceIdPtr + Debug>(
program: &Program,
devices: &[D],
options: &CString,
pfn_notify: Option<BuildProgramCallbackFn>,
user_data: Option<Box<UserDataPh>>,
) -> OclResult<()>
{
assert!(pfn_notify.is_none() && user_data.is_none(),
"ocl::core::build_program(): Callback functions not yet implemented.");
if devices.len() == 0 { return OclError::err("ocl::core::build_program: \
No devices specified."); }
let user_data = match user_data {
Some(ud) => ud.unwrapped(),
None => ptr::null_mut(),
};
let errcode = unsafe { cl_h::clBuildProgram(
program.as_ptr() as cl_program,
devices.len() as cl_uint,
devices.as_ptr() as *const cl_device_id,
options.as_ptr() as *const i8,
pfn_notify,
user_data,
) };
if errcode == cl_h::Status::CL_BUILD_PROGRAM_FAILURE as i32 {
program_build_err(program, devices)
} else {
try!(errcode_try("clBuildProgram", "", errcode));
Ok(())
}
}
pub fn compile_program() -> OclResult<()> {
unimplemented!();
}
pub fn link_program() -> OclResult<()> {
unimplemented!();
}
pub fn get_program_info(obj: &Program, request: ProgramInfo) -> ProgramInfoResult {
let mut result_size: size_t = 0;
let errcode = unsafe { cl_h::clGetProgramInfo(
obj.as_ptr() as cl_program,
request as cl_program_info,
0 as size_t,
0 as *mut c_void,
&mut result_size as *mut size_t,
) };
if let Err(err) = errcode_try("clGetProgramInfo", "", errcode) {
return ProgramInfoResult::Error(Box::new(err));
}
if result_size == 0 {
return ProgramInfoResult::from_bytes(request, Ok(vec![]));
}
let mut result: Vec<u8> = iter::repeat(0u8).take(result_size).collect();
let errcode = unsafe { cl_h::clGetProgramInfo(
obj.as_ptr() as cl_program,
request as cl_program_info,
result_size,
result.as_mut_ptr() as *mut _ as *mut c_void,
0 as *mut size_t,
) };
let result = errcode_try("clGetProgramInfo", "", errcode).and(Ok(result));
ProgramInfoResult::from_bytes(request, result)
}
pub fn get_program_build_info<D: ClDeviceIdPtr + Debug>(obj: &Program, device_obj: &D,
request: ProgramBuildInfo) -> ProgramBuildInfoResult
{
let mut result_size: size_t = 0;
let errcode = unsafe { cl_h::clGetProgramBuildInfo(
obj.as_ptr() as cl_program,
device_obj.as_ptr() as cl_device_id,
request as cl_program_build_info,
0 as size_t,
0 as *mut c_void,
&mut result_size as *mut size_t,
) };
if let Err(err) = errcode_try("clGetProgramBuildInfo", "", errcode) {
return ProgramBuildInfoResult::Error(Box::new(err));
}
if result_size == 0 {
return ProgramBuildInfoResult::from_bytes(request, Ok(vec![]));
}
let mut result: Vec<u8> = iter::repeat(0u8).take(result_size).collect();
let errcode = unsafe { cl_h::clGetProgramBuildInfo(
obj.as_ptr() as cl_program,
device_obj.as_ptr() as cl_device_id,
request as cl_program_build_info,
result_size as size_t,
result.as_mut_ptr() as *mut _ as *mut c_void,
0 as *mut size_t,
) };
let result = errcode_try("clGetProgramBuildInfo", "", errcode).and(Ok(result));
ProgramBuildInfoResult::from_bytes(request, result)
}
pub fn create_kernel(
program: &Program,
name: &str,
) -> OclResult<Kernel>
{
let mut err: cl_int = 0;
let kernel = unsafe { Kernel::from_fresh_ptr(cl_h::clCreateKernel(
program.as_ptr(),
try!(CString::new(name.as_bytes())).as_ptr(),
&mut err,
)) };
errcode_try("clCreateKernel", name, err).and(Ok(kernel))
}
pub fn create_kernels_in_program() -> OclResult<()> {
unimplemented!();
}
pub unsafe fn retain_kernel(kernel: &Kernel) -> OclResult<()> {
errcode_try("clRetainKernel", "", cl_h::clRetainKernel(kernel.as_ptr()))
}
pub unsafe fn release_kernel(kernel: &Kernel) -> OclResult<()> {
errcode_try("clReleaseKernel", "", cl_h::clReleaseKernel(kernel.as_ptr()))
}
pub fn set_kernel_arg<T: OclPrm>(kernel: &Kernel, arg_index: u32, arg: KernelArg<T>,
) -> OclResult<()>
{
let (arg_size, arg_value): (size_t, *const c_void) = match arg {
KernelArg::Mem(mem_core_ref) => (
mem::size_of::<cl_mem>() as size_t,
mem_core_ref as *const _ as *const c_void
),
KernelArg::Sampler(smplr_core_ref) => (
mem::size_of::<cl_sampler>() as size_t,
smplr_core_ref as *const _ as *const c_void
),
KernelArg::Scalar(ref scalar) => (
mem::size_of::<T>() as size_t,
scalar as *const T as *const c_void
),
KernelArg::Vector(slice)=> (
(mem::size_of::<T>() * slice.len()) as size_t,
slice as *const _ as *const c_void
),
KernelArg::Local(length) => (
(mem::size_of::<T>() * length) as size_t,
ptr::null()
),
KernelArg::UnsafePointer { size, value } => (size, value),
_ => (mem::size_of::<*const c_void>() as size_t, ptr::null()),
};
let err = unsafe { cl_h::clSetKernelArg(
kernel.as_ptr(),
arg_index,
arg_size,
arg_value,
) };
if err != 0 {
let name = get_kernel_name(&kernel);
errcode_try("clSetKernelArg", &name, err)
} else {
Ok(())
}
}
pub fn get_kernel_info(obj: &Kernel, request: KernelInfo,
) -> KernelInfoResult
{
let mut result_size: size_t = 0;
let errcode = unsafe { cl_h::clGetKernelInfo(
obj.as_ptr() as cl_kernel,
request as cl_kernel_info,
0 as size_t,
0 as *mut c_void,
&mut result_size as *mut size_t,
) };
if let Err(err) = errcode_try("clGetKernelInfo", "", errcode) {
return KernelInfoResult::Error(Box::new(err));
}
if result_size == 0 {
return KernelInfoResult::from_bytes(request, Ok(vec![]));
}
let mut result: Vec<u8> = iter::repeat(0u8).take(result_size).collect();
let errcode = unsafe { cl_h::clGetKernelInfo(
obj.as_ptr() as cl_kernel,
request as cl_kernel_info,
result_size,
result.as_mut_ptr() as *mut _ as *mut c_void,
0 as *mut size_t,
) };
let result = errcode_try("clGetKernelInfo", "", errcode).and(Ok(result));
KernelInfoResult::from_bytes(request, result)
}
pub fn get_kernel_arg_info(obj: &Kernel, arg_index: u32, request: KernelArgInfo,
) -> KernelArgInfoResult
{
let mut result_size: size_t = 0;
let errcode = unsafe { cl_h::clGetKernelArgInfo(
obj.as_ptr() as cl_kernel,
arg_index as cl_uint,
request as cl_kernel_arg_info,
0 as size_t,
0 as *mut c_void,
&mut result_size as *mut size_t,
) };
if let Err(err) = errcode_try("clGetKernelArgInfo", "", errcode) {
return KernelArgInfoResult::Error(Box::new(err));
}
if result_size == 0 {
return KernelArgInfoResult::from_bytes(request, Ok(vec![]));
}
let mut result: Vec<u8> = iter::repeat(0u8).take(result_size).collect();
let errcode = unsafe { cl_h::clGetKernelArgInfo(
obj.as_ptr() as cl_kernel,
arg_index as cl_uint,
request as cl_kernel_arg_info,
result_size,
result.as_mut_ptr() as *mut _ as *mut c_void,
0 as *mut size_t,
) };
let result = errcode_try("clGetKernelArgInfo", "", errcode).and(Ok(result));
KernelArgInfoResult::from_bytes(request, result)
}
pub fn get_kernel_work_group_info<D: ClDeviceIdPtr>(obj: &Kernel, device_obj: &D,
request: KernelWorkGroupInfo) -> KernelWorkGroupInfoResult
{
let mut result_size: size_t = 0;
let errcode = unsafe { cl_h::clGetKernelWorkGroupInfo(
obj.as_ptr() as cl_kernel,
device_obj.as_ptr() as cl_device_id,
request as cl_kernel_work_group_info,
0 as size_t,
0 as *mut c_void,
&mut result_size as *mut size_t,
) };
if let Err(err) = errcode_try("clGetKernelWorkGroupInfo", "", errcode) {
return KernelWorkGroupInfoResult::Error(Box::new(err));
}
if result_size == 0 {
return KernelWorkGroupInfoResult::from_bytes(request, Ok(vec![]));
}
let mut result: Vec<u8> = iter::repeat(0u8).take(result_size).collect();
let errcode = unsafe { cl_h::clGetKernelWorkGroupInfo(
obj.as_ptr() as cl_kernel,
device_obj.as_ptr() as cl_device_id,
request as cl_kernel_work_group_info,
result_size,
result.as_mut_ptr() as *mut _ as *mut c_void,
0 as *mut size_t,
) };
let result = errcode_try("clGetKernelWorkGroupInfo", "", errcode).and(Ok(result));
KernelWorkGroupInfoResult::from_bytes(request, result)
}
pub fn wait_for_events(num_events: u32, event_list: &EventList) -> OclResult<()> {
assert!(event_list.count() >= num_events);
let errcode = unsafe {
cl_h::clWaitForEvents(num_events, event_list.as_ptr_ptr())
};
errcode_try("clWaitForEvents", "", errcode)
}
pub fn get_event_info(event: &Event, request: EventInfo,
) -> EventInfoResult
{
let mut result_size: size_t = 0;
let errcode = unsafe { cl_h::clGetEventInfo(
*event.as_ptr_ref(),
request as cl_event_info,
0 as size_t,
0 as *mut c_void,
&mut result_size as *mut size_t,
) };
if let Err(err) = errcode_try("clGetEventInfo", "", errcode) {
return EventInfoResult::Error(Box::new(err));
}
if result_size == 0 {
return EventInfoResult::from_bytes(request, Ok(vec![]));
}
let mut result: Vec<u8> = iter::repeat(0u8).take(result_size).collect();
let errcode = unsafe { cl_h::clGetEventInfo(
*event.as_ptr_ref(),
request as cl_event_info,
result_size,
result.as_mut_ptr() as *mut _ as *mut c_void,
0 as *mut size_t,
) };
let result = errcode_try("clGetEventInfo", "", errcode).and(Ok(result));
EventInfoResult::from_bytes(request, result)
}
pub fn create_user_event(context: &Context) -> OclResult<Event> {
let mut errcode = 0;
let event = unsafe { Event::from_fresh_ptr(cl_h::clCreateUserEvent(context.as_ptr(), &mut errcode)) };
errcode_try("clCreateUserEvent", "", errcode).and(Ok(event))
}
pub unsafe fn retain_event<'e, E: ClEventRef<'e>>(event: &'e E) -> OclResult<()> {
errcode_try("clRetainEvent", "", cl_h::clRetainEvent(*event.as_ptr_ref()))
}
pub unsafe fn release_event<'e, E: ClEventRef<'e>>(event: &'e E) -> OclResult<()> {
errcode_try("clReleaseEvent", "", cl_h::clReleaseEvent(*event.as_ptr_ref()))
}
pub fn set_user_event_status<'e,E: ClEventRef<'e>>(event: &'e E,
execution_status: CommandExecutionStatus) -> OclResult<()>
{
unsafe { errcode_try("clSetUserEventStatus", "", cl_h::clSetUserEventStatus(
*event.as_ptr_ref(), execution_status as cl_int)) }
}
pub unsafe fn set_event_callback<'e, E: ClEventRef<'e>>(
event: &'e E,
callback_trigger: CommandExecutionStatus,
callback_receiver: Option<EventCallbackFn>,
user_data: *mut c_void,
) -> OclResult<()>
{
errcode_try("clSetEventCallback", "", cl_h::clSetEventCallback(
*event.as_ptr_ref(),
callback_trigger as cl_int,
callback_receiver,
user_data,
))
}
pub fn get_event_profiling_info(event: &Event, request: ProfilingInfo,
) -> ProfilingInfoResult
{
let mut result_size: size_t = 0;
let event: cl_event = unsafe { *event.as_ptr_ref() };
let errcode = unsafe { cl_h::clGetEventProfilingInfo(
event,
request as cl_profiling_info,
0 as size_t,
0 as *mut c_void,
&mut result_size as *mut size_t,
) };
if let Err(err) = errcode_try("clGetEventProfilingInfo", "", errcode) {
return ProfilingInfoResult::Error(Box::new(err));
}
if result_size == 0 {
return ProfilingInfoResult::from_bytes(request, Ok(vec![]));
}
let mut result: Vec<u8> = iter::repeat(0u8).take(result_size).collect();
let errcode = unsafe { cl_h::clGetEventProfilingInfo(
event,
request as cl_profiling_info,
result_size,
result.as_mut_ptr() as *mut _ as *mut c_void,
0 as *mut size_t,
) };
let result = errcode_try("clGetEventProfilingInfo", "", errcode).and(Ok(result));
ProfilingInfoResult::from_bytes(request, result)
}
pub fn flush(command_queue: &CommandQueue) -> OclResult<()> {
unsafe { errcode_try("clFlush", "", cl_h::clFlush(command_queue.as_ptr())) }
}
pub fn finish(command_queue: &CommandQueue) -> OclResult<()> {
unsafe {
let errcode = cl_h::clFinish(command_queue.as_ptr());
errcode_try("clFinish", "", errcode)
}
}
pub unsafe fn enqueue_read_buffer<T: OclPrm, L: AsRef<EventList>>(
command_queue: &CommandQueue,
buffer: &Mem,
block: bool,
offset: usize,
data: &mut [T],
wait_list: Option<&L>,
new_event: Option<&mut ClEventPtrNew>,
) -> OclResult<()>
{
let (wait_list_len, wait_list_ptr, new_event_ptr) =
try!(resolve_event_ptrs(wait_list, new_event));
let offset_bytes = offset * mem::size_of::<T>();
let errcode = cl_h::clEnqueueReadBuffer(
command_queue.as_ptr(),
buffer.as_ptr(),
block as cl_uint,
offset_bytes,
(data.len() * mem::size_of::<T>()) as size_t,
data.as_ptr() as cl_mem,
wait_list_len,
wait_list_ptr,
new_event_ptr,
);
errcode_try("clEnqueueReadBuffer", "", errcode)
}
pub unsafe fn enqueue_read_buffer_rect<T: OclPrm, L: AsRef<EventList>>(
command_queue: &CommandQueue,
buffer: &Mem,
block: bool,
buffer_origin: [usize; 3],
host_origin: [usize; 3],
region: [usize; 3],
buffer_row_pitch: usize,
buffer_slc_pitch: usize,
host_row_pitch: usize,
host_slc_pitch: usize,
data: &mut [T],
wait_list: Option<&L>,
new_event: Option<&mut ClEventPtrNew>,
) -> OclResult<()>
{
let buffer_origin_bytes = [buffer_origin[0] * mem::size_of::<T>(),
buffer_origin[1], buffer_origin[2]];
let host_origin_bytes = [host_origin[0] * mem::size_of::<T>(),
host_origin[1], host_origin[2]];
let region_bytes = [region[0] * mem::size_of::<T>(), region[1], region[2]];
let buffer_row_pitch_bytes = buffer_row_pitch * mem::size_of::<T>();
let buffer_slc_pitch_bytes = buffer_slc_pitch * mem::size_of::<T>();
let host_row_pitch_bytes = host_row_pitch * mem::size_of::<T>();
let host_slc_pitch_bytes = host_slc_pitch * mem::size_of::<T>();
if false {
println!("buffer_origin_bytes: {:?}, host_origin_bytes: {:?}, region_bytes: {:?}",
buffer_origin_bytes, host_origin_bytes, region_bytes);
println!("buffer_row_pitch_bytes: {}, buffer_slc_pitch_bytes: {}, \
host_row_pitch_bytes: {}, host_slc_pitch_bytes: {}",
buffer_row_pitch_bytes, buffer_slc_pitch_bytes, host_row_pitch_bytes, host_slc_pitch_bytes);
}
let (wait_list_len, wait_list_ptr, new_event_ptr) =
try!(resolve_event_ptrs(wait_list, new_event));
let errcode = cl_h::clEnqueueReadBufferRect(
command_queue.as_ptr(),
buffer.as_ptr(),
block as cl_uint,
&buffer_origin_bytes as *const _ as *const usize,
&host_origin_bytes as *const _ as *const usize,
®ion_bytes as *const _ as *const usize,
buffer_row_pitch_bytes,
buffer_slc_pitch_bytes,
host_row_pitch_bytes,
host_slc_pitch_bytes,
data.as_ptr() as cl_mem,
wait_list_len,
wait_list_ptr,
new_event_ptr,
);
errcode_try("clEnqueueReadBufferRect", "", errcode)
}
pub fn enqueue_write_buffer<T: OclPrm, L: AsRef<EventList>>(
command_queue: &CommandQueue,
buffer: &Mem,
block: bool,
offset: usize,
data: &[T],
wait_list: Option<&L>,
new_event: Option<&mut ClEventPtrNew>,
) -> OclResult<()>
{
let (wait_list_len, wait_list_ptr, new_event_ptr) =
try!(resolve_event_ptrs(wait_list, new_event));
let offset_bytes = offset * mem::size_of::<T>();
let errcode = unsafe { cl_h::clEnqueueWriteBuffer(
command_queue.as_ptr(),
buffer.as_ptr(),
block as cl_uint,
offset_bytes,
(data.len() * mem::size_of::<T>()) as size_t,
data.as_ptr() as cl_mem,
wait_list_len,
wait_list_ptr,
new_event_ptr,
) };
errcode_try("clEnqueueWriteBuffer", "", errcode)
}
pub fn enqueue_write_buffer_rect<T: OclPrm, L: AsRef<EventList>>(
command_queue: &CommandQueue,
buffer: &Mem,
block: bool,
buffer_origin: [usize; 3],
host_origin: [usize; 3],
region: [usize; 3],
buffer_row_pitch: usize,
buffer_slc_pitch: usize,
host_row_pitch: usize,
host_slc_pitch: usize,
data: &[T],
wait_list: Option<&L>,
new_event: Option<&mut ClEventPtrNew>,
) -> OclResult<()>
{
let (wait_list_len, wait_list_ptr, new_event_ptr) =
try!(resolve_event_ptrs(wait_list, new_event));
let buffer_origin_bytes = [buffer_origin[0] * mem::size_of::<T>(),
buffer_origin[1], buffer_origin[2]];
let host_origin_bytes = [host_origin[0] * mem::size_of::<T>(),
host_origin[1], host_origin[2]];
let region_bytes = [region[0] * mem::size_of::<T>(), region[1], region[2]];
let buffer_row_pitch_bytes = buffer_row_pitch * mem::size_of::<T>();
let buffer_slc_pitch_bytes = buffer_slc_pitch * mem::size_of::<T>();
let host_row_pitch_bytes = host_row_pitch * mem::size_of::<T>();
let host_slc_pitch_bytes = host_slc_pitch * mem::size_of::<T>();
let errcode = unsafe { cl_h::clEnqueueWriteBufferRect(
command_queue.as_ptr(),
buffer.as_ptr(),
block as cl_uint,
&buffer_origin_bytes as *const _ as *const usize,
&host_origin_bytes as *const _ as *const usize,
®ion_bytes as *const _ as *const usize,
buffer_row_pitch_bytes,
buffer_slc_pitch_bytes,
host_row_pitch_bytes,
host_slc_pitch_bytes,
data.as_ptr() as cl_mem,
wait_list_len,
wait_list_ptr,
new_event_ptr,
) };
errcode_try("clEnqueueWriteBufferRect", "", errcode)
}
pub fn enqueue_fill_buffer<T: OclPrm, L: AsRef<EventList>>(
command_queue: &CommandQueue,
buffer: &Mem,
pattern: &[T],
offset: usize,
len: usize,
wait_list: Option<&L>,
new_event: Option<&mut ClEventPtrNew>,
) -> OclResult<()>
{
let pattern_size = pattern.len() * mem::size_of::<T>();
let offset_bytes = offset * mem::size_of::<T>();
let size_bytes = len * mem::size_of::<T>();
let (wait_list_len, wait_list_ptr, new_event_ptr)
= try!(resolve_event_ptrs(wait_list, new_event));
let errcode = unsafe { cl_h::clEnqueueFillBuffer(
command_queue.as_ptr(),
buffer.as_ptr(),
pattern as *const _ as *const c_void,
pattern_size,
offset_bytes,
size_bytes,
wait_list_len,
wait_list_ptr,
new_event_ptr,
) };
errcode_try("clEnqueueFillBuffer", "", errcode)
}
pub fn enqueue_copy_buffer<T: OclPrm, L: AsRef<EventList>>(
command_queue: &CommandQueue,
src_buffer: &Mem,
dst_buffer: &Mem,
src_offset: usize,
dst_offset: usize,
len: usize,
wait_list: Option<&L>,
new_event: Option<&mut ClEventPtrNew>,
) -> OclResult<()>
{
let (wait_list_len, wait_list_ptr, new_event_ptr)
= try!(resolve_event_ptrs(wait_list, new_event));
let src_offset_bytes = src_offset * mem::size_of::<T>();
let dst_offset_bytes = dst_offset * mem::size_of::<T>();
let len_bytes = len * mem::size_of::<T>();
let errcode = unsafe { cl_h::clEnqueueCopyBuffer(
command_queue.as_ptr(),
src_buffer.as_ptr(),
dst_buffer.as_ptr(),
src_offset_bytes,
dst_offset_bytes,
len_bytes,
wait_list_len,
wait_list_ptr,
new_event_ptr,
) };
errcode_try("clEnqueueCopyBuffer", "", errcode)
}
pub fn enqueue_copy_buffer_rect<T: OclPrm, L: AsRef<EventList>>(
command_queue: &CommandQueue,
src_buffer: &Mem,
dst_buffer: &Mem,
src_origin: [usize; 3],
dst_origin: [usize; 3],
region: [usize; 3],
src_row_pitch: usize,
src_slc_pitch: usize,
dst_row_pitch: usize,
dst_slc_pitch: usize,
wait_list: Option<&L>,
new_event: Option<&mut ClEventPtrNew>,
) -> OclResult<()>
{
let (wait_list_len, wait_list_ptr, new_event_ptr) =
try!(resolve_event_ptrs(wait_list, new_event));
let src_origin_bytes = [src_origin[0] * mem::size_of::<T>(),
src_origin[1], src_origin[2]];
let dst_origin_bytes = [dst_origin[0] * mem::size_of::<T>(),
dst_origin[1], dst_origin[2]];
let region_bytes = [region[0] * mem::size_of::<T>(), region[1], region[2]];
let src_row_pitch_bytes = src_row_pitch * mem::size_of::<T>();
let src_slc_pitch_bytes = src_slc_pitch * mem::size_of::<T>();
let dst_row_pitch_bytes = dst_row_pitch * mem::size_of::<T>();
let dst_slc_pitch_bytes = dst_slc_pitch * mem::size_of::<T>();
let errcode = unsafe { cl_h::clEnqueueCopyBufferRect(
command_queue.as_ptr(),
src_buffer.as_ptr(),
dst_buffer.as_ptr(),
&src_origin_bytes as *const _ as *const usize,
&dst_origin_bytes as *const _ as *const usize,
®ion_bytes as *const _ as *const usize,
src_row_pitch_bytes,
src_slc_pitch_bytes,
dst_row_pitch_bytes,
dst_slc_pitch_bytes,
wait_list_len,
wait_list_ptr,
new_event_ptr,
) };
errcode_try("clEnqueueCopyBufferRect", "", errcode)
}
pub unsafe fn enqueue_read_image<T, L: AsRef<EventList>>(
command_queue: &CommandQueue,
image: &Mem,
block: bool,
origin: [usize; 3],
region: [usize; 3],
row_pitch: usize,
slc_pitch: usize,
data: &mut [T],
wait_list: Option<&L>,
new_event: Option<&mut ClEventPtrNew>,
) -> OclResult<()>
{
let row_pitch_bytes = row_pitch * mem::size_of::<T>();
let slc_pitch_bytes = slc_pitch * mem::size_of::<T>();
let (wait_list_len, wait_list_ptr, new_event_ptr)
= try!(resolve_event_ptrs(wait_list, new_event));
let errcode = cl_h::clEnqueueReadImage(
command_queue.as_ptr(),
image.as_ptr(),
block as cl_uint,
&origin as *const _ as *const usize,
®ion as *const _ as *const usize,
row_pitch_bytes,
slc_pitch_bytes,
data.as_ptr() as cl_mem,
wait_list_len,
wait_list_ptr,
new_event_ptr,
);
errcode_try("clEnqueueReadImage", "", errcode)
}
pub fn enqueue_write_image<T, L: AsRef<EventList>>(
command_queue: &CommandQueue,
image: &Mem,
block: bool,
origin: [usize; 3],
region: [usize; 3],
input_row_pitch: usize,
input_slc_pitch: usize,
data: &[T],
wait_list: Option<&L>,
new_event: Option<&mut ClEventPtrNew>,
) -> OclResult<()>
{
let input_row_pitch_bytes = input_row_pitch * mem::size_of::<T>();
let input_slc_pitch_bytes = input_slc_pitch * mem::size_of::<T>();
let (wait_list_len, wait_list_ptr, new_event_ptr)
= try!(resolve_event_ptrs(wait_list, new_event));
let errcode = unsafe { cl_h::clEnqueueWriteImage(
command_queue.as_ptr(),
image.as_ptr(),
block as cl_uint,
&origin as *const _ as *const usize,
®ion as *const _ as *const usize,
input_row_pitch_bytes,
input_slc_pitch_bytes,
data.as_ptr() as cl_mem,
wait_list_len,
wait_list_ptr,
new_event_ptr,
) };
errcode_try("clEnqueueWriteImage", "", errcode)
}
pub fn enqueue_fill_image<T, L: AsRef<EventList>>(
command_queue: &CommandQueue,
image: &Mem,
color: &[T],
origin: [usize; 3],
region: [usize; 3],
wait_list: Option<&L>,
new_event: Option<&mut ClEventPtrNew>,
) -> OclResult<()>
{
let (wait_list_len, wait_list_ptr, new_event_ptr)
= try!(resolve_event_ptrs(wait_list, new_event));
let errcode = unsafe { cl_h::clEnqueueFillImage(
command_queue.as_ptr(),
image.as_ptr(),
color as *const _ as *const c_void,
&origin as *const _ as *const usize,
®ion as *const _ as *const usize,
wait_list_len,
wait_list_ptr,
new_event_ptr,
) };
errcode_try("clEnqueueFillImage", "", errcode)
}
pub fn enqueue_copy_image<T, L: AsRef<EventList>>(
command_queue: &CommandQueue,
src_image: &Mem,
dst_image: &Mem,
src_origin: [usize; 3],
dst_origin: [usize; 3],
region: [usize; 3],
wait_list: Option<&L>,
new_event: Option<&mut ClEventPtrNew>,
) -> OclResult<()>
{
let (wait_list_len, wait_list_ptr, new_event_ptr)
= try!(resolve_event_ptrs(wait_list, new_event));
let errcode = unsafe { cl_h::clEnqueueCopyImage(
command_queue.as_ptr(),
src_image.as_ptr(),
dst_image.as_ptr(),
&src_origin as *const _ as *const usize,
&dst_origin as *const _ as *const usize,
®ion as *const _ as *const usize,
wait_list_len,
wait_list_ptr,
new_event_ptr,
) };
errcode_try("clEnqueueCopyImage", "", errcode)
}
pub fn enqueue_copy_image_to_buffer<T: OclPrm, L: AsRef<EventList>>(
command_queue: &CommandQueue,
src_image: &Mem,
dst_buffer: &Mem,
src_origin: [usize; 3],
region: [usize; 3],
dst_offset: usize,
wait_list: Option<&L>,
new_event: Option<&mut ClEventPtrNew>,
) -> OclResult<()>
{
let dst_offset_bytes = dst_offset * mem::size_of::<T>();
let (wait_list_len, wait_list_ptr, new_event_ptr)
= try!(resolve_event_ptrs(wait_list, new_event));
let errcode = unsafe { cl_h::clEnqueueCopyImageToBuffer(
command_queue.as_ptr(),
src_image.as_ptr(),
dst_buffer.as_ptr(),
&src_origin as *const _ as *const usize,
®ion as *const _ as *const usize,
dst_offset_bytes,
wait_list_len,
wait_list_ptr,
new_event_ptr,
) };
errcode_try("clEnqueueCopyImageToBuffer", "", errcode)
}
pub fn enqueue_copy_buffer_to_image<T: OclPrm, L: AsRef<EventList>>(
command_queue: &CommandQueue,
src_buffer: &Mem,
dst_image: &Mem,
src_offset: usize,
dst_origin: [usize; 3],
region: [usize; 3],
wait_list: Option<&L>,
new_event: Option<&mut ClEventPtrNew>,
) -> OclResult<()>
{
let src_offset_bytes = src_offset * mem::size_of::<T>();
let (wait_list_len, wait_list_ptr, new_event_ptr)
= try!(resolve_event_ptrs(wait_list, new_event));
let errcode = unsafe { cl_h::clEnqueueCopyBufferToImage(
command_queue.as_ptr(),
src_buffer.as_ptr(),
dst_image.as_ptr(),
src_offset_bytes,
&dst_origin as *const _ as *const usize,
®ion as *const _ as *const usize,
wait_list_len,
wait_list_ptr,
new_event_ptr,
) };
errcode_try("clEnqueueCopyBufferToImage", "", errcode)
}
pub unsafe fn enqueue_map_buffer<T: OclPrm, L: AsRef<EventList>>(
command_queue: &CommandQueue,
buffer: &Mem,
block: bool,
map_flags: MapFlags,
offset: usize,
size: usize,
wait_list: Option<&L>,
new_event: Option<&mut ClEventPtrNew>,
) -> OclResult<*mut c_void>
{
let offset_bytes = offset * mem::size_of::<T>();
let size_bytes = size * mem::size_of::<T>();
let (wait_list_len, wait_list_ptr, new_event_ptr) =
try!(resolve_event_ptrs(wait_list, new_event));
let mut errcode = 0i32;
let mapped_ptr = cl_h::clEnqueueMapBuffer(
command_queue.as_ptr(),
buffer.as_ptr(),
block as cl_uint,
map_flags.bits(),
offset_bytes,
size_bytes,
wait_list_len,
wait_list_ptr,
new_event_ptr,
&mut errcode,
);
try!(errcode_try("clEnqueueMapBuffer", "", errcode));
Ok(mapped_ptr)
}
pub unsafe fn enqueue_map_image<T, L: AsRef<EventList>>(
command_queue: &CommandQueue,
image: &Mem,
block: bool,
map_flags: MapFlags,
origin: [usize; 3],
region: [usize; 3],
row_pitch: usize,
slc_pitch: usize,
wait_list: Option<&L>,
new_event: Option<&mut ClEventPtrNew>,
) -> OclResult<*mut c_void>
{
let row_pitch_bytes = row_pitch * mem::size_of::<T>();
let slc_pitch_bytes = slc_pitch * mem::size_of::<T>();
let (wait_list_len, wait_list_ptr, new_event_ptr) =
try!(resolve_event_ptrs(wait_list, new_event));
let mut errcode = 0i32;
let mapped_ptr = cl_h::clEnqueueMapImage(
command_queue.as_ptr(),
image.as_ptr(),
block as cl_uint,
map_flags.bits(),
&origin as *const _ as *const usize,
®ion as *const _ as *const usize,
row_pitch_bytes,
slc_pitch_bytes,
wait_list_len,
wait_list_ptr,
new_event_ptr,
&mut errcode,
);
try!(errcode_try("clEnqueueMapImage", "", errcode));
Ok(mapped_ptr)
}
pub fn enqueue_unmap_mem_object<L: AsRef<EventList>>(
command_queue: &CommandQueue,
memobj: &Mem,
mapped_ptr: *mut c_void,
wait_list: Option<&L>,
new_event: Option<&mut ClEventPtrNew>,
) -> OclResult<()> {
let (wait_list_len, wait_list_ptr, new_event_ptr) =
try!(resolve_event_ptrs(wait_list, new_event));
let errcode = unsafe { cl_h::clEnqueueUnmapMemObject(
command_queue.as_ptr(),
memobj.as_ptr(),
mapped_ptr,
wait_list_len,
wait_list_ptr,
new_event_ptr,
) };
errcode_try("clEnqueueUnmapMemObject", "", errcode)
}
pub fn enqueue_migrate_mem_objects<L: AsRef<EventList>>(
command_queue: &CommandQueue,
num_mem_objects: u32,
mem_objects: &[Mem],
flags: MemMigrationFlags,
wait_list: Option<&L>,
new_event: Option<&mut ClEventPtrNew>,
) -> OclResult<()>
{
let (wait_list_len, wait_list_ptr, new_event_ptr)
= try!(resolve_event_ptrs(wait_list, new_event));
let mem_ptr_list: Vec<cl_mem> = mem_objects.iter()
.map(|ref mem_obj| unsafe { mem_obj.as_ptr() } ).collect();
let errcode = unsafe { cl_h::clEnqueueMigrateMemObjects(
command_queue.as_ptr(),
num_mem_objects,
mem_ptr_list.as_ptr() as *const _ as *const cl_mem,
flags.bits(),
wait_list_len,
wait_list_ptr,
new_event_ptr,
) };
errcode_try("clEnqueueMigrateMemObjects", "", errcode)
}
pub fn enqueue_kernel<L: AsRef<EventList> + Debug>(
command_queue: &CommandQueue,
kernel: &Kernel,
work_dims: u32,
global_work_offset: Option<[usize; 3]>,
global_work_dims: &[usize; 3],
local_work_dims: Option<[usize; 3]>,
wait_list: Option<&L>,
new_event: Option<&mut ClEventPtrNew>,
) -> OclResult<()>
{
let (wait_list_len, wait_list_ptr, new_event_ptr) =
try!(resolve_event_ptrs(wait_list, new_event));
let gwo = resolve_work_dims(&global_work_offset);
let gws = global_work_dims as *const size_t;
let lws = resolve_work_dims(&local_work_dims);
if cfg!(feature="kernel_debug_print") {
print!("core::enqueue_kernel('{}': \
work_dims: {}, \
gwo: {:?}, \
gws: {:?}, \
lws: {:?}, \
wait_list_len: {}, \
wait_list_ptr: {:?}, \
new_event_ptr: {:?}) \
",
get_kernel_name(&kernel),
work_dims,
global_work_offset,
global_work_dims,
local_work_dims,
wait_list_len,
wait_list_ptr,
new_event_ptr,
);
}
let errcode = unsafe { cl_h::clEnqueueNDRangeKernel(
command_queue.as_ptr(),
kernel.as_ptr() as cl_kernel,
work_dims,
gwo,
gws,
lws,
wait_list_len,
wait_list_ptr,
new_event_ptr,
) };
if cfg!(feature="kernel_debug_print") { println!("-> Status: {}.", errcode); }
if cfg!(feature="kernel_debug_sleep") {
thread::sleep(Duration::from_millis(KERNEL_DEBUG_SLEEP_DURATION_MS));
}
if errcode != 0 {
let name = get_kernel_name(&kernel);
errcode_try("clEnqueueNDRangeKernel", &name, errcode)
} else {
Ok(())
}
}
pub fn enqueue_task<L: AsRef<EventList>>(
command_queue: &CommandQueue,
kernel: &Kernel,
wait_list: Option<&L>,
new_event: Option<&mut ClEventPtrNew>,
kernel_name: Option<&str>
) -> OclResult<()>
{
let (wait_list_len, wait_list_ptr, new_event_ptr) =
try!(resolve_event_ptrs(wait_list, new_event));
let errcode = unsafe { cl_h::clEnqueueTask(
command_queue.as_ptr(),
kernel.as_ptr() as cl_kernel,
wait_list_len,
wait_list_ptr,
new_event_ptr,
) };
errcode_try("clEnqueueTask", kernel_name.unwrap_or(""), errcode)
}
pub fn enqueue_native_kernel() -> OclResult<()> {
unimplemented!();
}
pub fn enqueue_marker_with_wait_list<L: AsRef<EventList>>(
command_queue: &CommandQueue,
wait_list: Option<&L>,
new_event: Option<&mut ClEventPtrNew>,
) -> OclResult<()>
{
let (wait_list_len, wait_list_ptr, new_event_ptr) =
try!(resolve_event_ptrs(wait_list, new_event));
let errcode = unsafe { cl_h::clEnqueueMarkerWithWaitList(
command_queue.as_ptr(),
wait_list_len,
wait_list_ptr,
new_event_ptr,
) };
errcode_try("clEnqueueMarkerWithWaitList", "", errcode)
}
pub fn enqueue_barrier_with_wait_list<L: AsRef<EventList>>(
command_queue: &CommandQueue,
wait_list: Option<&L>,
new_event: Option<&mut ClEventPtrNew>,
) -> OclResult<()>
{
let (wait_list_len, wait_list_ptr, new_event_ptr) =
try!(resolve_event_ptrs(wait_list, new_event));
let errcode = unsafe { cl_h::clEnqueueBarrierWithWaitList(
command_queue.as_ptr(),
wait_list_len,
wait_list_ptr,
new_event_ptr,
) };
errcode_try("clEnqueueBarrierWithWaitList", "", errcode)
}
pub unsafe fn get_extension_function_address_for_platform(platform: &PlatformId,
func_name: &str) -> OclResult<*mut c_void>
{
let func_name_c = try!(CString::new(func_name));
let ext_fn = cl_h::clGetExtensionFunctionAddressForPlatform(
platform.as_ptr(),
func_name_c.as_ptr(),
);
if ext_fn == 0 as *mut c_void {
OclError::err("The specified function does not exist for the implementation or 'platform' \
is not a valid platform.")
} else {
Ok(ext_fn)
}
}
pub fn default_platform_idx() -> usize {
match env::var("OCL_DEFAULT_PLATFORM_IDX") {
Ok(s) => s.parse::<usize>().unwrap_or(0),
Err(_) => 0,
}
}
pub fn default_platform() -> OclResult<PlatformId> {
let platform_list = try!(get_platform_ids());
if platform_list.len() == 0 {
OclError::err("No platforms found!")
} else {
let default_platform_idx = default_platform_idx();
if default_platform_idx > platform_list.len() - 1 {
OclError::err(format!("The default platform set by the environment variable \
'OCL_DEFAULT_PLATFORM_IDX' has an index which is out of range \
(index: [{}], max: [{}]).", default_platform_idx, platform_list.len() - 1))
} else {
Ok(platform_list[default_platform_idx].clone())
}
}
}
pub fn default_device_type() -> OclResult<DeviceType> {
match env::var("OCL_DEFAULT_DEVICE_TYPE") {
Ok(ref s) => match s.trim() {
"DEFAULT" => Ok(core::DEVICE_TYPE_DEFAULT),
"CPU" => Ok(core::DEVICE_TYPE_CPU),
"GPU" => Ok(core::DEVICE_TYPE_GPU),
"ACCELERATOR" => Ok(core::DEVICE_TYPE_ACCELERATOR),
"CUSTOM" => Ok(core::DEVICE_TYPE_CUSTOM),
"ALL" => Ok(core::DEVICE_TYPE_ALL),
_ => OclError::err(format!("The default device type set by the environment variable \
'OCL_DEFAULT_DEVICE_TYPE': ('{}') is invalid. Valid types are: 'DEFAULT', 'CPU', \
'GPU', 'ACCELERATOR', 'CUSTOM', and 'ALL'.", s)),
},
Err(_) => Ok(core::DEVICE_TYPE_ALL),
}
}
pub fn get_kernel_name(kernel: &Kernel) -> String {
let result = get_kernel_info(kernel, KernelInfo::FunctionName);
result.into()
}
pub fn create_build_program<D: ClDeviceIdPtr + Debug>(
context: &Context,
src_strings: &Vec<CString>,
cmplr_opts: &CString,
device_ids: &[D],
) -> OclResult<Program>
{
let program = try!(create_program_with_source(context, src_strings));
try!(build_program(&program, device_ids, cmplr_opts, None, None));
Ok(program)
}
#[allow(dead_code)]
pub fn wait_for_event(event: &Event) -> OclResult<()> {
let errcode = unsafe {
let event_ptr = *event.as_ptr_ref();
cl_h::clWaitForEvents(1, &event_ptr)
};
errcode_try("clWaitForEvents", "", errcode)
}
pub fn get_event_status<'e, E: ClEventRef<'e>>(event: &'e E) -> OclResult<CommandExecutionStatus> {
let mut status_int: cl_int = 0;
let errcode = unsafe {
cl_h::clGetEventInfo(
*event.as_ptr_ref(),
cl_h::CL_EVENT_COMMAND_EXECUTION_STATUS,
mem::size_of::<cl_int>(),
&mut status_int as *mut _ as *mut c_void,
ptr::null_mut(),
)
};
try!(errcode_try("clGetEventInfo", "", errcode));
CommandExecutionStatus::from_i32(status_int).ok_or(OclError::new("Error converting \
'clGetEventInfo' status output."))
}
#[inline]
pub fn verify_context(context: &Context) -> OclResult<()> {
if cfg!(release) {
Ok(())
} else {
match get_context_info(context, ContextInfo::Devices) {
ContextInfoResult::Error(err) => Err(*err),
_ => Ok(()),
}
}
}