use crate::ffi::{c_void, size_t};
use num_traits::FromPrimitive;
use std::env;
use std::ffi::CString;
use std::fmt;
use std::iter;
use std::mem;
use std::ptr;
use std::thread;
use std::time::Duration;
#[cfg(not(feature = "opencl_vendor_mesa"))]
use crate::ffi::{
clCreateFromGLBuffer, clCreateFromGLRenderbuffer, clCreateFromGLTexture,
clCreateFromGLTexture2D, clCreateFromGLTexture3D, clEnqueueAcquireGLObjects,
clEnqueueReleaseGLObjects,
};
#[cfg(not(feature = "opencl_vendor_mesa"))]
use crate::ffi::{cl_GLenum, cl_GLint, cl_GLuint, cl_gl_context_info};
use crate::ffi::{
self, cl_addressing_mode, cl_bool, cl_buffer_create_type, cl_command_queue,
cl_command_queue_info, cl_context, cl_context_info, cl_context_properties, cl_device_id,
cl_device_info, cl_device_type, cl_event, cl_event_info, cl_filter_mode, cl_image_desc,
cl_image_format, cl_image_info, cl_int, cl_kernel, cl_kernel_arg_info, cl_kernel_info,
cl_kernel_work_group_info, cl_mem, cl_mem_flags, cl_mem_info, cl_mem_object_type,
cl_platform_id, cl_platform_info, cl_profiling_info, cl_program, cl_program_build_info,
cl_program_info, cl_sampler, cl_sampler_info, cl_uint,
};
use crate::error::{Error as OclCoreError, Result as OclCoreResult};
use crate::{
AddressingMode, ArgVal, AsMem, BufferCreateType, BufferRegion, BuildProgramCallbackFn,
ClContextPtr, ClDeviceIdPtr, ClEventPtrRef, ClNullEventPtr, ClPlatformIdPtr, ClVersions,
ClWaitListPtr, CommandExecutionStatus, CommandQueue, CommandQueueInfo, CommandQueueInfoResult,
CommandQueueProperties, Context, ContextInfo, ContextInfoResult, ContextProperties,
CreateContextCallbackFn, DeviceId, DeviceInfo, DeviceInfoResult, DeviceType, Event,
EventCallbackFn, EventInfo, EventInfoResult, FilterMode, ImageDescriptor, ImageFormat,
ImageFormatParseResult, ImageInfo, ImageInfoResult, Kernel, KernelArgInfo, KernelArgInfoResult,
KernelInfo, KernelInfoResult, KernelWorkGroupInfo, KernelWorkGroupInfoResult, MapFlags, Mem,
MemCmdAll, MemCmdRw, MemFlags, MemInfo, MemInfoResult, MemMap, MemMigrationFlags,
MemObjectType, OclPrm, OpenclVersion, PlatformId, PlatformInfo, PlatformInfoResult,
ProfilingInfo, ProfilingInfoResult, Program, ProgramBuildInfo, ProgramBuildInfoResult,
ProgramInfo, ProgramInfoResult, Sampler, SamplerInfo, SamplerInfoResult, Status, UserDataPtr,
};
#[cfg(not(feature = "opencl_vendor_mesa"))]
use crate::{GlContextInfo, GlContextInfoResult};
#[cfg(target_os = "macos")]
const CL_GL_SHARING_EXT: &str = "cl_APPLE_gl_sharing";
#[cfg(not(target_os = "macos"))]
const CL_GL_SHARING_EXT: &str = "cl_khr_gl_sharing";
const KERNEL_DEBUG_SLEEP_DURATION_MS: u64 = 150;
const PLATFORM_IDS_ATTEMPT_TIMEOUT_MS: u64 = 2000;
const PLATFORM_IDS_ATTEMPT_COUNT: u64 = 5;
pub extern "C" fn _dummy_event_callback(_: ffi::cl_event, _: i32, _: *mut c_void) {}
pub extern "C" fn _complete_user_event(
src_event_ptr: cl_event,
event_status: i32,
user_data: *mut c_void,
) {
#[cfg(not(feature = "event_debug_print"))]
let _ = src_event_ptr;
if event_status == CommandExecutionStatus::Complete as i32 && !user_data.is_null() {
let tar_event_ptr = user_data as *mut _ as cl_event;
unsafe {
let user_event = Event::from_raw(tar_event_ptr);
#[cfg(feature = "event_debug_print")]
println!(
"::_complete_user_event: Setting event complete for: \
source: {:?}, target: {:?}...",
src_event_ptr, &user_event
);
crate::set_user_event_status(&user_event, CommandExecutionStatus::Complete).unwrap();
}
#[cfg(feature = "event_debug_print")]
println!(
" - Event status has been set to 'CommandExecutionStatus::Complete' \
for event: {:?}",
tar_event_ptr
);
} else {
match CommandExecutionStatus::from_i32(event_status) {
Some(status_enum) => panic!(
"ocl_core::_complete_event: User data is null or event \
is not complete. Status: '{:?}'",
status_enum
),
None => eval_errcode(
event_status,
(),
"clSetEventCallback",
Some(format!("src_event_ptr: {:?}", src_event_ptr)),
)
.unwrap(),
}
}
}
static SDK_DOCS_URL_PRE: &'static str =
"https://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/";
static SDK_DOCS_URL_SUF: &'static str = ".html#errors";
#[derive(thiserror::Error)]
pub struct ApiError {
status: Status,
fn_name: &'static str,
fn_info: Option<String>,
}
impl ApiError {
pub fn new<S: Into<String>>(
errcode: i32,
fn_name: &'static str,
fn_info: Option<S>,
) -> ApiError {
let status = match Status::from_i32(errcode) {
Some(s) => s,
None => panic!(
"ocl_core::Error::err_status: Invalid error code: '{}'. \
Aborting.",
errcode
),
};
let fn_info = fn_info.map(|s| s.into());
ApiError {
status,
fn_name,
fn_info,
}
}
pub fn status(&self) -> Status {
self.status
}
}
impl fmt::Display for ApiError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let fn_info_string = if let Some(ref fn_info) = self.fn_info {
format!("(\"{}\")", fn_info)
} else {
String::with_capacity(0)
};
let status_int = self.status as i32;
write!(
f,
"\n\n\
################################ OPENCL ERROR ############################### \
\n\nError executing function: {}{} \
\n\nStatus error code: {:?} ({}) \
\n\nPlease visit the following url for more information: \n\n{}{}{} \n\n\
############################################################################# \n",
self.fn_name,
fn_info_string,
self.status,
status_int,
SDK_DOCS_URL_PRE,
self.fn_name,
SDK_DOCS_URL_SUF
)
}
}
impl fmt::Debug for ApiError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(&self, f)
}
}
#[inline(always)]
fn eval_errcode<T, S>(
errcode: cl_int,
result: T,
fn_name: &'static str,
fn_info: Option<S>,
) -> OclCoreResult<T>
where
S: Into<String>,
{
if (Status::CL_SUCCESS as i32) == errcode {
Ok(result)
} else {
Err(ApiError::new(errcode, fn_name, fn_info).into())
}
}
#[derive(Debug, thiserror::Error)]
pub enum ProgramBuildError {
#[error("Device list is empty. Aborting build.")]
DeviceListEmpty,
#[error(
"\n\n\
###################### OPENCL PROGRAM BUILD DEBUG OUTPUT \
######################\
\n\n{0}\n\
########################################################\
#######################\
\n\n"
)]
BuildLog(String),
#[error("{0}")]
InfoResult(Box<OclCoreError>),
}
pub fn program_build_err<D: ClDeviceIdPtr>(
program: &Program,
device_ids: &[D],
) -> Result<(), ProgramBuildError> {
if device_ids.is_empty() {
return Err(ProgramBuildError::DeviceListEmpty);
}
for device_id in device_ids.iter().cloned() {
match get_program_build_info(program, device_id, ProgramBuildInfo::BuildLog) {
Ok(ProgramBuildInfoResult::BuildLog(log)) => {
if log.len() > 1 {
return Err(ProgramBuildError::BuildLog(log));
}
}
Err(err) => return Err(ProgramBuildError::InfoResult(Box::new(err))),
_ => panic!("Unexpected 'ProgramBuildInfoResult' variant."),
}
}
Ok(())
}
#[allow(dead_code)]
#[derive(Debug)]
pub(crate) enum ApiFunction {
None,
RetainDevice,
ReleaseDevice,
CreateProgramWithIl,
CreateImage,
CreateFromGLTexture,
CreateFromD3D11Texture,
GetKernelArgInfo,
EnqueueFillBuffer,
EnqueueFillImage,
EnqueueMigrateMemObjects,
EnqueueMarkerWithWaitList,
EnqueueBarrierWithWaitList,
GetExtensionFunctionAddressForPlatform,
CompileProgram,
LinkProgram,
}
#[derive(Debug)]
pub(crate) enum VersionKind {
Device,
Platform,
}
#[derive(Debug, thiserror::Error)]
#[error("OpenCL ({kind:?}) version too low to use {function:?} (detected: {detected}, required: {required}).")]
pub struct VersionLowError {
detected: OpenclVersion,
required: OpenclVersion,
function: ApiFunction,
kind: VersionKind,
}
#[derive(Debug, thiserror::Error)]
pub enum ApiWrapperError {
#[error("Unable to get platform id list after {} seconds of waiting.", _0)]
GetPlatformIdsPlatformListUnavailable(u64),
#[error("`devices_max` can not be zero.")]
GetDeviceIdsDevicesMaxZero,
#[error("No devices specified.")]
CreateContextNoDevicesSpecified,
#[error("Buffer length and data length and do not match.")]
CreateBufferDataLengthMismatch,
#[error(
"One or more of the devices contained in the list provided to \
'::create_context` doesn't support the cl_gl_sharing extension and cannot be \
used to create a context associated with OpenGL. [FIXME: determine recommended \
resolution - gl_device list fn doesn't work yet]."
)]
CreateContextClGlSharingUnsupported,
#[error("Length of 'devices' must be greater than zero.")]
CreateProgramWithBinaryDevicesLenZero,
#[error(
"Length of 'devices' must equal the length of 'binaries' \
(e.g. one binary per device)."
)]
CreateProgramWithBinaryDevicesLenMismatch,
#[error(
"The specified function does not exist for the implementation or \
'platform' is not a valid platform."
)]
GetExtensionFunctionAddressForPlatformInvalidFunction,
#[error("No OpenCL platforms found. Check your driver.")]
DefaultPlatformNoPlatforms,
#[error(
"The default platform set by the environment variable \
'OCL_DEFAULT_PLATFORM_IDX' has an index which is out of range \
(index: [{default_platform_idx}], max: [{max_idx}])."
)]
DefaultPlatformEnvVarBadIdx {
default_platform_idx: usize,
max_idx: usize,
},
#[error(
"The default device type set by the environment variable \
'OCL_DEFAULT_DEVICE_TYPE': ('{0}') is invalid. Valid types are: 'DEFAULT', 'CPU', \
'GPU', 'ACCELERATOR', 'CUSTOM', and 'ALL'."
)]
DefaultDeviceTypeInvalidType(String),
#[error("The function pointer to {0} was not resolved.")]
ExtensionFunctionPointerNotResolved(String),
}
struct DevicePtrList(Vec<cl_device_id>);
impl DevicePtrList {
fn new<D: ClDeviceIdPtr>(devices: Option<&[D]>) -> DevicePtrList {
let list = match devices {
Some(device_ids) => device_ids.iter().map(|d| d.as_ptr()).collect::<Vec<_>>(),
None => Vec::new(),
};
DevicePtrList(list)
}
fn as_ptr(&self) -> *const cl_device_id {
match self.0.len() {
0 => ptr::null(),
_ => self.0.as_ptr(),
}
}
fn num(&self) -> u32 {
self.0.len() as u32
}
}
impl<D> From<Option<&[D]>> for DevicePtrList
where
D: ClDeviceIdPtr,
{
fn from(devices: Option<&[D]>) -> DevicePtrList {
DevicePtrList::new(devices)
}
}
fn resolve_event_ptrs<En: ClNullEventPtr, Ewl: ClWaitListPtr>(
wait_list: Option<Ewl>,
new_event: Option<En>,
) -> (cl_uint, *const cl_event, *mut cl_event) {
let (wait_list_len, wait_list_ptr) = match wait_list {
Some(wl) => {
if wl.count() > 0 {
(wl.count(), unsafe { wl.as_ptr_ptr() } as *const cl_event)
} else {
(0, ptr::null() as *const cl_event)
}
}
None => (0, ptr::null() as *const cl_event),
};
let new_event_ptr = match new_event {
Some(mut ne) => ne.alloc_new(),
None => ptr::null_mut() as *mut cl_event,
};
(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(w) => w as *const [usize; 3] as *const size_t,
None => ptr::null(),
}
}
pub(crate) fn verify_versions(
versions: &[OpenclVersion],
required_version: [u16; 2],
function: ApiFunction,
kind: VersionKind,
) -> OclCoreResult<()> {
let reqd_ver = OpenclVersion::from(required_version);
for &d_ver in versions {
if d_ver < reqd_ver {
return Err(VersionLowError {
detected: d_ver,
required: reqd_ver,
function,
kind,
}
.into());
}
}
Ok(())
}
fn verify_platform_version<V: ClVersions>(
provided_version: Option<&OpenclVersion>,
required_version: [u16; 2],
fallback_version_source: &V,
function: ApiFunction,
) -> OclCoreResult<()> {
match provided_version {
Some(pv) => {
let vers = [*pv];
verify_versions(&vers, required_version, function, VersionKind::Platform)
}
None => fallback_version_source.verify_platform_version(required_version),
}
}
fn verify_device_version<V: ClVersions>(
provided_version: Option<&OpenclVersion>,
required_version: [u16; 2],
fallback_version_source: &V,
function: ApiFunction,
) -> OclCoreResult<()> {
match provided_version {
Some(pv) => {
let ver = [*pv];
verify_versions(&ver, required_version, function, VersionKind::Device)
}
None => fallback_version_source.verify_device_versions(required_version),
}
}
fn verify_device_versions<V: ClVersions>(
provided_versions: Option<&[OpenclVersion]>,
required_version: [u16; 2],
fallback_versions_source: &V,
function: ApiFunction,
) -> OclCoreResult<()> {
match provided_versions {
Some(pv) => verify_versions(pv, required_version, function, VersionKind::Device),
None => fallback_versions_source.verify_device_versions(required_version),
}
}
pub fn get_platform_ids() -> OclCoreResult<Vec<PlatformId>> {
let mut num_platforms = 0 as cl_uint;
let mut errcode: cl_int =
unsafe { ffi::clGetPlatformIDs(0, ptr::null_mut(), &mut num_platforms) };
if errcode == Status::CL_PLATFORM_NOT_FOUND_KHR as i32 {
let sleep_ms = PLATFORM_IDS_ATTEMPT_TIMEOUT_MS;
let mut iters_rmng = PLATFORM_IDS_ATTEMPT_COUNT;
while errcode == Status::CL_PLATFORM_NOT_FOUND_KHR as i32 {
if iters_rmng == 0 {
return Err(ApiWrapperError::GetPlatformIdsPlatformListUnavailable(
(PLATFORM_IDS_ATTEMPT_COUNT * sleep_ms) / 1000,
)
.into());
}
thread::sleep(Duration::from_millis(sleep_ms));
errcode = unsafe { ffi::clGetPlatformIDs(0, ptr::null_mut(), &mut num_platforms) };
iters_rmng -= 1;
}
}
eval_errcode(errcode, (), "clGetPlatformIDs", None::<String>)?;
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 {
ffi::clGetPlatformIDs(
num_platforms,
platforms.as_mut_ptr() as *mut cl_platform_id,
ptr::null_mut(),
)
};
eval_errcode(errcode, platforms, "clGetPlatformIDs", None::<String>)
}
pub fn get_platform_info<P: ClPlatformIdPtr>(
platform: P,
request: PlatformInfo,
) -> OclCoreResult<PlatformInfoResult> {
let mut result_size = 0 as size_t;
let errcode = unsafe {
ffi::clGetPlatformInfo(
platform.as_ptr(),
request as cl_platform_info,
0 as size_t,
ptr::null_mut(),
&mut result_size as *mut size_t,
)
};
eval_errcode(errcode, (), "clGetPlatformInfo", None::<String>)?;
if result_size == 0 {
return PlatformInfoResult::from_bytes(request, vec![]);
}
let mut result: Vec<u8> = iter::repeat(32u8).take(result_size as usize).collect();
let errcode = unsafe {
ffi::clGetPlatformInfo(
platform.as_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 = eval_errcode(errcode, result, "clGetPlatformInfo", None::<String>)?;
PlatformInfoResult::from_bytes(request, result)
}
pub fn get_device_ids<P: ClPlatformIdPtr>(
platform: P,
device_types: Option<DeviceType>,
devices_max: Option<u32>,
) -> OclCoreResult<Vec<DeviceId>> {
let device_types = device_types.unwrap_or(default_device_type()?);
let mut devices_available: cl_uint = 0;
let devices_max = match devices_max {
Some(d) => {
if d == 0 {
return Err(ApiWrapperError::GetDeviceIdsDevicesMaxZero.into());
} else {
d
}
}
None => crate::DEVICES_MAX,
};
let mut device_ids: Vec<DeviceId> = iter::repeat(unsafe { DeviceId::null() })
.take(devices_max as usize)
.collect();
let errcode = unsafe {
ffi::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,
)
};
eval_errcode(errcode, (), "clGetDeviceIDs", None::<String>)?;
unsafe {
device_ids.set_len(devices_available as usize);
}
device_ids.shrink_to_fit();
Ok(device_ids)
}
pub fn get_device_info_raw<D: ClDeviceIdPtr>(device: D, request: u32) -> OclCoreResult<Vec<u8>> {
let mut result_size: size_t = 0;
let errcode = unsafe {
ffi::clGetDeviceInfo(
device.as_ptr() as cl_device_id,
request as cl_device_info,
0 as size_t,
ptr::null_mut(),
&mut result_size as *mut size_t,
)
};
if errcode < 0 {
if Status::from_i32(errcode).unwrap() == Status::CL_INVALID_VALUE {
return Err(OclCoreError::String(
"<unavailable (CL_INVALID_VALUE)>".to_string(),
));
} else if Status::from_i32(errcode).unwrap() == Status::CL_INVALID_OPERATION {
return Err(OclCoreError::String(
"<unavailable (CL_INVALID_OPERATION)>".to_string(),
));
}
}
eval_errcode(errcode, (), "clGetDeviceInfo", None::<String>)?;
if result_size == 0 {
return Ok(vec![]);
}
let mut result: Vec<u8> = iter::repeat(0u8).take(result_size).collect();
let errcode = unsafe {
ffi::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,
ptr::null_mut(),
)
};
eval_errcode(errcode, result, "clGetDeviceInfo", None::<String>)
}
pub fn get_device_info<D: ClDeviceIdPtr>(
device: D,
request: DeviceInfo,
) -> OclCoreResult<DeviceInfoResult> {
let result = get_device_info_raw(device, request as cl_device_info)?;
match request {
DeviceInfo::MaxWorkItemSizes => {
let max_wi_dims = match get_device_info(device, DeviceInfo::MaxWorkItemDimensions)? {
DeviceInfoResult::MaxWorkItemDimensions(d) => d,
_ => panic!(
"get_device_info(): Error determining dimensions for \
'DeviceInfo::MaxWorkItemSizes' due to mismatched variants."
),
};
DeviceInfoResult::from_bytes_max_work_item_sizes(request, result, max_wi_dims)
}
_ => DeviceInfoResult::from_bytes(request, result),
}
}
pub fn create_sub_devices(device_version: Option<&OpenclVersion>) -> OclCoreResult<()> {
let _ = device_version;
unimplemented!();
}
pub unsafe fn retain_device(
device: &DeviceId,
device_version: Option<&OpenclVersion>,
) -> OclCoreResult<()> {
verify_device_version(device_version, [1, 2], device, ApiFunction::RetainDevice)?;
eval_errcode(
ffi::clRetainDevice(device.as_ptr()),
(),
"clRetainDevice",
None::<String>,
)
}
pub unsafe fn release_device(
device: &DeviceId,
device_version: Option<&OpenclVersion>,
) -> OclCoreResult<()> {
verify_device_version(device_version, [1, 2], device, ApiFunction::ReleaseDevice)?;
eval_errcode(
ffi::clReleaseDevice(device.as_ptr()),
(),
"clReleaseDevice",
None::<String>,
)
}
pub fn create_context<D: ClDeviceIdPtr>(
properties: Option<&ContextProperties>,
device_ids: &[D],
pfn_notify: Option<CreateContextCallbackFn>,
user_data: Option<UserDataPtr>,
) -> OclCoreResult<Context> {
if device_ids.is_empty() {
return Err(ApiWrapperError::CreateContextNoDevicesSpecified.into());
}
if let Some(properties) = properties {
if properties.contains_gl_context_or_sharegroup() {
for &device in device_ids {
match device_supports_cl_gl_sharing(device) {
Ok(true) => {}
Ok(false) => {
return Err(ApiWrapperError::CreateContextClGlSharingUnsupported.into())
}
Err(err) => return Err(err),
}
}
}
}
let properties_bytes: Vec<isize> = match properties {
Some(props) => props.to_raw(),
None => Vec::<isize>::with_capacity(0),
};
let properties_ptr = if properties_bytes.is_empty() {
ptr::null() as *const cl_context_properties
} else {
properties_bytes.as_ptr()
};
let user_data_ptr = match user_data {
Some(_) => ptr::null_mut(),
None => ptr::null_mut(),
};
let device_ids: Vec<_> = device_ids.iter().map(|d| d.as_ptr()).collect();
let mut errcode: cl_int = 0;
let context_ptr = unsafe {
ffi::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,
)
};
eval_errcode(errcode, context_ptr, "clCreateContext", None::<String>)
.map(|ctx_ptr| unsafe { Context::from_raw_create_ptr(ctx_ptr) })
}
pub fn create_context_from_type<D: ClDeviceIdPtr>(
properties: Option<&ContextProperties>,
device_type: DeviceType,
pfn_notify: Option<CreateContextCallbackFn>,
user_data: Option<UserDataPtr>,
) -> OclCoreResult<Context> {
let properties_bytes: Vec<isize> = match properties {
Some(props) => props.to_raw(),
None => Vec::<isize>::with_capacity(0),
};
let properties_ptr = if properties_bytes.is_empty() {
ptr::null() as *const cl_context_properties
} else {
properties_bytes.as_ptr()
};
let user_data_ptr = match user_data {
Some(_) => ptr::null_mut(),
None => ptr::null_mut(),
};
let mut errcode: cl_int = 0;
let context_ptr = unsafe {
ffi::clCreateContextFromType(
properties_ptr,
device_type.bits(),
pfn_notify,
user_data_ptr,
&mut errcode,
)
};
eval_errcode(
errcode,
context_ptr,
"clCreateContextFromType",
None::<String>,
)
.map(|ctx_ptr| unsafe { Context::from_raw_create_ptr(ctx_ptr) })
}
pub unsafe fn retain_context<C>(context: C) -> OclCoreResult<()>
where
C: ClContextPtr,
{
eval_errcode(
ffi::clRetainContext(context.as_ptr()),
(),
"clRetainContext",
None::<String>,
)
}
pub unsafe fn release_context<C>(context: C) -> OclCoreResult<()>
where
C: ClContextPtr,
{
eval_errcode(
ffi::clReleaseContext(context.as_ptr()),
(),
"clReleaseContext",
None::<String>,
)
}
fn get_context_info_unparsed<C>(context: C, request: ContextInfo) -> OclCoreResult<Vec<u8>>
where
C: ClContextPtr,
{
let mut result_size: size_t = 0;
let errcode = unsafe {
ffi::clGetContextInfo(
context.as_ptr() as cl_context,
request as cl_context_info,
0 as size_t,
ptr::null_mut(),
&mut result_size as *mut usize,
)
};
eval_errcode(errcode, (), "clGetContextInfo", None::<String>)?;
if !cfg!(release) {
let err_if_zero_result_size = request as cl_context_info == ffi::CL_CONTEXT_DEVICES;
if result_size > 10000 || (result_size == 0 && err_if_zero_result_size) {
return Err(OclCoreError::String(
"\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"
.to_string(),
));
}
}
if result_size == 0 {
return Ok(vec![]);
}
let mut result: Vec<u8> = iter::repeat(0).take(result_size).collect();
let errcode = unsafe {
ffi::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,
ptr::null_mut(),
)
};
eval_errcode(errcode, result, "clGetContextInfo", None::<String>)
}
pub fn get_context_info<C>(context: C, request: ContextInfo) -> OclCoreResult<ContextInfoResult>
where
C: ClContextPtr,
{
ContextInfoResult::from_bytes(request, get_context_info_unparsed(context, request)?)
}
pub fn get_context_platform<C>(context: C) -> OclCoreResult<Option<PlatformId>>
where
C: ClContextPtr,
{
let props_raw_bytes = get_context_info_unparsed(context, ContextInfo::Properties)?;
let prop = unsafe {
let props_raw = crate::util::bytes_into_vec::<isize>(props_raw_bytes)?;
ContextProperties::extract_property_from_raw(crate::ContextProperty::Platform, &props_raw)
};
if let Some(crate::ContextPropertyValue::Platform(plat)) = prop {
Ok(Some(plat))
} else {
Ok(None)
}
}
#[cfg(not(feature = "opencl_vendor_mesa"))]
pub fn get_gl_context_info_khr(
properties: &ContextProperties,
request: GlContextInfo,
) -> OclCoreResult<GlContextInfoResult> {
let cl_get_gl_context_info_khr_fn: ffi::clGetGLContextInfoKHR_fn = unsafe {
let fn_name = match ::std::ffi::CString::new("clGetGLContextInfoKHR") {
Ok(s) => s,
Err(err) => return Err(err.into()),
};
let plat = match properties.get_platform() {
Some(p) => p,
None => {
return Err("ocl::core::get_gl_context_info_khr: \
Context properties must specify a platform."
.into());
}
};
let fn_ptr = ffi::clGetExtensionFunctionAddressForPlatform(
plat.as_ptr(),
fn_name.as_ptr() as *mut _,
);
if fn_ptr.is_null() {
return Err("Unable to get extension function \
address for clGetGLContextInfoKHR. The function is not supported by this \
platform."
.into());
}
std::mem::transmute(fn_ptr)
};
let props_bytes = properties.to_raw();
let mut result_size: size_t = 0;
let errcode = cl_get_gl_context_info_khr_fn(
props_bytes.as_ptr(),
request as cl_gl_context_info,
0 as size_t,
ptr::null_mut(),
&mut result_size as *mut usize,
);
eval_errcode(errcode, (), "clGetGlContextInfoKhr", None::<String>)?;
if result_size == 0 {
return GlContextInfoResult::from_bytes(request, vec![]);
}
let mut result: Vec<u8> = iter::repeat(0).take(result_size).collect();
let errcode = cl_get_gl_context_info_khr_fn(
props_bytes.as_ptr(),
request as cl_gl_context_info,
result_size as size_t,
result.as_mut_ptr() as *mut c_void,
ptr::null_mut(),
);
let result = eval_errcode(errcode, result, "clGetGlContextInfoKhr", None::<String>)?;
GlContextInfoResult::from_bytes(request, result)
}
pub fn create_command_queue<C, D>(
context: C,
device: D,
properties: Option<CommandQueueProperties>,
) -> OclCoreResult<CommandQueue>
where
C: ClContextPtr,
D: ClDeviceIdPtr,
{
verify_context(context)?;
let cmd_queue_props = match properties {
Some(p) => p.bits,
None => 0,
};
let mut errcode: cl_int = 0;
let cq_ptr = unsafe {
ffi::clCreateCommandQueue(
context.as_ptr(),
device.as_ptr(),
cmd_queue_props,
&mut errcode,
)
};
eval_errcode(errcode, cq_ptr, "clCreateCommandQueue", None::<String>)
.map(|cq_ptr| unsafe { CommandQueue::from_raw_create_ptr(cq_ptr) })
}
pub unsafe fn retain_command_queue(queue: &CommandQueue) -> OclCoreResult<()> {
eval_errcode(
ffi::clRetainCommandQueue(queue.as_ptr()),
(),
"clRetainCommandQueue",
None::<String>,
)
}
pub unsafe fn release_command_queue(queue: &CommandQueue) -> OclCoreResult<()> {
eval_errcode(
ffi::clReleaseCommandQueue(queue.as_ptr()),
(),
"clReleaseCommandQueue",
None::<String>,
)
}
pub fn get_command_queue_info(
queue: &CommandQueue,
request: CommandQueueInfo,
) -> OclCoreResult<CommandQueueInfoResult> {
let mut result_size: size_t = 0;
let errcode = unsafe {
ffi::clGetCommandQueueInfo(
queue.as_ptr() as cl_command_queue,
request as cl_command_queue_info,
0 as size_t,
ptr::null_mut(),
&mut result_size as *mut size_t,
)
};
eval_errcode(errcode, (), "clGetCommandQueueInfo", None::<String>)?;
if result_size == 0 {
return CommandQueueInfoResult::from_bytes(request, vec![]);
}
let mut result: Vec<u8> = iter::repeat(0u8).take(result_size).collect();
let errcode = unsafe {
ffi::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,
ptr::null_mut(),
)
};
let result = eval_errcode(errcode, result, "clGetCommandQueueInfo", None::<String>)?;
CommandQueueInfoResult::from_bytes(request, result)
}
pub unsafe fn create_buffer<C, T>(
context: C,
flags: MemFlags,
len: usize,
data: Option<&[T]>,
) -> OclCoreResult<Mem>
where
C: ClContextPtr,
T: OclPrm,
{
verify_context(context)?;
let mut errcode: cl_int = 0;
let host_ptr = match data {
Some(d) => {
if d.len() != len {
return Err(ApiWrapperError::CreateBufferDataLengthMismatch.into());
}
d.as_ptr() as cl_mem
}
None => ptr::null_mut(),
};
let buf_ptr = ffi::clCreateBuffer(
context.as_ptr(),
flags.bits() as cl_mem_flags,
len * mem::size_of::<T>(),
host_ptr,
&mut errcode,
);
eval_errcode(errcode, buf_ptr, "clCreateBuffer", None::<String>)
.map(|ptr| Mem::from_raw_create_ptr(ptr))
}
#[cfg(not(feature = "opencl_vendor_mesa"))]
pub unsafe fn create_from_gl_buffer<C>(
context: C,
gl_object: cl_GLuint,
flags: MemFlags,
) -> OclCoreResult<Mem>
where
C: ClContextPtr,
{
verify_context(context)?;
let mut errcode: cl_int = 0;
let buf_ptr = clCreateFromGLBuffer(
context.as_ptr(),
flags.bits() as cl_mem_flags,
gl_object,
&mut errcode,
);
eval_errcode(errcode, buf_ptr, "clCreateFromGLBuffer", None::<String>)
.map(|ptr| Mem::from_raw_create_ptr(ptr))
}
#[cfg(not(feature = "opencl_vendor_mesa"))]
pub unsafe fn create_from_gl_renderbuffer<C>(
context: C,
renderbuffer: cl_GLuint,
flags: MemFlags,
) -> OclCoreResult<Mem>
where
C: ClContextPtr,
{
verify_context(context)?;
let mut errcode: cl_int = 0;
let buf_ptr = clCreateFromGLRenderbuffer(
context.as_ptr(),
flags.bits() as cl_mem_flags,
renderbuffer,
&mut errcode,
);
eval_errcode(
errcode,
buf_ptr,
"clCreateFromGLRenderbuffer",
None::<String>,
)
.map(|ptr| Mem::from_raw_create_ptr(ptr))
}
#[cfg(not(feature = "opencl_vendor_mesa"))]
pub unsafe fn create_from_gl_texture<C>(
context: C,
texture_target: cl_GLenum,
miplevel: cl_GLint,
texture: cl_GLuint,
flags: MemFlags,
device_versions: Option<&[OpenclVersion]>,
) -> OclCoreResult<Mem>
where
C: ClContextPtr,
{
verify_context(context)?;
verify_device_versions(
device_versions,
[1, 2],
&context.as_ptr(),
ApiFunction::CreateFromGLTexture,
)?;
let mut errcode: cl_int = 0;
let buf_ptr = clCreateFromGLTexture(
context.as_ptr(),
flags.bits() as cl_mem_flags,
texture_target,
miplevel,
texture,
&mut errcode,
);
eval_errcode(errcode, buf_ptr, "clCreateFromGLTexture", None::<String>)
.map(|ptr| Mem::from_raw_create_ptr(ptr))
}
#[cfg(not(feature = "opencl_vendor_mesa"))]
pub unsafe fn create_from_gl_texture_2d<C>(
context: C,
texture_target: cl_GLenum,
miplevel: cl_GLint,
texture: cl_GLuint,
flags: MemFlags,
) -> OclCoreResult<Mem>
where
C: ClContextPtr,
{
verify_context(context)?;
let mut errcode: cl_int = 0;
let buf_ptr = clCreateFromGLTexture2D(
context.as_ptr(),
flags.bits() as cl_mem_flags,
texture_target,
miplevel,
texture,
&mut errcode,
);
eval_errcode(errcode, buf_ptr, "clCreateFromGLTexture2D", None::<String>)
.map(|ptr| Mem::from_raw_create_ptr(ptr))
}
#[cfg(not(feature = "opencl_vendor_mesa"))]
pub unsafe fn create_from_gl_texture_3d<C>(
context: C,
texture_target: cl_GLenum,
miplevel: cl_GLint,
texture: cl_GLuint,
flags: MemFlags,
) -> OclCoreResult<Mem>
where
C: ClContextPtr,
{
verify_context(context)?;
let mut errcode: cl_int = 0;
let buf_ptr = clCreateFromGLTexture3D(
context.as_ptr(),
flags.bits() as cl_mem_flags,
texture_target,
miplevel,
texture,
&mut errcode,
);
eval_errcode(errcode, buf_ptr, "clCreateFromGLTexture3D", None::<String>)
.map(|ptr| Mem::from_raw_create_ptr(ptr))
}
pub unsafe fn create_from_d3d11_buffer<C>(
context: C,
buffer: ffi::cl_id3d11_buffer,
flags: MemFlags,
extension_fns: &crate::ExtensionFunctions,
) -> OclCoreResult<Mem>
where
C: ClContextPtr,
{
verify_context(context)?;
match extension_fns.clCreateFromD3D11Buffer {
Some(func) => {
let mut errcode: cl_int = 0;
let buf_ptr = func(
context.as_ptr(),
flags.bits() as cl_mem_flags,
buffer,
&mut errcode,
);
eval_errcode(errcode, buf_ptr, "clCreateFromD3D11Buffer", None::<String>)
.map(|ptr| Mem::from_raw_create_ptr(ptr))
}
None => Err(ApiWrapperError::ExtensionFunctionPointerNotResolved(
"clCreateFromD3D11Buffer".into(),
)
.into()),
}
}
pub unsafe fn create_from_d3d11_texture2d<C>(
context: C,
texture: ffi::cl_id3d11_texture2d,
subresource: cl_uint,
flags: MemFlags,
device_versions: Option<&[OpenclVersion]>,
extension_fns: &crate::ExtensionFunctions,
) -> OclCoreResult<Mem>
where
C: ClContextPtr,
{
verify_context(context)?;
verify_device_versions(
device_versions,
[1, 2],
&context.as_ptr(),
ApiFunction::CreateFromD3D11Texture,
)?;
match extension_fns.clCreateFromD3D11Texture2D {
Some(func) => {
let mut errcode: cl_int = 0;
let buf_ptr = func(
context.as_ptr(),
flags.bits() as cl_mem_flags,
texture,
subresource,
&mut errcode,
);
eval_errcode(
errcode,
buf_ptr,
"clCreateFromD3D11Texture2D",
None::<String>,
)
.map(|ptr| Mem::from_raw_create_ptr(ptr))
}
None => Err(ApiWrapperError::ExtensionFunctionPointerNotResolved(
"clCreateFromD3D11Texture2D".into(),
)
.into()),
}
}
pub unsafe fn create_from_d3d11_texture3d<C>(
context: C,
texture: ffi::cl_id3d11_texture3d,
subresource: cl_uint,
flags: MemFlags,
device_versions: Option<&[OpenclVersion]>,
extension_fns: &crate::ExtensionFunctions,
) -> OclCoreResult<Mem>
where
C: ClContextPtr,
{
verify_context(context)?;
verify_device_versions(
device_versions,
[1, 2],
&context.as_ptr(),
ApiFunction::CreateFromD3D11Texture,
)?;
match extension_fns.clCreateFromD3D11Texture3D {
Some(func) => {
let mut errcode: cl_int = 0;
let buf_ptr = func(
context.as_ptr(),
flags.bits() as cl_mem_flags,
texture,
subresource,
&mut errcode,
);
eval_errcode(
errcode,
buf_ptr,
"clCreateFromD3D11Texture3D",
None::<String>,
)
.map(|ptr| Mem::from_raw_create_ptr(ptr))
}
None => Err(ApiWrapperError::ExtensionFunctionPointerNotResolved(
"clCreateFromD3D11Texture3D".into(),
)
.into()),
}
}
pub fn enqueue_acquire_d3d11_objects<En, Ewl>(
command_queue: &CommandQueue,
buffers: &[Mem],
wait_list: Option<Ewl>,
new_event: Option<En>,
extension_fns: &crate::ExtensionFunctions,
) -> OclCoreResult<()>
where
En: ClNullEventPtr,
Ewl: ClWaitListPtr,
{
let (wait_list_len, wait_list_ptr, new_event_ptr) = resolve_event_ptrs(wait_list, new_event);
match extension_fns.clEnqueueAcquireD3D11Objects {
Some(func) => {
let errcode = func(
command_queue.as_ptr(),
buffers.len() as u32,
buffers.as_ptr() as *const cl_mem,
wait_list_len,
wait_list_ptr,
new_event_ptr,
);
eval_errcode(errcode, (), "clEnqueueAcquireD3D11Objects", None::<String>)
}
None => Err(ApiWrapperError::ExtensionFunctionPointerNotResolved(
"clEnqueueAcquireD3D11Objects".into(),
)
.into()),
}
}
pub fn enqueue_release_d3d11_objects<En, Ewl>(
command_queue: &CommandQueue,
buffers: &[Mem],
wait_list: Option<Ewl>,
new_event: Option<En>,
extension_fns: &crate::ExtensionFunctions,
) -> OclCoreResult<()>
where
En: ClNullEventPtr,
Ewl: ClWaitListPtr,
{
let (wait_list_len, wait_list_ptr, new_event_ptr) = resolve_event_ptrs(wait_list, new_event);
match extension_fns.clEnqueueReleaseD3D11Objects {
Some(func) => {
let errcode = func(
command_queue.as_ptr(),
buffers.len() as u32,
buffers.as_ptr() as *const cl_mem,
wait_list_len,
wait_list_ptr,
new_event_ptr,
);
eval_errcode(errcode, (), "clEnqueueReleaseD3D11Objects", None::<String>)
}
None => Err(ApiWrapperError::ExtensionFunctionPointerNotResolved(
"clEnqueueReleaseD3D11Objects".into(),
)
.into()),
}
}
pub fn create_sub_buffer<T: OclPrm>(
buffer: &Mem,
flags: MemFlags,
buffer_create_info: &BufferRegion<T>,
) -> OclCoreResult<Mem> {
let buffer_create_type = BufferCreateType::Region;
let buffer_create_info_bytes = buffer_create_info.to_bytes();
let mut errcode = 0i32;
let sub_buf_ptr = unsafe {
ffi::clCreateSubBuffer(
buffer.as_ptr(),
flags.bits(),
buffer_create_type as cl_buffer_create_type,
&buffer_create_info_bytes as *const _ as *const c_void,
&mut errcode,
)
};
eval_errcode(errcode, sub_buf_ptr, "clCreateSubBuffer", None::<String>)
.map(|ptr| unsafe { Mem::from_raw_create_ptr(ptr) })
}
pub unsafe fn create_image<C, T>(
context: C,
flags: MemFlags,
format: &ImageFormat,
desc: &ImageDescriptor,
data: Option<&[T]>,
device_versions: Option<&[OpenclVersion]>,
) -> OclCoreResult<Mem>
where
C: ClContextPtr,
T: OclPrm,
{
verify_context(context)?;
verify_device_versions(
device_versions,
[1, 2],
&context.as_ptr(),
ApiFunction::CreateImage,
)?;
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 = ffi::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,
);
eval_errcode(errcode, image_ptr, "clCreateImage", None::<String>)
.map(|ptr| Mem::from_raw_create_ptr(ptr))
}
pub unsafe fn retain_mem_object(mem: &Mem) -> OclCoreResult<()> {
eval_errcode(
ffi::clRetainMemObject(mem.as_ptr()),
(),
"clRetainMemObject",
None::<String>,
)
}
pub unsafe fn release_mem_object(mem: &Mem) -> OclCoreResult<()> {
eval_errcode(
ffi::clReleaseMemObject(mem.as_ptr()),
(),
"clReleaseMemObject",
None::<String>,
)
}
pub fn get_supported_image_formats<C>(
context: C,
flags: MemFlags,
image_type: MemObjectType,
) -> OclCoreResult<Vec<ImageFormatParseResult>>
where
C: ClContextPtr,
{
let mut num_image_formats = 0 as cl_uint;
let errcode = unsafe {
ffi::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,
)
};
eval_errcode(errcode, (), "clGetSupportedImageFormats", None::<String>)?;
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.is_empty());
let errcode = unsafe {
ffi::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,
ptr::null_mut(),
)
};
eval_errcode(errcode, (), "clGetSupportedImageFormats", None::<String>)?;
Ok(ImageFormat::list_from_raw(image_formats))
}
pub fn get_mem_object_info(obj: &Mem, request: MemInfo) -> OclCoreResult<MemInfoResult> {
let mut result_size: size_t = 0;
let errcode = unsafe {
ffi::clGetMemObjectInfo(
obj.as_ptr() as cl_mem,
request as cl_mem_info,
0 as size_t,
ptr::null_mut(),
&mut result_size as *mut size_t,
)
};
eval_errcode(errcode, (), "clGetMemObjectInfo", None::<String>)?;
if result_size == 0 {
return MemInfoResult::from_bytes(request, vec![]);
}
let mut result: Vec<u8> = iter::repeat(0u8).take(result_size).collect();
let errcode = unsafe {
ffi::clGetMemObjectInfo(
obj.as_ptr() as cl_mem,
request as cl_mem_info,
result_size,
result.as_mut_ptr() as *mut _ as *mut c_void,
ptr::null_mut(),
)
};
let result = eval_errcode(errcode, result, "clGetMemObjectInfo", None::<String>)?;
MemInfoResult::from_bytes(request, result)
}
pub fn get_image_info(obj: &Mem, request: ImageInfo) -> OclCoreResult<ImageInfoResult> {
let mut result_size: size_t = 0;
let errcode = unsafe {
ffi::clGetImageInfo(
obj.as_ptr() as cl_mem,
request as cl_image_info,
0 as size_t,
ptr::null_mut(),
&mut result_size as *mut size_t,
)
};
eval_errcode(errcode, (), "clGetImageInfo", None::<String>)?;
if result_size == 0 {
return ImageInfoResult::from_bytes(request, vec![]);
}
let mut result: Vec<u8> = iter::repeat(0u8).take(result_size).collect();
let errcode = unsafe {
ffi::clGetImageInfo(
obj.as_ptr() as cl_mem,
request as cl_image_info,
result_size,
result.as_mut_ptr() as *mut _ as *mut c_void,
ptr::null_mut(),
)
};
let result = eval_errcode(errcode, result, "clGetImageInfo", None::<String>)?;
ImageInfoResult::from_bytes(request, result)
}
pub fn set_mem_object_destructor_callback() -> OclCoreResult<()> {
unimplemented!();
}
pub fn create_sampler<C>(
context: C,
normalize_coords: bool,
addressing_mode: AddressingMode,
filter_mode: FilterMode,
) -> OclCoreResult<Sampler>
where
C: ClContextPtr,
{
let mut errcode = 0;
let sampler = unsafe {
Sampler::from_raw_create_ptr(ffi::clCreateSampler(
context.as_ptr(),
normalize_coords as cl_bool,
addressing_mode as cl_addressing_mode,
filter_mode as cl_filter_mode,
&mut errcode,
))
};
eval_errcode(errcode, sampler, "clCreateSampler", None::<String>)
}
pub unsafe fn retain_sampler(sampler: &Sampler) -> OclCoreResult<()> {
eval_errcode(
ffi::clRetainSampler(sampler.as_ptr()),
(),
"clRetainSampler",
None::<String>,
)
}
pub unsafe fn release_sampler(sampler: &Sampler) -> OclCoreResult<()> {
eval_errcode(
ffi::clReleaseSampler(sampler.as_ptr()),
(),
"clReleaseSampler",
None::<String>,
)
}
pub fn get_sampler_info(obj: &Sampler, request: SamplerInfo) -> OclCoreResult<SamplerInfoResult> {
let mut result_size: size_t = 0;
let errcode = unsafe {
ffi::clGetSamplerInfo(
obj.as_ptr() as cl_sampler,
request as cl_sampler_info,
0 as size_t,
ptr::null_mut(),
&mut result_size as *mut size_t,
)
};
eval_errcode(errcode, (), "clGetSamplerInfo", None::<String>)?;
if result_size == 0 {
return SamplerInfoResult::from_bytes(request, vec![]);
}
let mut result: Vec<u8> = iter::repeat(0u8).take(result_size).collect();
let errcode = unsafe {
ffi::clGetSamplerInfo(
obj.as_ptr() as cl_sampler,
request as cl_sampler_info,
result_size,
result.as_mut_ptr() as *mut _ as *mut c_void,
ptr::null_mut(),
)
};
let result = eval_errcode(errcode, result, "clGetSamplerInfo", None::<String>)?;
SamplerInfoResult::from_bytes(request, result)
}
pub fn create_program_with_source<C>(context: C, src_strings: &[CString]) -> OclCoreResult<Program>
where
C: ClContextPtr,
{
verify_context(context)?;
let ks_lens: Vec<usize> = src_strings.iter().map(|cs| cs.as_bytes().len()).collect();
let kern_string_ptrs: Vec<*const _> = src_strings.iter().map(|cs| cs.as_ptr()).collect();
let mut errcode: cl_int = 0;
let program_ptr = unsafe {
ffi::clCreateProgramWithSource(
context.as_ptr(),
kern_string_ptrs.len() as cl_uint,
kern_string_ptrs.as_ptr() as *const *const _,
ks_lens.as_ptr() as *const usize,
&mut errcode,
)
};
eval_errcode(
errcode,
program_ptr,
"clCreateProgramWithSource",
None::<String>,
)
.map(|ptr| unsafe { Program::from_raw_create_ptr(ptr) })
}
pub fn create_program_with_binary<C, D>(
context: C,
devices: &[D],
binaries: &[&[u8]],
) -> OclCoreResult<Program>
where
C: ClContextPtr,
D: ClDeviceIdPtr,
{
if devices.is_empty() {
return Err(ApiWrapperError::CreateProgramWithBinaryDevicesLenZero.into());
}
if devices.len() != binaries.len() {
return Err(ApiWrapperError::CreateProgramWithBinaryDevicesLenMismatch.into());
}
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 ptrs = binaries.iter().map(|bin| bin.as_ptr()).collect::<Vec<_>>();
let program = unsafe {
ffi::clCreateProgramWithBinary(
context.as_ptr(),
devices.len() as u32,
devices.as_ptr() as *const _ as *const cl_device_id,
lengths.as_ptr(),
ptrs.as_ptr() as *const *const u8,
binary_status.as_mut_ptr(),
&mut errcode,
)
};
eval_errcode(errcode, (), "clCreateProgramWithBinary", None::<String>)?;
for (i, item) in binary_status.iter().enumerate() {
eval_errcode(
*item,
(),
"clCreateProgramWithBinary",
Some(format!("Device [{}]", i)),
)?;
}
unsafe { Ok(Program::from_raw_create_ptr(program)) }
}
pub fn create_program_with_built_in_kernels(
device_version: Option<&OpenclVersion>,
) -> OclCoreResult<()> {
let _ = device_version;
unimplemented!();
}
#[cfg(feature = "opencl_version_2_1")]
pub fn create_program_with_il<C>(
context: C,
il: &[u8],
device_versions: Option<&[OpenclVersion]>,
) -> OclCoreResult<Program>
where
C: ClContextPtr + ClVersions,
{
verify_device_versions(
device_versions,
[2, 1],
&context,
ApiFunction::CreateProgramWithIl,
)?;
let mut errcode: cl_int = 0;
let program_ptr = unsafe {
ffi::clCreateProgramWithIL(
context.as_ptr(),
il.as_ptr() as *mut c_void,
il.len(),
&mut errcode,
)
};
eval_errcode(
errcode,
program_ptr,
"clCreateProgramWithIL",
None::<String>,
)
.map(|ptr| unsafe { Program::from_raw_create_ptr(ptr) })
}
pub unsafe fn retain_program(program: &Program) -> OclCoreResult<()> {
eval_errcode(
ffi::clRetainProgram(program.as_ptr()),
(),
"clRetainProgram",
None::<String>,
)
}
pub unsafe fn release_program(program: &Program) -> OclCoreResult<()> {
eval_errcode(
ffi::clReleaseProgram(program.as_ptr()),
(),
"clReleaseKernel",
None::<String>,
)
}
pub struct UserDataPh(usize);
impl UserDataPh {
fn unwrapped(&self) -> *mut c_void {
ptr::null_mut()
}
}
pub fn build_program<D: ClDeviceIdPtr>(
program: &Program,
devices: Option<&[D]>,
options: &CString,
pfn_notify: Option<BuildProgramCallbackFn>,
user_data: Option<Box<UserDataPh>>,
) -> OclCoreResult<()> {
assert!(
pfn_notify.is_none() && user_data.is_none(),
"ocl::core::build_program(): Callback functions not yet implemented."
);
let device_ptrs = DevicePtrList::from(devices);
let user_data = match user_data {
Some(ud) => ud.unwrapped(),
None => ptr::null_mut(),
};
let errcode = unsafe {
ffi::clBuildProgram(
program.as_ptr() as cl_program,
device_ptrs.num(),
device_ptrs.as_ptr(),
options.as_ptr(),
pfn_notify,
user_data,
)
};
if errcode == Status::CL_BUILD_PROGRAM_FAILURE as i32 {
if let Some(ds) = devices {
program_build_err(program, ds).map_err(|err| err.into())
} else {
let ds = program.devices()?;
program_build_err(program, &ds).map_err(|err| err.into())
}
} else {
eval_errcode(errcode, (), "clBuildProgram", None::<String>)
}
}
#[cfg(feature = "opencl_version_1_2")]
pub fn compile_program<D: ClDeviceIdPtr>(
program: &Program,
devices: Option<&[D]>,
options: &CString,
input_headers: &[&Program],
header_include_names: &[CString],
pfn_notify: Option<BuildProgramCallbackFn>,
user_data: Option<Box<UserDataPh>>,
device_versions: Option<&[OpenclVersion]>,
) -> OclCoreResult<()> {
verify_device_versions(
device_versions,
[1, 2],
program,
ApiFunction::CompileProgram,
)?;
assert!(
pfn_notify.is_none() && user_data.is_none(),
"ocl::core::compile_program(): Callback functions not yet implemented."
);
assert!(input_headers.len() == header_include_names.len(),
"ocl::core::compile_program(): Length of input_headers and header_include_names should be equal.");
let device_ptrs = DevicePtrList::new(devices);
let input_hdrs_ptrs: Vec<_> = input_headers.iter().map(|cs| cs.as_ptr()).collect();
let hdrs_names_ptrs: Vec<*const _> =
header_include_names.iter().map(|cs| cs.as_ptr()).collect();
let (input_ptr, names_ptr) = if input_headers.is_empty() {
(ptr::null(), ptr::null())
} else {
(input_hdrs_ptrs.as_ptr(), hdrs_names_ptrs.as_ptr())
};
let user_data = match user_data {
Some(ud) => ud.unwrapped(),
None => ptr::null_mut(),
};
let errcode = unsafe {
ffi::clCompileProgram(
program.as_ptr() as cl_program,
device_ptrs.num(),
device_ptrs.as_ptr(),
options.as_ptr(),
input_hdrs_ptrs.len() as cl_uint,
input_ptr as *const cl_program,
names_ptr as *const *const _,
pfn_notify,
user_data,
)
};
if errcode == Status::CL_COMPILE_PROGRAM_FAILURE as i32 {
if let Some(ds) = devices {
program_build_err(program, ds).map_err(|err| err.into())
} else {
let ds = program.devices()?;
program_build_err(program, &ds).map_err(|err| err.into())
}
} else {
eval_errcode(errcode, (), "clCompileProgram", None::<String>)
}
}
#[cfg(feature = "opencl_version_1_2")]
pub fn link_program<D: ClDeviceIdPtr, C: ClContextPtr>(
context: C,
devices: Option<&[D]>,
options: &CString,
input_programs: &[&Program],
pfn_notify: Option<BuildProgramCallbackFn>,
user_data: Option<Box<UserDataPh>>,
device_versions: Option<&[OpenclVersion]>,
) -> OclCoreResult<Program> {
verify_context(context)?;
verify_device_versions(
device_versions,
[1, 2],
&context.as_ptr(),
ApiFunction::LinkProgram,
)?;
assert!(
pfn_notify.is_none() && user_data.is_none(),
"ocl::core::link_program(): Callback functions not yet implemented."
);
let device_ptrs = DevicePtrList::new(devices);
let input_programs_ptrs: Vec<_> = input_programs.iter().map(|cs| cs.as_ptr()).collect();
let user_data = match user_data {
Some(ud) => ud.unwrapped(),
None => ptr::null_mut(),
};
let mut errcode: cl_int = 0;
let program_ptr = unsafe {
ffi::clLinkProgram(
context.as_ptr(),
device_ptrs.num(),
device_ptrs.as_ptr(),
options.as_ptr(),
input_programs_ptrs.len() as cl_uint,
input_programs_ptrs.as_ptr() as *const cl_program,
pfn_notify,
user_data,
&mut errcode,
)
};
eval_errcode(errcode, program_ptr, "clLinkProgram", None::<String>)
.map(|ptr| unsafe { Program::from_raw_create_ptr(ptr) })
}
fn get_program_info_raw(program: &Program, request: ProgramInfo) -> OclCoreResult<Vec<u8>> {
let mut result_size: size_t = 0;
let errcode = unsafe {
ffi::clGetProgramInfo(
program.as_ptr() as cl_program,
request as cl_program_info,
0 as size_t,
ptr::null_mut(),
&mut result_size as *mut size_t,
)
};
eval_errcode(errcode, (), "clGetProgramInfo", None::<String>)?;
if result_size == 0 {
return Ok(vec![]);
}
let mut result: Vec<u8> = iter::repeat(0u8).take(result_size).collect();
let errcode = unsafe {
ffi::clGetProgramInfo(
program.as_ptr() as cl_program,
request as cl_program_info,
result_size,
result.as_mut_ptr() as *mut _ as *mut c_void,
ptr::null_mut(),
)
};
eval_errcode(errcode, result, "clGetProgramInfo", None::<String>)
}
fn get_program_info_binaries(program: &Program) -> OclCoreResult<Vec<Vec<u8>>> {
let binary_sizes_raw = get_program_info_raw(program, ProgramInfo::BinarySizes)?;
let binary_sizes = unsafe { crate::util::bytes_into_vec::<usize>(binary_sizes_raw)? };
let binaries = binary_sizes
.into_iter()
.map(|size| vec![0u8; size])
.collect::<Vec<Vec<u8>>>();
let mut binary_ptrs = binaries.iter().map(|vec| vec.as_ptr()).collect::<Vec<_>>();
let errcode = unsafe {
ffi::clGetProgramInfo(
program.as_ptr() as cl_program,
ProgramInfo::Binaries as cl_program_info,
mem::size_of::<*mut c_void>() * binary_ptrs.len(),
binary_ptrs.as_mut_ptr() as *mut _ as *mut c_void,
ptr::null_mut(),
)
};
eval_errcode(errcode, binaries, "clGetProgramInfo", None::<String>)
}
pub fn get_program_info(
program: &Program,
request: ProgramInfo,
) -> OclCoreResult<ProgramInfoResult> {
match request {
ProgramInfo::Binaries => {
get_program_info_binaries(program).map(ProgramInfoResult::Binaries)
}
_ => {
let result = get_program_info_raw(program, request)?;
ProgramInfoResult::from_bytes(request, result)
}
}
}
pub fn get_program_build_info<D: ClDeviceIdPtr + fmt::Debug>(
obj: &Program,
device_obj: D,
request: ProgramBuildInfo,
) -> OclCoreResult<ProgramBuildInfoResult> {
let mut result_size: size_t = 0;
let errcode = unsafe {
ffi::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,
ptr::null_mut(),
&mut result_size as *mut size_t,
)
};
eval_errcode(errcode, (), "clGetProgramBuildInfo", None::<String>)?;
if result_size == 0 {
return ProgramBuildInfoResult::from_bytes(request, vec![]);
}
let mut result: Vec<u8> = iter::repeat(0u8).take(result_size).collect();
let errcode = unsafe {
ffi::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,
ptr::null_mut(),
)
};
let result = eval_errcode(errcode, result, "clGetProgramBuildInfo", None::<String>)?;
ProgramBuildInfoResult::from_bytes(request, result)
}
pub fn create_kernel<S: AsRef<str>>(program: &Program, name: S) -> OclCoreResult<Kernel> {
let mut err: cl_int = 0;
unsafe {
let kernel_ptr = ffi::clCreateKernel(
program.as_ptr(),
CString::new(name.as_ref().as_bytes())?.as_ptr(),
&mut err,
);
eval_errcode(err, kernel_ptr, "clCreateKernel", Some(name.as_ref()))
.map(|ptr| Kernel::from_raw_create_ptr(ptr))
}
}
pub fn create_kernels_in_program() -> OclCoreResult<()> {
unimplemented!();
}
pub unsafe fn retain_kernel(kernel: &Kernel) -> OclCoreResult<()> {
eval_errcode(
ffi::clRetainKernel(kernel.as_ptr()),
(),
"clRetainKernel",
None::<String>,
)
}
pub unsafe fn release_kernel(kernel: &Kernel) -> OclCoreResult<()> {
eval_errcode(
ffi::clReleaseKernel(kernel.as_ptr()),
(),
"clReleaseKernel",
None::<String>,
)
}
pub fn set_kernel_arg(kernel: &Kernel, index: u32, arg_val: ArgVal) -> OclCoreResult<()> {
let (size, value) = arg_val.as_raw();
let err = unsafe { ffi::clSetKernelArg(kernel.as_ptr(), index, size, value) };
if err != Status::CL_SUCCESS as i32 {
let name = get_kernel_name(kernel)?;
eval_errcode(err, (), "clSetKernelArg", Some(name))
} else {
Ok(())
}
}
pub fn get_kernel_info(obj: &Kernel, request: KernelInfo) -> OclCoreResult<KernelInfoResult> {
let mut result_size: size_t = 0;
let errcode = unsafe {
ffi::clGetKernelInfo(
obj.as_ptr() as cl_kernel,
request as cl_kernel_info,
0 as size_t,
ptr::null_mut(),
&mut result_size as *mut size_t,
)
};
eval_errcode(errcode, (), "clGetKernelInfo", None::<String>)?;
if result_size == 0 {
return KernelInfoResult::from_bytes(request, vec![]);
}
let mut result: Vec<u8> = iter::repeat(0u8).take(result_size).collect();
let errcode = unsafe {
ffi::clGetKernelInfo(
obj.as_ptr() as cl_kernel,
request as cl_kernel_info,
result_size,
result.as_mut_ptr() as *mut _ as *mut c_void,
ptr::null_mut(),
)
};
let result = eval_errcode(errcode, result, "clGetKernelInfo", None::<String>)?;
KernelInfoResult::from_bytes(request, result)
}
pub fn get_kernel_arg_info(
obj: &Kernel,
arg_index: u32,
request: KernelArgInfo,
device_versions: Option<&[OpenclVersion]>,
) -> OclCoreResult<KernelArgInfoResult> {
verify_device_versions(device_versions, [1, 2], obj, ApiFunction::GetKernelArgInfo)?;
let mut result_size: size_t = 0;
let errcode = unsafe {
ffi::clGetKernelArgInfo(
obj.as_ptr() as cl_kernel,
arg_index as cl_uint,
request as cl_kernel_arg_info,
0 as size_t,
ptr::null_mut(),
&mut result_size as *mut size_t,
)
};
eval_errcode(errcode, (), "clGetKernelArgInfo", None::<String>)?;
if result_size == 0 {
return KernelArgInfoResult::from_bytes(request, vec![]);
}
let mut result: Vec<u8> = iter::repeat(0u8).take(result_size).collect();
let errcode = unsafe {
ffi::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,
ptr::null_mut(),
)
};
let result = eval_errcode(errcode, result, "clGetKernelArgInfo", None::<String>)?;
KernelArgInfoResult::from_bytes(request, result)
}
pub fn get_kernel_work_group_info<D: ClDeviceIdPtr>(
obj: &Kernel,
device_obj: D,
request: KernelWorkGroupInfo,
) -> OclCoreResult<KernelWorkGroupInfoResult> {
let mut result_size: size_t = 0;
let errcode = unsafe {
ffi::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,
ptr::null_mut(),
&mut result_size as *mut size_t,
)
};
if let Err(err) = eval_errcode(errcode, (), "clGetKernelWorkGroupInfo", None::<String>) {
if let Some(status) = err.api_status() {
if request == KernelWorkGroupInfo::GlobalWorkSize && status == Status::CL_INVALID_VALUE
{
return Ok(KernelWorkGroupInfoResult::CustomBuiltinOnly);
}
if status == Status::CL_INVALID_DEVICE {
return Ok(KernelWorkGroupInfoResult::Unavailable(status));
}
}
return Err(err);
}
if result_size == 0 {
return KernelWorkGroupInfoResult::from_bytes(request, vec![]);
}
let mut result: Vec<u8> = iter::repeat(0u8).take(result_size).collect();
let errcode = unsafe {
ffi::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,
ptr::null_mut(),
)
};
let result = eval_errcode(errcode, result, "clGetKernelWorkGroupInfo", None::<String>)?;
KernelWorkGroupInfoResult::from_bytes(request, result)
}
pub fn wait_for_events(num_events: u32, event_list: &dyn ClWaitListPtr) -> OclCoreResult<()> {
assert!(event_list.count() >= num_events);
let errcode = unsafe { ffi::clWaitForEvents(num_events, event_list.as_ptr_ptr()) };
eval_errcode(errcode, (), "clWaitForEvents", None::<String>)
}
pub fn get_event_info<'e, E: ClEventPtrRef<'e>>(
event: &'e E,
request: EventInfo,
) -> OclCoreResult<EventInfoResult> {
let mut result_size: size_t = 0;
let errcode = unsafe {
ffi::clGetEventInfo(
*event.as_ptr_ref(),
request as cl_event_info,
0 as size_t,
ptr::null_mut(),
&mut result_size as *mut size_t,
)
};
eval_errcode(errcode, (), "clGetEventInfo", None::<String>)?;
if result_size == 0 {
return EventInfoResult::from_bytes(request, vec![]);
}
let mut result: Vec<u8> = iter::repeat(0u8).take(result_size).collect();
let errcode = unsafe {
ffi::clGetEventInfo(
*event.as_ptr_ref(),
request as cl_event_info,
result_size,
result.as_mut_ptr() as *mut _ as *mut c_void,
ptr::null_mut(),
)
};
let result = eval_errcode(errcode, result, "clGetEventInfo", None::<String>)?;
EventInfoResult::from_bytes(request, result)
}
pub fn create_user_event<C>(context: C) -> OclCoreResult<Event>
where
C: ClContextPtr,
{
let mut errcode = 0;
let event = unsafe {
Event::from_raw_create_ptr(ffi::clCreateUserEvent(context.as_ptr(), &mut errcode))
};
eval_errcode(errcode, event, "clCreateUserEvent", None::<String>)
}
pub unsafe fn retain_event<'e, E: ClEventPtrRef<'e>>(event: &'e E) -> OclCoreResult<()> {
eval_errcode(
ffi::clRetainEvent(*event.as_ptr_ref()),
(),
"clRetainEvent",
None::<String>,
)
}
pub unsafe fn release_event<'e, E: ClEventPtrRef<'e>>(event: &'e E) -> OclCoreResult<()> {
eval_errcode(
ffi::clReleaseEvent(*event.as_ptr_ref()),
(),
"clReleaseEvent",
None::<String>,
)
}
pub fn set_user_event_status<'e, E: ClEventPtrRef<'e>>(
event: &'e E,
execution_status: CommandExecutionStatus,
) -> OclCoreResult<()> {
unsafe {
#[cfg(feature = "event_debug_print")]
println!(
"::set_user_event_status: Setting user event status for event: {:?}",
*event.as_ptr_ref()
);
eval_errcode(
ffi::clSetUserEventStatus(*event.as_ptr_ref(), execution_status as cl_int),
(),
"clSetUserEventStatus",
None::<String>,
)
}
}
pub unsafe fn set_event_callback<'e, E: ClEventPtrRef<'e>>(
event: &'e E,
callback_trigger: CommandExecutionStatus,
callback_receiver: Option<EventCallbackFn>,
user_data: *mut c_void,
) -> OclCoreResult<()> {
eval_errcode(
ffi::clSetEventCallback(
*event.as_ptr_ref(),
callback_trigger as cl_int,
callback_receiver,
user_data,
),
(),
"clSetEventCallback",
None::<String>,
)
}
pub fn get_event_profiling_info<'e, E: ClEventPtrRef<'e>>(
event: &'e E,
request: ProfilingInfo,
) -> OclCoreResult<ProfilingInfoResult> {
let max_result_size_bytes = 8;
let mut result_size: size_t = 0;
let event: cl_event = unsafe { *event.as_ptr_ref() };
let errcode = unsafe {
ffi::clGetEventProfilingInfo(
event,
request as cl_profiling_info,
max_result_size_bytes,
ptr::null_mut(),
&mut result_size as *mut size_t,
)
};
assert!(result_size <= max_result_size_bytes);
if errcode < 0 && Status::from_i32(errcode).unwrap() == Status::CL_INVALID_VALUE {
return Err(OclCoreError::String(
"<unavailable (CL_INVALID_VALUE)>".to_string(),
));
}
eval_errcode(errcode, (), "clGetEventProfilingInfo", None::<String>)?;
if result_size == 0 {
return ProfilingInfoResult::from_bytes(request, vec![]);
}
let mut result: Vec<u8> = iter::repeat(0u8).take(result_size).collect();
let errcode = unsafe {
ffi::clGetEventProfilingInfo(
event,
request as cl_profiling_info,
result_size,
result.as_mut_ptr() as *mut _ as *mut c_void,
ptr::null_mut(),
)
};
let result = eval_errcode(errcode, result, "clGetEventProfilingInfo", None::<String>)?;
ProfilingInfoResult::from_bytes(request, result)
}
pub fn flush(command_queue: &CommandQueue) -> OclCoreResult<()> {
unsafe {
eval_errcode(
ffi::clFlush(command_queue.as_ptr()),
(),
"clFlush",
None::<String>,
)
}
}
pub fn finish(command_queue: &CommandQueue) -> OclCoreResult<()> {
unsafe {
let errcode = ffi::clFinish(command_queue.as_ptr());
eval_errcode(errcode, (), "clFinish", None::<String>)
}
}
pub unsafe fn enqueue_read_buffer<T, M, En, Ewl>(
command_queue: &CommandQueue,
buffer: M,
block: bool,
offset: usize,
data: &mut [T],
wait_list: Option<Ewl>,
new_event: Option<En>,
) -> OclCoreResult<()>
where
T: OclPrm,
En: ClNullEventPtr,
Ewl: ClWaitListPtr,
M: AsMem<T> + MemCmdRw,
{
let (wait_list_len, wait_list_ptr, new_event_ptr) = resolve_event_ptrs(wait_list, new_event);
let offset_bytes = offset * mem::size_of::<T>();
let errcode = ffi::clEnqueueReadBuffer(
command_queue.as_ptr(),
buffer.as_mem().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,
);
eval_errcode(errcode, (), "clEnqueueReadBuffer", None::<String>)
}
pub unsafe fn enqueue_read_buffer_rect<T, M, En, Ewl>(
command_queue: &CommandQueue,
buffer: M,
block: bool,
buffer_origin: [usize; 3],
host_origin: [usize; 3],
region: [usize; 3],
buffer_row_pitch_bytes: usize,
buffer_slc_pitch_bytes: usize,
host_row_pitch_bytes: usize,
host_slc_pitch_bytes: usize,
data: &mut [T],
wait_list: Option<Ewl>,
new_event: Option<En>,
) -> OclCoreResult<()>
where
T: OclPrm,
En: ClNullEventPtr,
Ewl: ClWaitListPtr,
M: AsMem<T> + MemCmdRw,
{
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]];
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) = resolve_event_ptrs(wait_list, new_event);
let errcode = ffi::clEnqueueReadBufferRect(
command_queue.as_ptr(),
buffer.as_mem().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,
);
eval_errcode(errcode, (), "clEnqueueReadBufferRect", None::<String>)
}
pub unsafe fn enqueue_write_buffer<T, M, En, Ewl>(
command_queue: &CommandQueue,
buffer: M,
block: bool,
offset: usize,
data: &[T],
wait_list: Option<Ewl>,
new_event: Option<En>,
) -> OclCoreResult<()>
where
T: OclPrm,
En: ClNullEventPtr,
Ewl: ClWaitListPtr,
M: AsMem<T> + MemCmdRw,
{
let (wait_list_len, wait_list_ptr, new_event_ptr) = resolve_event_ptrs(wait_list, new_event);
let offset_bytes = offset * mem::size_of::<T>();
let errcode = ffi::clEnqueueWriteBuffer(
command_queue.as_ptr(),
buffer.as_mem().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,
);
eval_errcode(errcode, (), "clEnqueueWriteBuffer", None::<String>)
}
pub unsafe fn enqueue_write_buffer_rect<T, M, En, Ewl>(
command_queue: &CommandQueue,
buffer: M,
block: bool,
buffer_origin: [usize; 3],
host_origin: [usize; 3],
region: [usize; 3],
buffer_row_pitch_bytes: usize,
buffer_slc_pitch_bytes: usize,
host_row_pitch_bytes: usize,
host_slc_pitch_bytes: usize,
data: &[T],
wait_list: Option<Ewl>,
new_event: Option<En>,
) -> OclCoreResult<()>
where
T: OclPrm,
En: ClNullEventPtr,
Ewl: ClWaitListPtr,
M: AsMem<T> + MemCmdRw,
{
let (wait_list_len, wait_list_ptr, new_event_ptr) = 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 errcode = ffi::clEnqueueWriteBufferRect(
command_queue.as_ptr(),
buffer.as_mem().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,
);
eval_errcode(errcode, (), "clEnqueueWriteBufferRect", None::<String>)
}
#[cfg(not(feature = "opencl_vendor_mesa"))]
pub fn enqueue_fill_buffer<T, M, En, Ewl>(
command_queue: &CommandQueue,
buffer: M,
pattern: T,
offset: usize,
len: usize,
wait_list: Option<Ewl>,
new_event: Option<En>,
device_version: Option<&OpenclVersion>,
) -> OclCoreResult<()>
where
T: OclPrm,
En: ClNullEventPtr,
Ewl: ClWaitListPtr,
M: AsMem<T> + MemCmdRw,
{
verify_device_version(
device_version,
[1, 2],
command_queue,
ApiFunction::EnqueueFillBuffer,
)?;
let pattern_size = 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) = resolve_event_ptrs(wait_list, new_event);
let errcode = unsafe {
ffi::clEnqueueFillBuffer(
command_queue.as_ptr(),
buffer.as_mem().as_ptr(),
&pattern as *const _ as *const c_void,
pattern_size,
offset_bytes,
size_bytes,
wait_list_len,
wait_list_ptr,
new_event_ptr,
)
};
eval_errcode(errcode, (), "clEnqueueFillBuffer", None::<String>)
}
pub fn enqueue_copy_buffer<T, M, En, Ewl>(
command_queue: &CommandQueue,
src_buffer: M,
dst_buffer: M,
src_offset: usize,
dst_offset: usize,
len: usize,
wait_list: Option<Ewl>,
new_event: Option<En>,
) -> OclCoreResult<()>
where
T: OclPrm,
En: ClNullEventPtr,
Ewl: ClWaitListPtr,
M: AsMem<T> + MemCmdAll,
{
let (wait_list_len, wait_list_ptr, new_event_ptr) = 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 {
ffi::clEnqueueCopyBuffer(
command_queue.as_ptr(),
src_buffer.as_mem().as_ptr(),
dst_buffer.as_mem().as_ptr(),
src_offset_bytes,
dst_offset_bytes,
len_bytes,
wait_list_len,
wait_list_ptr,
new_event_ptr,
)
};
eval_errcode(errcode, (), "clEnqueueCopyBuffer", None::<String>)
}
pub fn enqueue_copy_buffer_rect<T, M, En, Ewl>(
command_queue: &CommandQueue,
src_buffer: M,
dst_buffer: M,
src_origin: [usize; 3],
dst_origin: [usize; 3],
region: [usize; 3],
src_row_pitch_bytes: usize,
src_slc_pitch_bytes: usize,
dst_row_pitch_bytes: usize,
dst_slc_pitch_bytes: usize,
wait_list: Option<Ewl>,
new_event: Option<En>,
) -> OclCoreResult<()>
where
T: OclPrm,
En: ClNullEventPtr,
Ewl: ClWaitListPtr,
M: AsMem<T> + MemCmdAll,
{
let (wait_list_len, wait_list_ptr, new_event_ptr) = 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 errcode = unsafe {
ffi::clEnqueueCopyBufferRect(
command_queue.as_ptr(),
src_buffer.as_mem().as_ptr(),
dst_buffer.as_mem().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,
)
};
eval_errcode(errcode, (), "clEnqueueCopyBufferRect", None::<String>)
}
#[cfg(not(feature = "opencl_vendor_mesa"))]
pub fn enqueue_acquire_gl_objects<En, Ewl>(
command_queue: &CommandQueue,
buffers: &[Mem],
wait_list: Option<Ewl>,
new_event: Option<En>,
) -> OclCoreResult<()>
where
En: ClNullEventPtr,
Ewl: ClWaitListPtr,
{
let (wait_list_len, wait_list_ptr, new_event_ptr) = resolve_event_ptrs(wait_list, new_event);
let errcode = unsafe {
clEnqueueAcquireGLObjects(
command_queue.as_ptr(),
buffers.len() as u32,
buffers.as_ptr() as *const cl_mem,
wait_list_len,
wait_list_ptr,
new_event_ptr,
)
};
eval_errcode(errcode, (), "clEnqueueAcquireGLObjects", None::<String>)
}
#[cfg(not(feature = "opencl_vendor_mesa"))]
pub fn enqueue_release_gl_objects<En, Ewl>(
command_queue: &CommandQueue,
buffers: &[Mem],
wait_list: Option<Ewl>,
new_event: Option<En>,
) -> OclCoreResult<()>
where
En: ClNullEventPtr,
Ewl: ClWaitListPtr,
{
let (wait_list_len, wait_list_ptr, new_event_ptr) = resolve_event_ptrs(wait_list, new_event);
let errcode = unsafe {
clEnqueueReleaseGLObjects(
command_queue.as_ptr(),
buffers.len() as u32,
buffers.as_ptr() as *const cl_mem,
wait_list_len,
wait_list_ptr,
new_event_ptr,
)
};
eval_errcode(errcode, (), "clEnqueueReleaseGLObjects", None::<String>)
}
pub unsafe fn enqueue_read_image<T, M, En, Ewl>(
command_queue: &CommandQueue,
image: M,
block: bool,
origin: [usize; 3],
region: [usize; 3],
row_pitch_bytes: usize,
slc_pitch_bytes: usize,
data: &mut [T],
wait_list: Option<Ewl>,
new_event: Option<En>,
) -> OclCoreResult<()>
where
T: OclPrm,
En: ClNullEventPtr,
Ewl: ClWaitListPtr,
M: AsMem<T> + MemCmdRw,
{
let (wait_list_len, wait_list_ptr, new_event_ptr) = resolve_event_ptrs(wait_list, new_event);
let errcode = ffi::clEnqueueReadImage(
command_queue.as_ptr(),
image.as_mem().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,
);
eval_errcode(errcode, (), "clEnqueueReadImage", None::<String>)
}
pub unsafe fn enqueue_write_image<T, M, En, Ewl>(
command_queue: &CommandQueue,
image: M,
block: bool,
origin: [usize; 3],
region: [usize; 3],
input_row_pitch_bytes: usize,
input_slc_pitch_bytes: usize,
data: &[T],
wait_list: Option<Ewl>,
new_event: Option<En>,
) -> OclCoreResult<()>
where
T: OclPrm,
En: ClNullEventPtr,
Ewl: ClWaitListPtr,
M: AsMem<T> + MemCmdRw,
{
let (wait_list_len, wait_list_ptr, new_event_ptr) = resolve_event_ptrs(wait_list, new_event);
let errcode = ffi::clEnqueueWriteImage(
command_queue.as_ptr(),
image.as_mem().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,
);
eval_errcode(errcode, (), "clEnqueueWriteImage", None::<String>)
}
pub fn enqueue_fill_image<T, M, En, Ewl>(
command_queue: &CommandQueue,
image: M,
color: &[T],
origin: [usize; 3],
region: [usize; 3],
wait_list: Option<Ewl>,
new_event: Option<En>,
device_version: Option<&OpenclVersion>,
) -> OclCoreResult<()>
where
T: OclPrm,
En: ClNullEventPtr,
Ewl: ClWaitListPtr,
M: AsMem<T> + MemCmdAll,
{
verify_device_version(
device_version,
[1, 2],
command_queue,
ApiFunction::EnqueueFillImage,
)?;
let (wait_list_len, wait_list_ptr, new_event_ptr) = resolve_event_ptrs(wait_list, new_event);
let errcode = unsafe {
ffi::clEnqueueFillImage(
command_queue.as_ptr(),
image.as_mem().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,
)
};
eval_errcode(errcode, (), "clEnqueueFillImage", None::<String>)
}
pub fn enqueue_copy_image<En, Ewl>(
command_queue: &CommandQueue,
src_image: &Mem,
dst_image: &Mem,
src_origin: [usize; 3],
dst_origin: [usize; 3],
region: [usize; 3],
wait_list: Option<Ewl>,
new_event: Option<En>,
) -> OclCoreResult<()>
where
En: ClNullEventPtr,
Ewl: ClWaitListPtr,
{
let (wait_list_len, wait_list_ptr, new_event_ptr) = resolve_event_ptrs(wait_list, new_event);
let errcode = unsafe {
ffi::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,
)
};
eval_errcode(errcode, (), "clEnqueueCopyImage", None::<String>)
}
pub fn enqueue_copy_image_to_buffer<T, M, En, Ewl>(
command_queue: &CommandQueue,
src_image: M,
dst_buffer: M,
src_origin: [usize; 3],
region: [usize; 3],
dst_offset: usize,
wait_list: Option<Ewl>,
new_event: Option<En>,
) -> OclCoreResult<()>
where
T: OclPrm,
En: ClNullEventPtr,
Ewl: ClWaitListPtr,
M: AsMem<T> + MemCmdAll,
{
let dst_offset_bytes = dst_offset * mem::size_of::<T>();
let (wait_list_len, wait_list_ptr, new_event_ptr) = resolve_event_ptrs(wait_list, new_event);
let errcode = unsafe {
ffi::clEnqueueCopyImageToBuffer(
command_queue.as_ptr(),
src_image.as_mem().as_ptr(),
dst_buffer.as_mem().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,
)
};
eval_errcode(errcode, (), "clEnqueueCopyImageToBuffer", None::<String>)
}
pub fn enqueue_copy_buffer_to_image<T, M, En, Ewl>(
command_queue: &CommandQueue,
src_buffer: M,
dst_image: M,
src_offset: usize,
dst_origin: [usize; 3],
region: [usize; 3],
wait_list: Option<Ewl>,
new_event: Option<En>,
) -> OclCoreResult<()>
where
T: OclPrm,
En: ClNullEventPtr,
Ewl: ClWaitListPtr,
M: AsMem<T> + MemCmdAll,
{
let src_offset_bytes = src_offset * mem::size_of::<T>();
let (wait_list_len, wait_list_ptr, new_event_ptr) = resolve_event_ptrs(wait_list, new_event);
let errcode = unsafe {
ffi::clEnqueueCopyBufferToImage(
command_queue.as_ptr(),
src_buffer.as_mem().as_ptr(),
dst_image.as_mem().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,
)
};
eval_errcode(errcode, (), "clEnqueueCopyBufferToImage", None::<String>)
}
#[inline]
unsafe fn _enqueue_map_buffer<T, M>(
command_queue: &CommandQueue,
buffer: M,
block: bool,
map_flags: MapFlags,
offset: usize,
len: usize,
wait_list_len: cl_uint,
wait_list_ptr: *const cl_event,
new_event_ptr: *mut cl_event,
) -> OclCoreResult<*mut T>
where
T: OclPrm,
M: AsMem<T> + MemCmdAll,
{
let offset_bytes = offset * mem::size_of::<T>();
let size_bytes = len * mem::size_of::<T>();
let mut errcode = 0i32;
let mapped_ptr = ffi::clEnqueueMapBuffer(
command_queue.as_ptr(),
buffer.as_mem().as_ptr(),
block as cl_uint,
map_flags.bits(),
offset_bytes,
size_bytes,
wait_list_len,
wait_list_ptr,
new_event_ptr,
&mut errcode,
);
eval_errcode(
errcode,
mapped_ptr as *mut T,
"clEnqueueMapBuffer",
None::<String>,
)
}
pub unsafe fn enqueue_map_buffer<T, M, En, Ewl>(
command_queue: &CommandQueue,
buffer: M,
block: bool,
map_flags: MapFlags,
offset: usize,
len: usize,
wait_list: Option<Ewl>,
new_event: Option<En>,
) -> OclCoreResult<MemMap<T>>
where
T: OclPrm,
En: ClNullEventPtr,
Ewl: ClWaitListPtr,
M: AsMem<T> + MemCmdAll,
{
let (wait_list_len, wait_list_ptr, new_event_ptr) = resolve_event_ptrs(wait_list, new_event);
let mapped_ptr_res = _enqueue_map_buffer(
command_queue,
buffer.as_mem(),
block,
map_flags,
offset,
len,
wait_list_len,
wait_list_ptr,
new_event_ptr,
);
mapped_ptr_res.map(|ptr| MemMap::from_raw(ptr))
}
pub unsafe fn enqueue_map_image<T, M, En, Ewl>(
command_queue: &CommandQueue,
image: M,
block: bool,
map_flags: MapFlags,
origin: [usize; 3],
region: [usize; 3],
row_pitch_bytes: &mut usize,
slc_pitch_bytes: &mut usize,
wait_list: Option<Ewl>,
new_event: Option<En>,
) -> OclCoreResult<MemMap<T>>
where
T: OclPrm,
En: ClNullEventPtr,
Ewl: ClWaitListPtr,
M: AsMem<T> + MemCmdAll,
{
let (wait_list_len, wait_list_ptr, new_event_ptr) = resolve_event_ptrs(wait_list, new_event);
let mut errcode = 0i32;
let mapped_ptr = ffi::clEnqueueMapImage(
command_queue.as_ptr(),
image.as_mem().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,
);
eval_errcode(errcode, mapped_ptr, "clEnqueueMapImage", None::<String>)
.map(|ptr| MemMap::from_raw(ptr as *mut _ as *mut T))
}
pub fn enqueue_unmap_mem_object<T, M, En, Ewl>(
command_queue: &CommandQueue,
memobj: M,
mapped_mem: &MemMap<T>,
wait_list: Option<Ewl>,
new_event: Option<En>,
) -> OclCoreResult<()>
where
T: OclPrm,
En: ClNullEventPtr,
Ewl: ClWaitListPtr,
M: AsMem<T> + MemCmdAll,
{
let (wait_list_len, wait_list_ptr, new_event_ptr) = resolve_event_ptrs(wait_list, new_event);
let errcode = unsafe {
ffi::clEnqueueUnmapMemObject(
command_queue.as_ptr(),
memobj.as_mem().as_ptr(),
mapped_mem.as_void_ptr(),
wait_list_len,
wait_list_ptr,
new_event_ptr,
)
};
eval_errcode(errcode, (), "clEnqueueUnmapMemObject", None::<String>)
}
pub fn enqueue_migrate_mem_objects<En: ClNullEventPtr, Ewl: ClWaitListPtr>(
command_queue: &CommandQueue,
mem_objects: &[Mem],
flags: MemMigrationFlags,
wait_list: Option<Ewl>,
new_event: Option<En>,
device_version: Option<&OpenclVersion>,
) -> OclCoreResult<()> {
verify_device_version(
device_version,
[1, 2],
command_queue,
ApiFunction::EnqueueMigrateMemObjects,
)?;
let (wait_list_len, wait_list_ptr, new_event_ptr) = resolve_event_ptrs(wait_list, new_event);
let errcode = unsafe {
ffi::clEnqueueMigrateMemObjects(
command_queue.as_ptr(),
mem_objects.len() as u32,
mem_objects.as_ptr() as *const _ as *const cl_mem,
flags.bits(),
wait_list_len,
wait_list_ptr,
new_event_ptr,
)
};
eval_errcode(errcode, (), "clEnqueueMigrateMemObjects", None::<String>)
}
pub unsafe fn enqueue_kernel<En: ClNullEventPtr, Ewl: ClWaitListPtr>(
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<Ewl>,
new_event: Option<En>,
) -> OclCoreResult<()> {
#[cfg(feature = "kernel_debug_sleep")]
#[allow(unused_imports)]
use std::thread;
#[cfg(feature = "kernel_debug_sleep")]
#[allow(unused_imports)]
use std::time::Duration;
#[cfg(feature = "kernel_debug_print")]
println!(
"Resolving events: wait_list: {:?}, new_event: {:?}",
wait_list, new_event
);
let (wait_list_len, wait_list_ptr, new_event_ptr) = resolve_event_ptrs(wait_list, new_event);
#[cfg(feature = "kernel_debug_print")]
println!("Resolving global work offset: {:?}...", global_work_offset);
let gwo = resolve_work_dims(global_work_offset.as_ref());
#[cfg(feature = "kernel_debug_print")]
println!("Assigning global work size: {:?}...", global_work_dims);
let gws = global_work_dims as *const size_t;
#[cfg(feature = "kernel_debug_print")]
println!("Resolving local work size: {:?}...", local_work_dims);
let lws = resolve_work_dims(local_work_dims.as_ref());
#[cfg(feature = "kernel_debug_print")]
println!("Preparing to print all details...");
#[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 = ffi::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)?;
eval_errcode(errcode, (), "clEnqueueNDRangeKernel", Some(name))
} else {
Ok(())
}
}
pub unsafe fn enqueue_task<En: ClNullEventPtr, Ewl: ClWaitListPtr>(
command_queue: &CommandQueue,
kernel: &Kernel,
wait_list: Option<Ewl>,
new_event: Option<En>,
kernel_name: Option<&str>,
) -> OclCoreResult<()> {
let (wait_list_len, wait_list_ptr, new_event_ptr) = resolve_event_ptrs(wait_list, new_event);
let errcode = ffi::clEnqueueTask(
command_queue.as_ptr(),
kernel.as_ptr() as cl_kernel,
wait_list_len,
wait_list_ptr,
new_event_ptr,
);
eval_errcode(errcode, (), "clEnqueueTask", kernel_name)
}
pub fn enqueue_native_kernel() -> OclCoreResult<()> {
unimplemented!();
}
pub fn enqueue_marker_with_wait_list<En, Ewl>(
command_queue: &CommandQueue,
wait_list: Option<Ewl>,
new_event: Option<En>,
device_version: Option<&OpenclVersion>,
) -> OclCoreResult<()>
where
En: ClNullEventPtr,
Ewl: ClWaitListPtr,
{
verify_device_version(
device_version,
[1, 2],
command_queue,
ApiFunction::EnqueueMarkerWithWaitList,
)?;
let (wait_list_len, wait_list_ptr, new_event_ptr) = resolve_event_ptrs(wait_list, new_event);
let errcode = unsafe {
ffi::clEnqueueMarkerWithWaitList(
command_queue.as_ptr(),
wait_list_len,
wait_list_ptr,
new_event_ptr,
)
};
eval_errcode(errcode, (), "clEnqueueMarkerWithWaitList", None::<String>)
}
pub fn enqueue_barrier_with_wait_list<En, Ewl>(
command_queue: &CommandQueue,
wait_list: Option<Ewl>,
new_event: Option<En>,
device_version: Option<&OpenclVersion>,
) -> OclCoreResult<()>
where
En: ClNullEventPtr,
Ewl: ClWaitListPtr,
{
verify_device_version(
device_version,
[1, 2],
command_queue,
ApiFunction::EnqueueBarrierWithWaitList,
)?;
let (wait_list_len, wait_list_ptr, new_event_ptr) = resolve_event_ptrs(wait_list, new_event);
let errcode = unsafe {
ffi::clEnqueueBarrierWithWaitList(
command_queue.as_ptr(),
wait_list_len,
wait_list_ptr,
new_event_ptr,
)
};
eval_errcode(errcode, (), "clEnqueueBarrierWithWaitList", None::<String>)
}
pub unsafe fn get_extension_function_address_for_platform(
platform: &PlatformId,
func_name: &str,
platform_version: Option<&OpenclVersion>,
) -> OclCoreResult<*mut c_void> {
verify_platform_version(
platform_version,
[1, 2],
platform,
ApiFunction::GetExtensionFunctionAddressForPlatform,
)?;
let func_name_c = CString::new(func_name)?;
let ext_fn =
ffi::clGetExtensionFunctionAddressForPlatform(platform.as_ptr(), func_name_c.as_ptr());
if ext_fn.is_null() {
Err(ApiWrapperError::GetExtensionFunctionAddressForPlatformInvalidFunction.into())
} else {
Ok(ext_fn)
}
}
pub fn device_versions(device_ids: &[DeviceId]) -> OclCoreResult<Vec<OpenclVersion>> {
let mut d_versions = Vec::with_capacity(device_ids.len());
for device_id in device_ids {
d_versions.push(device_id.version()?);
}
Ok(d_versions)
}
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() -> OclCoreResult<PlatformId> {
let platform_list = get_platform_ids()?;
if platform_list.is_empty() {
Err(ApiWrapperError::DefaultPlatformNoPlatforms.into())
} else {
let default_platform_idx = default_platform_idx();
if default_platform_idx > platform_list.len() - 1 {
Err(ApiWrapperError::DefaultPlatformEnvVarBadIdx {
default_platform_idx,
max_idx: platform_list.len() - 1,
}
.into())
} else {
Ok(platform_list[default_platform_idx])
}
}
}
pub fn default_device_type() -> OclCoreResult<DeviceType> {
match env::var("OCL_DEFAULT_DEVICE_TYPE") {
Ok(ref s) => match s.trim() {
"DEFAULT" => Ok(DeviceType::DEFAULT),
"CPU" => Ok(DeviceType::CPU),
"GPU" => Ok(DeviceType::GPU),
"ACCELERATOR" => Ok(DeviceType::ACCELERATOR),
"CUSTOM" => Ok(DeviceType::CUSTOM),
"ALL" => Ok(DeviceType::ALL),
_ => Err(ApiWrapperError::DefaultDeviceTypeInvalidType(s.to_owned()).into()),
},
Err(_) => Ok(DeviceType::ALL),
}
}
pub fn get_kernel_name(kernel: &Kernel) -> OclCoreResult<String> {
let result = get_kernel_info(kernel, KernelInfo::FunctionName)?;
Ok(result.into())
}
pub fn create_build_program<C, D>(
context: C,
src_strings: &[CString],
device_ids: Option<&[D]>,
cmplr_opts: &CString,
) -> OclCoreResult<Program>
where
C: ClContextPtr,
D: ClDeviceIdPtr + fmt::Debug,
{
let program = create_program_with_source(context, src_strings)?;
build_program(&program, device_ids, cmplr_opts, None, None)?;
Ok(program)
}
#[allow(dead_code)]
pub fn wait_for_event<'e, E: ClEventPtrRef<'e>>(event: &'e E) -> OclCoreResult<()> {
let errcode = unsafe { ffi::clWaitForEvents(1, event.as_ptr_ref()) };
eval_errcode(errcode, (), "clWaitForEvents", None::<String>)
}
pub fn event_status<'e, E: ClEventPtrRef<'e>>(
event: &'e E,
) -> OclCoreResult<CommandExecutionStatus> {
let mut status_int: cl_int = 0;
let errcode = unsafe {
ffi::clGetEventInfo(
*event.as_ptr_ref(),
ffi::CL_EVENT_COMMAND_EXECUTION_STATUS,
mem::size_of::<cl_int>(),
&mut status_int as *mut _ as *mut c_void,
ptr::null_mut(),
)
};
eval_errcode(errcode, (), "clGetEventInfo", None::<String>)?;
CommandExecutionStatus::from_i32(status_int).ok_or_else(|| {
OclCoreError::String(
"Error converting \
'clGetEventInfo' status output."
.to_string(),
)
})
}
pub fn event_is_complete<'e, E: ClEventPtrRef<'e>>(event: &'e E) -> OclCoreResult<bool> {
let mut status_int: cl_int = 0;
let errcode = unsafe {
ffi::clGetEventInfo(
*event.as_ptr_ref(),
ffi::CL_EVENT_COMMAND_EXECUTION_STATUS,
mem::size_of::<cl_int>(),
&mut status_int as *mut _ as *mut c_void,
ptr::null_mut(),
)
};
#[cfg(feature = "event_debug_print")]
unsafe {
println!(
"Event Status: {:?} (ptr: {:?})",
CommandExecutionStatus::from_i32(status_int).unwrap(),
*event.as_ptr_ref()
);
}
eval_errcode(
errcode,
status_int == CommandExecutionStatus::Complete as i32,
"clEventGetInfo",
Some("CL_EVENT_COMMAND_EXECUTION_STATUS"),
)
}
#[inline]
pub fn verify_context<C>(context: C) -> OclCoreResult<()>
where
C: ClContextPtr,
{
if cfg!(release) {
Ok(())
} else {
match get_context_info(context, ContextInfo::Devices) {
Err(err) => Err(err),
_ => Ok(()),
}
}
}
fn device_supports_cl_gl_sharing<D: ClDeviceIdPtr>(device: D) -> OclCoreResult<bool> {
match get_device_info(device, DeviceInfo::Extensions) {
Ok(DeviceInfoResult::Extensions(extensions)) => Ok(extensions.contains(CL_GL_SHARING_EXT)),
Err(err) => Err(err),
_ => unreachable!(),
}
}
pub fn get_command_queue_context_ptr(queue: &CommandQueue) -> OclCoreResult<cl_context> {
let mut result = 0 as cl_context;
let result_size = mem::size_of::<cl_context>();
let errcode = unsafe {
ffi::clGetCommandQueueInfo(
queue.as_ptr(),
CommandQueueInfo::Context as cl_command_queue_info,
result_size,
&mut result as *mut _ as *mut c_void,
ptr::null_mut(),
)
};
eval_errcode(
errcode,
result,
"clGetCommandQueueInfo",
Some("functions::get_command_queue_context_ptr"),
)
}