fil_ocl_core/
functions.rs

1//! Thin and safe OpenCL API function wrappers.
2//!
3//!
4//!
5//!
6// ### Error Handling Notes
7//
8// In an ideal world, each function would have its own error enum with a
9// variant for each of the possible errors that API can throw with nice long
10// descriptions (presumably ported from the official docs). For now, all
11// functions use the same error type `ApiError` and error messages include a
12// link to the relevant Khronos API reference web page.
13//
14
15use std::ptr;
16use std::mem;
17use std::ffi::CString;
18use std::iter;
19use std::thread;
20use std::time::Duration;
21use std::env;
22use std::fmt;
23use failure::Fail;
24use crate::ffi::{size_t, c_void};
25use num_traits::FromPrimitive;
26
27#[cfg(not(feature="opencl_vendor_mesa"))]
28use crate::ffi::{cl_GLuint, cl_GLint, cl_GLenum, cl_gl_context_info,};
29#[cfg(not(feature="opencl_vendor_mesa"))]
30use crate::ffi::{clCreateFromGLBuffer, clCreateFromGLRenderbuffer, clCreateFromGLTexture,
31    clCreateFromGLTexture2D, clCreateFromGLTexture3D, clEnqueueAcquireGLObjects,
32    clEnqueueReleaseGLObjects};
33
34use crate::ffi::{self, cl_bool, cl_int, cl_uint, cl_platform_id, cl_device_id, cl_device_type,
35    cl_device_info, cl_platform_info, cl_context, cl_context_info, cl_context_properties,
36    cl_image_format, cl_image_desc, cl_kernel, cl_program_build_info, cl_mem, cl_mem_info,
37    cl_mem_flags, cl_mem_object_type, cl_buffer_create_type, cl_event, cl_program,
38    cl_addressing_mode, cl_filter_mode, cl_command_queue_info, cl_command_queue, cl_image_info,
39    cl_sampler, cl_sampler_info, cl_program_info, cl_kernel_info, cl_kernel_arg_info,
40    cl_kernel_work_group_info, cl_event_info, cl_profiling_info};
41
42use crate::error::{Error as OclCoreError, Result as OclCoreResult};
43
44use crate::{OclPrm, PlatformId, DeviceId, Context, ContextProperties, ContextInfo,
45    ContextInfoResult, MemFlags, CommandQueue, Mem, MemObjectType, Program,
46    Kernel, ClNullEventPtr, Sampler, ArgVal, DeviceType, ImageFormat, ImageDescriptor,
47    CommandExecutionStatus, AddressingMode, FilterMode, PlatformInfo, PlatformInfoResult,
48    DeviceInfo, DeviceInfoResult, CommandQueueInfo, CommandQueueInfoResult, MemInfo, MemInfoResult,
49    ImageInfo, ImageInfoResult, SamplerInfo, SamplerInfoResult, ProgramInfo, ProgramInfoResult,
50    ProgramBuildInfo, ProgramBuildInfoResult, KernelInfo, KernelInfoResult, KernelArgInfo,
51    KernelArgInfoResult, KernelWorkGroupInfo, KernelWorkGroupInfoResult, ClEventPtrRef,
52    ClWaitListPtr, EventInfo, EventInfoResult, ProfilingInfo, ProfilingInfoResult,
53    CreateContextCallbackFn, UserDataPtr, ClPlatformIdPtr, ClDeviceIdPtr, ClContextPtr,
54    EventCallbackFn, BuildProgramCallbackFn, MemMigrationFlags, MapFlags, BufferRegion,
55    BufferCreateType, OpenclVersion, ClVersions, Status, CommandQueueProperties, MemMap, AsMem,
56    MemCmdRw, MemCmdAll, Event, ImageFormatParseResult};
57
58#[cfg(not(feature="opencl_vendor_mesa"))]
59use crate::{GlContextInfo, GlContextInfoResult};
60
61// [TODO]: Do proper auto-detection of available OpenGL context type.
62#[cfg(target_os="macos")]
63const CL_GL_SHARING_EXT: &str = "cl_APPLE_gl_sharing";
64#[cfg(not(target_os="macos"))]
65const CL_GL_SHARING_EXT: &str = "cl_khr_gl_sharing";
66
67const KERNEL_DEBUG_SLEEP_DURATION_MS: u64 = 150;
68const PLATFORM_IDS_ATTEMPT_TIMEOUT_MS: u64 = 2000;
69const PLATFORM_IDS_ATTEMPT_COUNT: u64 = 5;
70
71//============================================================================
72//============================================================================
73//=============================== CALLBACKS ==================================
74//============================================================================
75//============================================================================
76
77
78/// Don't be a dummy. Buckle your `_dummy_callback`.
79pub extern "C" fn _dummy_event_callback(_: ffi::cl_event, _: i32, _: *mut c_void) {}
80
81
82/// If `event_status` is `CommandExecutionStatus::Complete`, the `cl_event`
83/// pointed to by `user_data` will be set to the same.
84///
85/// `user_data` must be a `cl_event` which has not yet had its destructor run
86/// (`::release_event`).
87///
88/// `src_event_ptr` is not used and does not need anything special done with
89/// its destructor (it will already have been managed by the call to `::set_event_callback`.
90///
91pub extern "C" fn _complete_user_event(src_event_ptr: cl_event, event_status: i32,
92        user_data: *mut c_void)
93{
94    #[cfg(not(feature = "event_debug_print"))]
95    let _ = src_event_ptr;
96
97    if event_status == CommandExecutionStatus::Complete as i32 && !user_data.is_null() {
98        let tar_event_ptr = user_data as *mut _ as cl_event;
99
100        unsafe {
101            let user_event = Event::from_raw(tar_event_ptr);
102
103            #[cfg(feature = "event_debug_print")]
104            println!("::_complete_user_event: Setting event complete for: \
105                source: {:?}, target: {:?}...", src_event_ptr, &user_event);
106
107            crate::set_user_event_status(&user_event, CommandExecutionStatus::Complete).unwrap();
108        }
109
110        #[cfg(feature = "event_debug_print")]
111        println!("  - Event status has been set to 'CommandExecutionStatus::Complete' \
112            for event: {:?}", tar_event_ptr);
113    } else {
114        // NOTE: Though these should be unreachable, panic/unwrap will likely
115        // crash the calling module:
116        match CommandExecutionStatus::from_i32(event_status) {
117            Some(status_enum) => panic!("ocl_core::_complete_event: User data is null or event \
118                is not complete. Status: '{:?}'", status_enum),
119            None => eval_errcode(event_status, (), "clSetEventCallback",
120                Some(format!("src_event_ptr: {:?}", src_event_ptr))).unwrap(),
121        }
122    }
123}
124
125//============================================================================
126//============================================================================
127//============================ ERROR HANDLING ================================
128//============================================================================
129//============================================================================
130
131static SDK_DOCS_URL_PRE: &'static str = "https://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/";
132static SDK_DOCS_URL_SUF: &'static str = ".html#errors";
133
134
135/// An OpenCL API error.
136pub struct ApiError {
137    status: Status,
138    fn_name: &'static str,
139    fn_info: Option<String>,
140}
141
142impl ApiError {
143    pub fn new<S: Into<String>>(errcode: i32, fn_name: &'static str, fn_info: Option<S>) -> ApiError {
144        let status = match Status::from_i32(errcode) {
145            Some(s) => s,
146            None => panic!("ocl_core::Error::err_status: Invalid error code: '{}'. \
147                Aborting.", errcode),
148        };
149
150        let fn_info = fn_info.map(|s| s.into());
151
152        ApiError {
153            status,
154            fn_name,
155            fn_info,
156        }
157    }
158
159    pub fn status(&self) -> Status {
160        self.status
161    }
162}
163
164impl Fail for ApiError {}
165
166impl fmt::Display for ApiError {
167    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
168        let fn_info_string = if let Some(ref fn_info) = self.fn_info {
169            format!("(\"{}\")", fn_info)
170        } else {
171            String::with_capacity(0)
172        };
173
174        let status_int = self.status as i32;
175
176        write!(f, "\n\n\
177            ################################ OPENCL ERROR ############################### \
178            \n\nError executing function: {}{}  \
179            \n\nStatus error code: {:?} ({})  \
180            \n\nPlease visit the following url for more information: \n\n{}{}{}  \n\n\
181            ############################################################################# \n",
182            self.fn_name, fn_info_string, self.status, status_int,
183            SDK_DOCS_URL_PRE, self.fn_name, SDK_DOCS_URL_SUF)
184    }
185}
186
187impl fmt::Debug for ApiError {
188    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
189        fmt::Display::fmt(&self, f)
190    }
191}
192
193/// Evaluates `errcode` and returns an `Err` with a failure message if it is
194/// not 0 (Status::CL_SUCCESS).
195///
196#[inline(always)]
197fn eval_errcode<T, S>(errcode: cl_int, result: T, fn_name: &'static str, fn_info: Option<S>)
198        -> OclCoreResult<T>
199        where S: Into<String> {
200    if (Status::CL_SUCCESS as i32) == errcode {
201        Ok(result)
202    } else {
203        Err(ApiError::new(errcode, fn_name, fn_info).into())
204    }
205}
206
207
208/// An OpenCL program build error.
209#[derive(Debug, Fail)]
210pub enum ProgramBuildError {
211    #[fail(display = "Device list is empty. Aborting build.")]
212    DeviceListEmpty,
213    #[fail(display =
214        "\n\n\
215        ###################### OPENCL PROGRAM BUILD DEBUG OUTPUT \
216        ######################\
217        \n\n{}\n\
218        ########################################################\
219        #######################\
220        \n\n",
221        _0
222    )]
223    BuildLog(String),
224    #[fail(display = "{}", _0)]
225    InfoResult(Box<OclCoreError>),
226}
227
228
229/// If the program pointed to by `cl_program` for any of the devices listed in
230/// `device_ids` has a build log of any length, it will be returned as an
231/// errcode result.
232///
233pub fn program_build_err<D: ClDeviceIdPtr>(program: &Program, device_ids: &[D])
234        -> Result<(), ProgramBuildError> {
235    if device_ids.is_empty() {
236        return Err(ProgramBuildError::DeviceListEmpty);
237    }
238
239    for device_id in device_ids.iter().cloned() {
240        match get_program_build_info(program, device_id, ProgramBuildInfo::BuildLog) {
241            Ok(ProgramBuildInfoResult::BuildLog(log)) => {
242                if log.len() > 1 {
243                    return Err(ProgramBuildError::BuildLog(log));
244                }
245            },
246            Err(err) => return Err(ProgramBuildError::InfoResult(Box::new(err))),
247            _ => panic!("Unexpected 'ProgramBuildInfoResult' variant."),
248        }
249    }
250
251    Ok(())
252}
253
254
255/// An API function identifier.
256#[allow(dead_code)]
257#[derive(Debug)]
258pub(crate) enum ApiFunction {
259    None,
260    RetainDevice,
261    ReleaseDevice,
262    CreateProgramWithIl,
263    CreateImage,
264    CreateFromGLTexture,
265    GetKernelArgInfo,
266    EnqueueFillBuffer,
267    EnqueueFillImage,
268    EnqueueMigrateMemObjects,
269    EnqueueMarkerWithWaitList,
270    EnqueueBarrierWithWaitList,
271    GetExtensionFunctionAddressForPlatform,
272    CompileProgram,
273    LinkProgram,
274}
275
276
277/// A version kind identifier.
278#[derive(Debug)]
279pub(crate) enum VersionKind {
280    Device,
281    Platform,
282}
283
284
285/// A version too low error.
286#[derive(Debug, Fail)]
287#[fail(display = "OpenCL ({:?}) version too low to use {:?} (detected: {}, required: {}).",
288    kind, function, detected, required)]
289pub struct VersionLowError {
290    detected: OpenclVersion,
291    required: OpenclVersion,
292    function: ApiFunction,
293    kind: VersionKind,
294}
295
296
297/// An error representing miscellaneous errors from throughout this module.
298#[derive(Debug, Fail)]
299pub enum ApiWrapperError {
300    #[fail(display = "Unable to get platform id list after {} seconds of waiting.", _0)]
301    GetPlatformIdsPlatformListUnavailable(u64),
302    #[fail(display = "`devices_max` can not be zero.")]
303    GetDeviceIdsDevicesMaxZero,
304    #[fail(display = "No devices specified.")]
305    CreateContextNoDevicesSpecified,
306    #[fail(display = "Buffer length and data length and do not match.")]
307    CreateBufferDataLengthMismatch,
308    #[fail(display = "One or more of the devices contained in the list provided to \
309        '::create_context` doesn't support the cl_gl_sharing extension and cannot be \
310        used to create a context associated with OpenGL. [FIXME: determine recommended \
311        resolution - gl_device list fn doesn't work yet].")]
312    CreateContextClGlSharingUnsupported,
313    #[fail(display = "Length of 'devices' must be greater than zero.")]
314    CreateProgramWithBinaryDevicesLenZero,
315    #[fail(display = "Length of 'devices' must equal the length of 'binaries' \
316        (e.g. one binary per device).")]
317    CreateProgramWithBinaryDevicesLenMismatch,
318    #[fail(display = "The specified function does not exist for the implementation or \
319        'platform' is not a valid platform.")]
320    GetExtensionFunctionAddressForPlatformInvalidFunction,
321    #[fail(display = "No OpenCL platforms found. Check your driver.")]
322    DefaultPlatformNoPlatforms,
323    #[fail(display = "The default platform set by the environment variable \
324        'OCL_DEFAULT_PLATFORM_IDX' has an index which is out of range \
325        (index: [{}], max: [{}]).", default_platform_idx, max_idx)]
326    DefaultPlatformEnvVarBadIdx { default_platform_idx: usize, max_idx: usize },
327    #[fail(display = "The default device type set by the environment variable \
328        'OCL_DEFAULT_DEVICE_TYPE': ('{}') is invalid. Valid types are: 'DEFAULT', 'CPU', \
329        'GPU', 'ACCELERATOR', 'CUSTOM', and 'ALL'.", _0)]
330    DefaultDeviceTypeInvalidType(String),
331}
332
333
334//============================================================================
335//============================================================================
336//=========================== SUPPORT FUNCTIONS ==============================
337//============================================================================
338//============================================================================
339
340/// A device pointer list.
341///
342/// Used to create a safe (and platform-homogeneous) list of device pointers
343/// to be passed to a runtime.
344struct DevicePtrList(Vec<cl_device_id>);
345
346impl DevicePtrList {
347    /// Create a new device pointer list.
348    fn new<D: ClDeviceIdPtr>(devices: Option<&[D]>) -> DevicePtrList {
349        let list = match devices {
350            Some(device_ids) => {
351                device_ids.iter().map(|d| d.as_ptr()).collect::<Vec<_>>()
352            },
353            None => Vec::new(),
354        };
355
356        DevicePtrList(list)
357    }
358
359    /// Returns a pointer to the list of device pointers.
360    fn as_ptr(&self) -> *const cl_device_id {
361        match self.0.len() {
362            0 => ptr::null(),
363            _ => self.0.as_ptr(),
364        }
365    }
366
367    /// Returns the number of devices in the pointer list.
368    fn num(&self) -> u32 {
369        self.0.len() as u32
370    }
371}
372
373impl<D> From<Option<&[D]>> for DevicePtrList where D: ClDeviceIdPtr {
374    fn from(devices: Option<&[D]>) -> DevicePtrList {
375        DevicePtrList::new(devices)
376    }
377}
378
379
380/// Maps options of slices to pointers and a length.
381fn resolve_event_ptrs<En: ClNullEventPtr, Ewl: ClWaitListPtr>(wait_list: Option<Ewl>,
382            new_event: Option<En>) -> (cl_uint, *const cl_event, *mut cl_event)
383{
384    // If the wait list is empty or if its containing option is none, map to (0, null),
385    // otherwise map to the length and pointer:
386    let (wait_list_len, wait_list_ptr) = match wait_list {
387        Some(wl) => {
388            if wl.count() > 0 {
389                (wl.count(), unsafe { wl.as_ptr_ptr() } as *const cl_event)
390            } else {
391                (0, ptr::null() as *const cl_event)
392            }
393        },
394        None => (0, ptr::null() as *const cl_event),
395    };
396
397    let new_event_ptr = match new_event {
398        Some(mut ne) => ne.alloc_new(),
399        None => ptr::null_mut() as *mut cl_event,
400    };
401
402    (wait_list_len, wait_list_ptr, new_event_ptr)
403}
404
405/// Converts an array option reference into a pointer to the contained array.
406fn resolve_work_dims(work_dims: Option<&[usize; 3]>) -> *const size_t {
407    match work_dims {
408        Some(w) => w as *const [usize; 3] as *const size_t,
409        None => ptr::null(),
410    }
411}
412
413/// Verifies that OpenCL versions are above a specified threshold.
414pub(crate) fn verify_versions(versions: &[OpenclVersion], required_version: [u16; 2],
415        function: ApiFunction, kind: VersionKind) -> OclCoreResult<()> {
416    let reqd_ver = OpenclVersion::from(required_version);
417
418    for &d_ver in versions {
419        if d_ver < reqd_ver {
420            return Err(VersionLowError {
421                detected: d_ver,
422                required: reqd_ver,
423                function,
424                kind,
425            }.into())
426        }
427    }
428
429    Ok(())
430}
431
432// Verifies that a platform version (`provided_version`) is above a threshold
433// (`required_version`).
434fn verify_platform_version<V: ClVersions>(provided_version: Option<&OpenclVersion>,
435        required_version: [u16; 2], fallback_version_source: &V, function: ApiFunction)
436        -> OclCoreResult<()> {
437    match provided_version {
438        Some(pv) => {
439            let vers = [*pv];
440            verify_versions(&vers, required_version, function, VersionKind::Platform)
441        },
442        None => fallback_version_source.verify_platform_version(required_version),
443    }
444}
445
446// Verifies that a device version (`provided_version`) is above a threshold
447// (`required_version`).
448fn verify_device_version<V: ClVersions>(provided_version: Option<&OpenclVersion>,
449        required_version: [u16; 2], fallback_version_source: &V, function: ApiFunction)
450        -> OclCoreResult<()> {
451    match provided_version {
452        Some(pv) => {
453            let ver = [*pv];
454            verify_versions(&ver, required_version, function, VersionKind::Device)
455        },
456        None => fallback_version_source.verify_device_versions(required_version),
457    }
458}
459
460// Verifies multiple device versions.
461fn verify_device_versions<V: ClVersions>(provided_versions: Option<&[OpenclVersion]>,
462        required_version: [u16; 2], fallback_versions_source: &V, function: ApiFunction)
463        -> OclCoreResult<()> {
464    match provided_versions {
465        Some(pv) => verify_versions(pv, required_version, function, VersionKind::Device),
466        None => fallback_versions_source.verify_device_versions(required_version),
467    }
468}
469
470//============================================================================
471//============================================================================
472//======================= OPENCL FUNCTION WRAPPERS ===========================
473//============================================================================
474//============================================================================
475
476//============================================================================
477//============================= Platform API =================================
478//============================================================================
479
480/// Returns a list of available platforms as 'core' objects.
481pub fn get_platform_ids() -> OclCoreResult<Vec<PlatformId>> {
482    let mut num_platforms = 0 as cl_uint;
483
484    // Get a count of available platforms:
485    let mut errcode: cl_int = unsafe {
486        ffi::clGetPlatformIDs(0, ptr::null_mut(), &mut num_platforms)
487    };
488
489    // Deal with ICD wake up problems when called from multiple threads at the
490    // same time by adding a delay/retry loop:
491    if errcode == Status::CL_PLATFORM_NOT_FOUND_KHR as i32 {
492        // println!("CL_PLATFORM_NOT_FOUND_KHR... looping until platform list is available...");
493        let sleep_ms = PLATFORM_IDS_ATTEMPT_TIMEOUT_MS;
494        let mut iters_rmng = PLATFORM_IDS_ATTEMPT_COUNT;
495
496        while errcode == Status::CL_PLATFORM_NOT_FOUND_KHR as i32 {
497            if iters_rmng == 0 {
498                return Err(ApiWrapperError::GetPlatformIdsPlatformListUnavailable(
499                    (PLATFORM_IDS_ATTEMPT_COUNT * sleep_ms) / 1000).into())
500            }
501
502            // Sleep to allow the ICD to refresh or whatever it does:
503            thread::sleep(Duration::from_millis(sleep_ms));
504
505            // Get a count of available platforms:
506            errcode = unsafe {
507                ffi::clGetPlatformIDs(0, ptr::null_mut(), &mut num_platforms)
508            };
509
510            iters_rmng -= 1;
511        }
512    }
513
514    r#try!(eval_errcode(errcode, (), "clGetPlatformIDs", None::<String>));
515
516    // If no platforms are found, return an empty vec directly:
517    if num_platforms == 0 {
518        return Ok(vec![]);
519    }
520
521    // Create a vec with the appropriate size:
522    let mut null_vec: Vec<usize> = iter::repeat(0).take(num_platforms as usize).collect();
523    let (ptr, len, cap) = (null_vec.as_mut_ptr(), null_vec.len(), null_vec.capacity());
524
525    // Steal the vec's soul:
526    let mut platforms: Vec<PlatformId> = unsafe {
527        mem::forget(null_vec);
528        Vec::from_raw_parts(ptr as *mut PlatformId, len, cap)
529    };
530
531    errcode = unsafe {
532        ffi::clGetPlatformIDs(
533            num_platforms,
534            platforms.as_mut_ptr() as *mut cl_platform_id,
535            ptr::null_mut()
536        )
537    };
538
539    eval_errcode(errcode, platforms, "clGetPlatformIDs", None::<String>)
540}
541
542/// Returns platform information of the requested type.
543pub fn get_platform_info<P: ClPlatformIdPtr>(platform: P, request: PlatformInfo,
544        ) -> OclCoreResult<PlatformInfoResult>
545{
546    let mut result_size = 0 as size_t;
547
548    let errcode = unsafe {
549        ffi::clGetPlatformInfo(
550            platform.as_ptr(),
551            request as cl_platform_info,
552            0 as size_t,
553            ptr::null_mut(),
554            &mut result_size as *mut size_t,
555        )
556    };
557
558    // if let Err(err) = eval_errcode(errcode, (), "clGetPlatformInfo", None::<String>) {
559    //     return PlatformInfoResult::Error(Box::new(err));
560    // }
561    eval_errcode(errcode, (), "clGetPlatformInfo", None::<String>)?;
562
563    // If result size is zero, return an empty info result directly:
564    if result_size == 0 {
565        return PlatformInfoResult::from_bytes(request, vec![]);
566    }
567
568    let mut result: Vec<u8> = iter::repeat(32u8).take(result_size as usize).collect();
569
570    let errcode = unsafe {
571        ffi::clGetPlatformInfo(
572            platform.as_ptr(),
573            request as cl_platform_info,
574            result_size as size_t,
575            result.as_mut_ptr() as *mut c_void,
576            ptr::null_mut() as *mut size_t,
577        )
578    };
579
580    let result = eval_errcode(errcode, result, "clGetPlatformInfo", None::<String>)?;
581    PlatformInfoResult::from_bytes(request, result)
582}
583
584//============================================================================
585//============================= Device APIs  =================================
586//============================================================================
587
588/// Returns a list of available devices for a particular platform.
589pub fn get_device_ids<P: ClPlatformIdPtr>(
590            platform: P,
591            device_types: Option<DeviceType>,
592            devices_max: Option<u32>,
593        ) -> OclCoreResult<Vec<DeviceId>>
594{
595    let device_types = device_types.unwrap_or(r#try!(default_device_type()));
596    let mut devices_available: cl_uint = 0;
597
598    let devices_max = match devices_max {
599        Some(d) => {
600            if d == 0 {
601                return Err(ApiWrapperError::GetDeviceIdsDevicesMaxZero.into());
602            } else {
603                d
604            }
605        },
606        None => crate::DEVICES_MAX,
607    };
608
609    let mut device_ids: Vec<DeviceId> = iter::repeat(unsafe { DeviceId::null() } )
610        .take(devices_max as usize).collect();
611
612    let errcode = unsafe { ffi::clGetDeviceIDs(
613        platform.as_ptr(),
614        device_types.bits() as cl_device_type,
615        devices_max,
616        device_ids.as_mut_ptr() as *mut cl_device_id,
617        &mut devices_available,
618    ) };
619    r#try!(eval_errcode(errcode, (), "clGetDeviceIDs", None::<String>));
620
621    // Trim vec len:
622    unsafe { device_ids.set_len(devices_available as usize); }
623    device_ids.shrink_to_fit();
624
625    Ok(device_ids)
626}
627
628/// Returns raw information about a device, as a vector of bytes.
629pub fn get_device_info_raw<D: ClDeviceIdPtr>(device: D, request: u32) -> OclCoreResult<Vec<u8>> {
630    let mut result_size: size_t = 0;
631
632    let errcode = unsafe { ffi::clGetDeviceInfo(
633        device.as_ptr() as cl_device_id,
634        request as cl_device_info,
635        0 as size_t,
636        ptr::null_mut(),
637        &mut result_size as *mut size_t,
638    ) };
639
640    // Don't generate a full error report for `CL_INVALID_VALUE` or
641    // `CL_INVALID_OPERATION` it's always just an extension unsupported by the
642    // device (i.e. `CL_DEVICE_HALF_FP_CONFIG` on Intel or Apple). Note:
643    // `CL_INVALID_OPERATION` is actually an invalid error value for this
644    // function and is a bug. Don't hold your breath for a fix.
645    if errcode < 0 {
646        if Status::from_i32(errcode).unwrap() == Status::CL_INVALID_VALUE {
647            return Err(OclCoreError::from("<unavailable (CL_INVALID_VALUE)>"));
648        } else if Status::from_i32(errcode).unwrap() == Status::CL_INVALID_OPERATION {
649            return Err(OclCoreError::from("<unavailable (CL_INVALID_OPERATION)>"));
650        }
651    }
652
653    eval_errcode(errcode, (), "clGetDeviceInfo", None::<String>)?;
654
655    // If result size is zero, return an empty vector directly:
656    if result_size == 0 {
657        return Ok(vec![]);
658    }
659
660    let mut result: Vec<u8> = iter::repeat(0u8).take(result_size).collect();
661
662    let errcode = unsafe { ffi::clGetDeviceInfo(
663        device.as_ptr() as cl_device_id,
664        request as cl_device_info,
665        result_size as size_t,
666        result.as_mut_ptr() as *mut _ as *mut c_void,
667        ptr::null_mut(),
668    ) };
669
670    eval_errcode(errcode, result, "clGetDeviceInfo", None::<String>)
671}
672
673/// Returns information about a device.
674pub fn get_device_info<D: ClDeviceIdPtr>(device: D, request: DeviceInfo)
675        -> OclCoreResult<DeviceInfoResult>
676{
677    let result = get_device_info_raw(device, request as cl_device_info)?;
678
679    match request {
680        DeviceInfo::MaxWorkItemSizes => {
681            let max_wi_dims = match get_device_info(device, DeviceInfo::MaxWorkItemDimensions)? {
682                DeviceInfoResult::MaxWorkItemDimensions(d) => d,
683                // Ok(DeviceInfoResult::Error(err)) => return Err(*err),
684                _ => panic!("get_device_info(): Error determining dimensions for \
685                    'DeviceInfo::MaxWorkItemSizes' due to mismatched variants."),
686            };
687            DeviceInfoResult::from_bytes_max_work_item_sizes(request, result, max_wi_dims)
688        },
689        _ => DeviceInfoResult::from_bytes(request, result)
690    }
691}
692
693/// [UNIMPLEMENTED: Please implement me]
694///
695/// [Version Controlled: OpenCL 1.2+] See module docs for more info.
696pub fn create_sub_devices(device_version: Option<&OpenclVersion>) -> OclCoreResult<()> {
697    // clCreateSubDevices(in_device: cl_device_id,
698    //                    properties: *const cl_device_partition_property,
699    //                    num_devices: cl_uint,
700    //                    out_devices: *mut cl_device_id,
701    //                    num_devices_ret: *mut cl_uint) -> cl_int;
702
703    let _ = device_version;
704    unimplemented!();
705}
706
707/// Increments the reference count of a device.
708///
709/// [Version Controlled: OpenCL 1.2+] See module docs for more info.
710pub unsafe fn retain_device(device: &DeviceId, device_version: Option<&OpenclVersion>)
711            -> OclCoreResult<()> {
712    verify_device_version(device_version, [1, 2], device, ApiFunction::RetainDevice)?;
713    eval_errcode(ffi::clRetainDevice(device.as_ptr()), (), "clRetainDevice", None::<String>)
714}
715
716/// Decrements the reference count of a device.
717///
718/// [Version Controlled: OpenCL 1.2+] See module docs for more info.
719pub unsafe fn release_device(device: &DeviceId, device_version: Option<&OpenclVersion>)
720            -> OclCoreResult<()> {
721    verify_device_version(device_version, [1, 2], device, ApiFunction::ReleaseDevice)?;
722    eval_errcode(ffi::clReleaseDevice(device.as_ptr()), (), "clReleaseDevice", None::<String>)
723}
724
725//============================================================================
726//============================= Context APIs  ================================
727//============================================================================
728
729/// Creates a new context pointer valid for all devices in `device_ids`.
730///
731/// Platform is specified in `properties`. If `properties` is `None`, the platform may
732/// default to the first available.
733///
734/// [FIXME]: Incomplete implementation. Callback and userdata untested.
735/// [FIXME]: Verify OpenCL Version on property.
736/// [FIXME]: Most context sources not implemented for `ContextProperties`.
737//
738// [NOTE]: Leave commented "DEBUG" print statements intact until more
739// `ContextProperties` variants are implemented. [PROBABLY DONE]
740pub fn create_context<D: ClDeviceIdPtr>(properties: Option<&ContextProperties>, device_ids: &[D],
741            pfn_notify: Option<CreateContextCallbackFn>, user_data: Option<UserDataPtr>
742        ) -> OclCoreResult<Context>
743{
744    if device_ids.is_empty() {
745        return Err(ApiWrapperError::CreateContextNoDevicesSpecified.into())
746    }
747
748    // // [DEBUG]:
749    // println!("CREATE_CONTEXT: ORIGINAL: properties: {:?}", properties);
750
751    // If properties specify an OpenGL context/sharegroup, ensure all devices
752    // in the provided list support the `cl_gl_sharing` extension:
753    if let Some(properties) = properties {
754        if properties.contains_gl_context_or_sharegroup() {
755            for &device in device_ids {
756                match device_supports_cl_gl_sharing(device) {
757                    Ok(true) => {},
758                    Ok(false) => {
759                        return Err(ApiWrapperError::CreateContextClGlSharingUnsupported.into())
760                    },
761                    Err(err) => return Err(err),
762                }
763            }
764        }
765    }
766
767    let properties_bytes: Vec<isize> = match properties {
768        Some(props) => props.to_raw(),
769        None => Vec::<isize>::with_capacity(0),
770    };
771
772    // // [DEBUG]:
773    // print!("CREATE_CONTEXT: BYTES: ");
774    // util::print_bytes_as_hex(&properties_bytes);
775    // print!("\n");
776
777    // [FIXME]: Disabled:
778    let properties_ptr = if properties_bytes.is_empty() {
779        ptr::null() as *const cl_context_properties
780    } else {
781        properties_bytes.as_ptr()
782    };
783
784    // [FIXME]: Disabled:
785    let user_data_ptr = match user_data {
786        Some(_) => ptr::null_mut(),
787        None => ptr::null_mut(),
788    };
789
790    let device_ids: Vec<_> = device_ids.iter().map(|d| d.as_ptr()).collect();
791
792    let mut errcode: cl_int = 0;
793
794    let context_ptr = unsafe { ffi::clCreateContext(
795        properties_ptr,
796        device_ids.len() as cl_uint,
797        device_ids.as_ptr()  as *const cl_device_id,
798        pfn_notify,
799        user_data_ptr,
800        &mut errcode,
801    ) };
802    // // [DEBUG]:
803    // println!("CREATE_CONTEXT: CONTEXT PTR: {:?}", context);
804    eval_errcode(errcode, context_ptr, "clCreateContext", None::<String>)
805        .map(|ctx_ptr| unsafe { Context::from_raw_create_ptr(ctx_ptr) })
806}
807
808/// Creates a new context pointer for all devices of a specific type.
809///
810/// Platform is specified in `properties`. If `properties` is `None`, the platform may
811/// default to the first available.
812///
813/// [FIXME]: Incomplete implementation. Callback and userdata untested.
814/// [FIXME]: Verify OpenCL Version on property.
815/// [FIXME]: Most context sources not implemented for `ContextProperties`.
816//
817// [NOTE]: Leave commented "DEBUG" print statements intact until more
818// `ContextProperties` variants are implemented.
819pub fn create_context_from_type<D: ClDeviceIdPtr>(properties: Option<&ContextProperties>,
820            device_type: DeviceType, pfn_notify: Option<CreateContextCallbackFn>,
821            user_data: Option<UserDataPtr>) -> OclCoreResult<Context> {
822
823    // [DEBUG]:
824    // println!("CREATE_CONTEXT: ORIGINAL: properties: {:?}", properties);
825
826    let properties_bytes: Vec<isize> = match properties {
827        Some(props) => props.to_raw(),
828        None => Vec::<isize>::with_capacity(0),
829    };
830
831    // [DEBUG]:
832    // print!("CREATE_CONTEXT: BYTES: ");
833    // util::print_bytes_as_hex(&properties_bytes);
834    // print!("\n");
835
836    // [FIXME]: Disabled:
837    let properties_ptr = if properties_bytes.is_empty() {
838        ptr::null() as *const cl_context_properties
839    } else {
840        properties_bytes.as_ptr()
841    };
842
843    // [FIXME]: Disabled:
844    let user_data_ptr = match user_data {
845        Some(_) => ptr::null_mut(),
846        None => ptr::null_mut(),
847    };
848
849    let mut errcode: cl_int = 0;
850
851    let context_ptr = unsafe { ffi::clCreateContextFromType(
852        properties_ptr,
853        device_type.bits(),
854        pfn_notify,
855        user_data_ptr,
856        &mut errcode,
857    ) };
858    eval_errcode(errcode, context_ptr, "clCreateContextFromType", None::<String>)
859        .map(|ctx_ptr| unsafe { Context::from_raw_create_ptr(ctx_ptr) })
860}
861
862/// Increments the reference count of a context.
863pub unsafe fn retain_context<C>(context: C) -> OclCoreResult<()>
864        where C: ClContextPtr
865{
866    eval_errcode(ffi::clRetainContext(context.as_ptr()), (), "clRetainContext", None::<String>)
867}
868
869/// Decrements reference count of a context.
870pub unsafe fn release_context<C>(context: C) -> OclCoreResult<()>
871        where C: ClContextPtr
872{
873    eval_errcode(ffi::clReleaseContext(context.as_ptr()), (), "clReleaseContext", None::<String>)
874}
875
876fn get_context_info_unparsed<C>(context: C, request: ContextInfo)
877        -> OclCoreResult<Vec<u8>>
878        where C: ClContextPtr
879{
880   let mut result_size: size_t = 0;
881
882    let errcode = unsafe { ffi::clGetContextInfo(
883        context.as_ptr() as cl_context,
884        request as cl_context_info,
885        0 as size_t,
886        ptr::null_mut(),
887        &mut result_size as *mut usize,
888    ) };
889
890    eval_errcode(errcode, (), "clGetContextInfo", None::<String>)?;
891
892    // Check for invalid context pointer (a potentially hard to track down bug)
893    // using ridiculous and probably platform-specific logic [if the `Devices`
894    // variant is passed and we're not in the release config]:
895    if !cfg!(release) {
896        let err_if_zero_result_size = request as cl_context_info == ffi::CL_CONTEXT_DEVICES;
897
898        if result_size > 10000 || (result_size == 0 && err_if_zero_result_size) {
899            return Err(OclCoreError::from("\n\nocl::core::context_info(): \
900                Possible invalid context detected. \n\
901                Context info result size is either '> 10k bytes' or '== 0'. Almost certainly an \n\
902                invalid context object. If not, please file an issue at: \n\
903                https://github.com/cogciprocate/ocl/issues.\n\n"));
904        }
905    }
906
907    // If result size is zero, return an empty info result directly:
908    if result_size == 0 {
909        return Ok(vec![]);
910    }
911
912    let mut result: Vec<u8> = iter::repeat(0).take(result_size).collect();
913
914    let errcode = unsafe { ffi::clGetContextInfo(
915        context.as_ptr() as cl_context,
916        request as cl_context_info,
917        result_size as size_t,
918        result.as_mut_ptr() as *mut c_void,
919        ptr::null_mut(),
920    ) };
921
922    eval_errcode(errcode, result, "clGetContextInfo", None::<String>)
923}
924
925/// Returns various kinds of context information.
926///
927/// [SDK Reference](https://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clGetContextInfo.html)
928///
929/// ## Errors
930///
931/// Returns an error result for all the reasons listed in the SDK in addition
932/// to an additional error when called with `CL_CONTEXT_DEVICES` as described
933/// in in the `verify_context()` documentation below.
934pub fn get_context_info<C>(context: C, request: ContextInfo) -> OclCoreResult<ContextInfoResult>
935        where C: ClContextPtr {
936    ContextInfoResult::from_bytes(request, get_context_info_unparsed(context, request)?)
937}
938
939/// Returns the platform for a context.
940///
941/// Errors upon the usual OpenCL errors.
942///
943/// Returns `None` if the context properties do not specify a platform.
944pub fn get_context_platform<C>(context: C) -> OclCoreResult<Option<PlatformId>>
945        where C: ClContextPtr
946{
947    let props_raw_bytes = get_context_info_unparsed(context, ContextInfo::Properties)?;
948
949    let prop = unsafe {
950        let props_raw = crate::util::bytes_into_vec::<isize>(props_raw_bytes)?;
951        ContextProperties::extract_property_from_raw(crate::ContextProperty::Platform, &props_raw)
952    };
953
954    if let Some(crate::ContextPropertyValue::Platform(plat)) = prop {
955        Ok(Some(plat))
956    } else {
957        Ok(None)
958    }
959}
960
961/// [INOPERATIVE: Needs troubleshooting] Returns OpenGL context information.
962///
963/// Used to query current or available devices associated with an existing
964/// OpenGL context/sharegroup.
965///
966/// `properties` must identify a single valid GL context or GL share group
967/// object and a valid platform.
968///
969/// ### Debugging (notes)
970///
971/// For some reason, calling the function pointer returned by the call to
972/// `ffi::clGetExtensionFunctionAddressForPlatform` causes a segfault
973/// (`ffi::clGetExtensionFunctionAddressForPlatform` appears to be working
974/// just fine). The function pointer returned is not null.
975///
976/// Further investigation into the what address the returned function pointer
977/// points to is needed. There may be some Rust-specific quirk having to do
978/// with how libraries are loaded into memory. There may alternatively just be
979/// a simple mistake somewhere.
980///
981#[cfg(not(feature="opencl_vendor_mesa"))]
982pub fn get_gl_context_info_khr(properties: &ContextProperties, request: GlContextInfo)
983        -> OclCoreResult<GlContextInfoResult>
984{
985    let cl_get_gl_context_info_khr_fn = unsafe {
986        let fn_name = match ::std::ffi::CString::new("clGetGLContextInfoKHR") {
987            Ok(s) => s,
988            Err(err) => return Err(err.into()),
989        };
990
991        let plat = match properties.get_platform() {
992            Some(p) => p,
993            None => {
994                return Err("ocl::core::get_gl_context_info_khr: \
995                    Context properties must specify a platform.".into());
996            },
997        };
998
999        let fn_ptr = ffi::clGetExtensionFunctionAddressForPlatform(plat.as_ptr(),
1000            fn_name.as_ptr() as *mut _);
1001
1002        if fn_ptr.is_null() {
1003            return Err("Unable to get extension function \
1004                address for clGetGLContextInfoKHR. The function is not supported by this \
1005                platform.".into());
1006        }
1007
1008        fn_ptr as ffi::clGetGLContextInfoKHR_fn
1009    };
1010
1011    let props_bytes = properties.to_raw();
1012    let mut result_size: size_t = 0;
1013
1014    let errcode = unsafe { (*cl_get_gl_context_info_khr_fn)(
1015        props_bytes.as_ptr(),
1016        request as cl_gl_context_info,
1017        0 as size_t,
1018        ptr::null_mut(),
1019        &mut result_size as *mut usize,
1020    ) };
1021
1022    // if let Err(err) = eval_errcode(errcode, (), "clGetGlContextInfoKhr", None::<String>) {
1023    //     return GlContextInfoResult::Error(Box::new(err));
1024    // }
1025    eval_errcode(errcode, (), "clGetGlContextInfoKhr", None::<String>)?;
1026
1027    if result_size == 0 {
1028        return GlContextInfoResult::from_bytes(request, vec![]);
1029    }
1030
1031    // // DEBUG:
1032    // let result_size = match request {
1033    //     GlContextInfo::CurrentDevice => ::std::mem::size_of::<ffi::cl_device_id>(),
1034    //     GlContextInfo::Devices => ::std::mem::size_of::<*mut ffi::cl_device_id>(),
1035    // };
1036
1037    let mut result: Vec<u8> = iter::repeat(0).take(result_size).collect();
1038
1039    let errcode = unsafe { (*cl_get_gl_context_info_khr_fn)(
1040        props_bytes.as_ptr(),
1041        request as cl_gl_context_info,
1042        result_size as size_t,
1043        result.as_mut_ptr() as *mut c_void,
1044        ptr::null_mut(),
1045    ) };
1046
1047    let result = eval_errcode(errcode, result, "clGetGlContextInfoKhr", None::<String>)?;
1048    GlContextInfoResult::from_bytes(request, result)
1049}
1050
1051
1052//============================================================================
1053//========================== Command Queue APIs ==============================
1054//============================================================================
1055
1056/// Returns a new command queue pointer.
1057pub fn create_command_queue<C, D>(
1058            context: C,
1059            device: D,
1060            properties: Option<CommandQueueProperties>,
1061        ) -> OclCoreResult<CommandQueue>
1062        where C: ClContextPtr, D: ClDeviceIdPtr
1063{
1064    // Verify that the context is valid:
1065    r#try!(verify_context(context));
1066
1067    let cmd_queue_props = match properties {
1068        Some(p) => p.bits,
1069        None => 0,
1070    };
1071
1072    let mut errcode: cl_int = 0;
1073
1074    let cq_ptr = unsafe { ffi::clCreateCommandQueue(
1075        context.as_ptr(),
1076        device.as_ptr(),
1077        cmd_queue_props,
1078        &mut errcode
1079    ) };
1080    eval_errcode(errcode, cq_ptr, "clCreateCommandQueue", None::<String>)
1081        .map(|cq_ptr| unsafe { CommandQueue::from_raw_create_ptr(cq_ptr) })
1082
1083}
1084
1085/// Increments the reference count of a command queue.
1086pub unsafe fn retain_command_queue(queue: &CommandQueue) -> OclCoreResult<()> {
1087    eval_errcode(ffi::clRetainCommandQueue(queue.as_ptr()), (), "clRetainCommandQueue", None::<String>)
1088}
1089
1090/// Decrements the reference count of a command queue.
1091///
1092/// [FIXME]: Return result
1093pub unsafe fn release_command_queue(queue: &CommandQueue) -> OclCoreResult<()> {
1094    eval_errcode(ffi::clReleaseCommandQueue(queue.as_ptr()), (), "clReleaseCommandQueue", None::<String>)
1095}
1096
1097/// Returns information about a command queue
1098pub fn get_command_queue_info(queue: &CommandQueue, request: CommandQueueInfo,
1099        ) -> OclCoreResult<CommandQueueInfoResult>
1100{
1101    let mut result_size: size_t = 0;
1102
1103    let errcode = unsafe { ffi::clGetCommandQueueInfo(
1104        queue.as_ptr() as cl_command_queue,
1105        request as cl_command_queue_info,
1106        0 as size_t,
1107        ptr::null_mut(),
1108        &mut result_size as *mut size_t,
1109    ) };
1110
1111    eval_errcode(errcode, (), "clGetCommandQueueInfo", None::<String>)?;
1112
1113    // If result size is zero, return an empty info result directly:
1114    if result_size == 0 {
1115        return CommandQueueInfoResult::from_bytes(request, vec![]);
1116    }
1117
1118    let mut result: Vec<u8> = iter::repeat(0u8).take(result_size).collect();
1119
1120    let errcode = unsafe { ffi::clGetCommandQueueInfo(
1121        queue.as_ptr() as cl_command_queue,
1122        request as cl_command_queue_info,
1123        result_size,
1124        result.as_mut_ptr() as *mut _ as *mut c_void,
1125        ptr::null_mut(),
1126    ) };
1127
1128    let result = eval_errcode(errcode, result, "clGetCommandQueueInfo", None::<String>)?;
1129    CommandQueueInfoResult::from_bytes(request, result)
1130}
1131
1132//============================================================================
1133//========================== Memory Object APIs ==============================
1134//============================================================================
1135
1136/// Returns a new buffer pointer with size (bytes): `len` * sizeof(T).
1137///
1138/// ## Safety
1139///
1140/// The caller must ensure that correct and appropriate `flags` are being
1141/// used.
1142///
1143pub unsafe fn create_buffer<C, T>(
1144            context: C,
1145            flags: MemFlags,
1146            len: usize,
1147            data: Option<&[T]>,
1148        ) -> OclCoreResult<Mem>
1149        where C: ClContextPtr, T: OclPrm
1150{
1151    // Verify that the context is valid:
1152    r#try!(verify_context(context));
1153
1154    let mut errcode: cl_int = 0;
1155
1156    let host_ptr = match data {
1157        Some(d) => {
1158            if d.len() != len {
1159                return Err(ApiWrapperError::CreateBufferDataLengthMismatch.into())
1160            }
1161            d.as_ptr() as cl_mem
1162        },
1163        None => ptr::null_mut(),
1164    };
1165
1166    let buf_ptr = ffi::clCreateBuffer(
1167        context.as_ptr(),
1168        flags.bits() as cl_mem_flags,
1169        len * mem::size_of::<T>(),
1170        host_ptr,
1171        &mut errcode,
1172    );
1173
1174    // [TODO]: Convert back the return style to this:
1175    eval_errcode(errcode, buf_ptr, "clCreateBuffer", None::<String>)
1176        .map(|ptr| Mem::from_raw_create_ptr(ptr))
1177}
1178
1179/// Return a buffer pointer from a `OpenGL` buffer object.
1180///
1181/// ## Safety
1182///
1183/// The caller must ensure that correct and appropriate `flags` are being
1184/// used.
1185///
1186// [UNTESTED]
1187//
1188#[cfg(not(feature="opencl_vendor_mesa"))]
1189pub unsafe fn create_from_gl_buffer<C>(
1190            context: C,
1191            gl_object: cl_GLuint,
1192            flags: MemFlags
1193        ) -> OclCoreResult<Mem>
1194        where C: ClContextPtr
1195{
1196    // Verify that the context is valid
1197    r#try!(verify_context(context));
1198
1199    let mut errcode: cl_int = 0;
1200
1201    let buf_ptr = clCreateFromGLBuffer(
1202            context.as_ptr(),
1203            flags.bits() as cl_mem_flags,
1204            gl_object,
1205            &mut errcode);
1206
1207    eval_errcode(errcode, buf_ptr, "clCreateFromGLBuffer", None::<String>)
1208        .map(|ptr| Mem::from_raw_create_ptr(ptr))
1209}
1210
1211/// Return a renderbuffer pointer from a `OpenGL` renderbuffer object.
1212///
1213/// ## Safety
1214///
1215/// The caller must ensure that correct and appropriate `flags` are being
1216/// used.
1217///
1218// [UNTESTED]
1219//
1220#[cfg(not(feature="opencl_vendor_mesa"))]
1221pub unsafe fn create_from_gl_renderbuffer<C>(
1222            context: C,
1223            renderbuffer: cl_GLuint,
1224            flags: MemFlags
1225        ) -> OclCoreResult<Mem>
1226        where C: ClContextPtr
1227{
1228    // Verify that the context is valid
1229    r#try!(verify_context(context));
1230
1231    let mut errcode: cl_int = 0;
1232
1233    let buf_ptr = clCreateFromGLRenderbuffer(
1234            context.as_ptr(),
1235            flags.bits() as cl_mem_flags,
1236            renderbuffer,
1237            &mut errcode);
1238
1239    eval_errcode(errcode, buf_ptr, "clCreateFromGLRenderbuffer", None::<String>)
1240        .map(|ptr| Mem::from_raw_create_ptr(ptr))
1241}
1242
1243/// Return a texture2D pointer from a `OpenGL` texture2D object.
1244///
1245/// [Version Controlled: OpenCL 1.2+] See module docs for more info.
1246///
1247/// ## Safety
1248///
1249/// The caller must ensure that correct and appropriate `flags` are being
1250/// used.
1251///
1252// [UNTESTED]
1253//
1254// [TODO]: If version is < 1.2, automatically use older versions.
1255//
1256#[cfg(not(feature="opencl_vendor_mesa"))]
1257pub unsafe fn create_from_gl_texture<C>(
1258            context: C,
1259            texture_target: cl_GLenum,
1260            miplevel: cl_GLint,
1261            texture: cl_GLuint,
1262            flags: MemFlags,
1263            device_versions: Option<&[OpenclVersion]>,
1264        ) -> OclCoreResult<Mem>
1265        where C: ClContextPtr
1266{
1267    // Verify that the context is valid
1268    r#try!(verify_context(context));
1269
1270    // Verify device versions:
1271    verify_device_versions(device_versions, [1, 2], &context.as_ptr(),
1272        ApiFunction::CreateFromGLTexture)?;
1273
1274    // [TODO]: Forward old OpenCL versions to these instead:
1275    // let obj_core = match image_desc.image_depth {
1276    //     2 => unsafe { try!(core::create_from_gl_texture_2d(
1277    //                         queue.context_core(),
1278    //                         texture_target,
1279    //                         miplevel,
1280    //                         texture,
1281    //                         flags)) },
1282    //     3 => unsafe { try!(core::create_from_gl_texture_3d(
1283    //                         queue.context_core(),
1284    //                         texture_target,
1285    //                         miplevel,
1286    //                         texture,
1287    //                         flags)) },
1288    //     _ => unimplemented!() // FIXME: return an error ? or panic! ?
1289    // };
1290
1291    let mut errcode: cl_int = 0;
1292
1293    let buf_ptr = clCreateFromGLTexture(
1294            context.as_ptr(),
1295            flags.bits() as cl_mem_flags,
1296            texture_target,
1297            miplevel,
1298            texture,
1299            &mut errcode);
1300
1301    eval_errcode(errcode, buf_ptr, "clCreateFromGLTexture", None::<String>)
1302        .map(|ptr| Mem::from_raw_create_ptr(ptr))
1303}
1304
1305/// Return a texture2D pointer from a `OpenGL` texture2D object.
1306///
1307// [UNTESTED] [DEPRICATED]
1308#[cfg(not(feature="opencl_vendor_mesa"))]
1309pub unsafe fn create_from_gl_texture_2d<C>(
1310            context: C,
1311            texture_target: cl_GLenum,
1312            miplevel: cl_GLint,
1313            texture: cl_GLuint,
1314            flags: MemFlags
1315        ) -> OclCoreResult<Mem>
1316        where C: ClContextPtr
1317{
1318    // Verify that the context is valid
1319    r#try!(verify_context(context));
1320
1321    let mut errcode: cl_int = 0;
1322
1323    let buf_ptr = clCreateFromGLTexture2D(
1324            context.as_ptr(),
1325            flags.bits() as cl_mem_flags,
1326            texture_target,
1327            miplevel,
1328            texture,
1329            &mut errcode);
1330
1331    eval_errcode(errcode, buf_ptr, "clCreateFromGLTexture2D", None::<String>)
1332        .map(|ptr| Mem::from_raw_create_ptr(ptr))
1333}
1334
1335/// Return a texture3D pointer from a `OpenGL` texture3D object.
1336///
1337// [UNTESTED] [DEPRICATED]
1338#[cfg(not(feature="opencl_vendor_mesa"))]
1339pub unsafe fn create_from_gl_texture_3d<C>(
1340            context: C,
1341            texture_target: cl_GLenum,
1342            miplevel: cl_GLint,
1343            texture: cl_GLuint,
1344            flags: MemFlags
1345        ) -> OclCoreResult<Mem>
1346        where C: ClContextPtr
1347{
1348    // Verify that the context is valid
1349    r#try!(verify_context(context));
1350
1351    let mut errcode: cl_int = 0;
1352
1353    let buf_ptr = clCreateFromGLTexture3D(
1354            context.as_ptr(),
1355            flags.bits() as cl_mem_flags,
1356            texture_target,
1357            miplevel,
1358            texture,
1359            &mut errcode);
1360
1361    eval_errcode(errcode, buf_ptr, "clCreateFromGLTexture3D", None::<String>)
1362        .map(|ptr| Mem::from_raw_create_ptr(ptr))
1363}
1364
1365/// Creates a new buffer object (referred to as a sub-buffer object) from an
1366/// existing buffer object.
1367///
1368/// The returned sub-buffer has a number of caveats which can cause undefined
1369/// behavior.
1370///
1371/// [SDK Docs](https://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clCreateSubBuffer.html)
1372///
1373pub fn create_sub_buffer<T: OclPrm>(
1374            buffer: &Mem,
1375            flags: MemFlags,
1376            buffer_create_info: &BufferRegion<T>,
1377        ) -> OclCoreResult<Mem>
1378{
1379    let buffer_create_type = BufferCreateType::Region;
1380    let buffer_create_info_bytes = buffer_create_info.to_bytes();
1381    let mut errcode = 0i32;
1382
1383    let sub_buf_ptr = unsafe { ffi::clCreateSubBuffer(
1384        buffer.as_ptr(),
1385        flags.bits(),
1386        buffer_create_type as cl_buffer_create_type,
1387        &buffer_create_info_bytes as *const _ as *const c_void,
1388        &mut errcode,
1389    ) };
1390
1391    eval_errcode(errcode, sub_buf_ptr, "clCreateSubBuffer", None::<String>)
1392        .map(|ptr| unsafe { Mem::from_raw_create_ptr(ptr) })
1393}
1394
1395/// Returns a new image (mem) pointer.
1396///
1397/// [TODO]: If version is < 1.2, automatically use older versions.
1398///
1399///
1400/// ## Safety
1401///
1402///
1403///
1404/// [Version Controlled: OpenCL 1.2+] See module docs for more info.
1405pub unsafe fn create_image<C, T>(
1406            context: C,
1407            flags: MemFlags,
1408            format: &ImageFormat,
1409            desc: &ImageDescriptor,
1410            data: Option<&[T]>,
1411            device_versions: Option<&[OpenclVersion]>,
1412        ) -> OclCoreResult<Mem>
1413        where C: ClContextPtr, T: OclPrm
1414{
1415    // Verify that the context is valid:
1416    r#try!(verify_context(context));
1417
1418    // Verify device versions:
1419    verify_device_versions(device_versions, [1, 2], &context.as_ptr(), ApiFunction::CreateImage)?;
1420
1421    let mut errcode: cl_int = 0;
1422
1423    let host_ptr = match data {
1424        Some(d) => {
1425            // [FIXME]: CALCULATE CORRECT IMAGE SIZE AND COMPARE WITH FORMAT/DESC
1426            // assert!(d.len() == len, "ocl::create_image(): Data length mismatch.");
1427            d.as_ptr() as cl_mem
1428        },
1429        None => ptr::null_mut(),
1430    };
1431
1432    let image_ptr = ffi::clCreateImage(
1433        context.as_ptr(),
1434        flags.bits() as cl_mem_flags,
1435        &format.to_raw() as *const cl_image_format,
1436        &desc.to_raw() as *const cl_image_desc,
1437        host_ptr,
1438        &mut errcode as *mut cl_int,
1439    );
1440
1441    eval_errcode(errcode, image_ptr, "clCreateImage", None::<String>)
1442        .map(|ptr| Mem::from_raw_create_ptr(ptr))
1443}
1444
1445/// Increments the reference counter of a mem object.
1446pub unsafe fn retain_mem_object(mem: &Mem) -> OclCoreResult<()> {
1447    eval_errcode(ffi::clRetainMemObject(mem.as_ptr()), (), "clRetainMemObject", None::<String>)
1448}
1449
1450/// Decrements the reference counter of a mem object.
1451pub unsafe fn release_mem_object(mem: &Mem) -> OclCoreResult<()> {
1452    eval_errcode(ffi::clReleaseMemObject(mem.as_ptr()), (), "clReleaseMemObject", None::<String>)
1453}
1454
1455/// Returns a list of supported image formats.
1456///
1457/// ## Example
1458///
1459/// ```rust,ignore
1460/// let context = Context::builder().build().unwrap();
1461///
1462/// let img_fmts = core::get_supported_image_formats(context,
1463///    core::MEM_READ_WRITE, core::MemObjectType::Image2d)
1464/// ```
1465pub fn get_supported_image_formats<C>(
1466            context: C,
1467            flags: MemFlags,
1468            image_type: MemObjectType,
1469        ) -> OclCoreResult<Vec<ImageFormatParseResult>>
1470        where C: ClContextPtr
1471{
1472    let mut num_image_formats = 0 as cl_uint;
1473
1474    let errcode = unsafe { ffi::clGetSupportedImageFormats(
1475        context.as_ptr(),
1476        flags.bits() as cl_mem_flags,
1477        image_type as cl_mem_object_type,
1478        0 as cl_uint,
1479        ptr::null_mut() as *mut cl_image_format,
1480        &mut num_image_formats as *mut cl_uint,
1481    ) };
1482    r#try!(eval_errcode(errcode, (), "clGetSupportedImageFormats", None::<String>));
1483
1484    // If no formats found, return an empty list directly:
1485    if num_image_formats == 0 {
1486        return Ok(vec![]);
1487    }
1488
1489    let mut image_formats: Vec<cl_image_format> = (0..(num_image_formats as usize)).map(|_| {
1490           ImageFormat::new_raw()
1491        } ).collect();
1492
1493    debug_assert!(image_formats.len() == num_image_formats as usize && !image_formats.is_empty());
1494
1495    let errcode = unsafe { ffi::clGetSupportedImageFormats(
1496        context.as_ptr(),
1497        flags.bits() as cl_mem_flags,
1498        image_type as cl_mem_object_type,
1499        num_image_formats,
1500        image_formats.as_mut_ptr() as *mut _ as *mut cl_image_format,
1501        ptr::null_mut(),
1502    ) };
1503
1504    r#try!(eval_errcode(errcode, (), "clGetSupportedImageFormats", None::<String>));
1505    Ok(ImageFormat::list_from_raw(image_formats))
1506}
1507
1508
1509/// Get mem object info.
1510pub fn get_mem_object_info(obj: &Mem, request: MemInfo) -> OclCoreResult<MemInfoResult> {
1511    let mut result_size: size_t = 0;
1512
1513    let errcode = unsafe { ffi::clGetMemObjectInfo(
1514        obj.as_ptr() as cl_mem,
1515        request as cl_mem_info,
1516        0 as size_t,
1517        ptr::null_mut(),
1518        &mut result_size as *mut size_t,
1519    ) };
1520
1521    eval_errcode(errcode, (), "clGetMemObjectInfo", None::<String>)?;
1522
1523    // If result size is zero, return an empty info result directly:
1524    if result_size == 0 {
1525        return MemInfoResult::from_bytes(request, vec![]);
1526    }
1527
1528    let mut result: Vec<u8> = iter::repeat(0u8).take(result_size).collect();
1529
1530    let errcode = unsafe { ffi::clGetMemObjectInfo(
1531        obj.as_ptr() as cl_mem,
1532        request as cl_mem_info,
1533        result_size,
1534        result.as_mut_ptr() as *mut _ as *mut c_void,
1535        ptr::null_mut(),
1536    ) };
1537    let result = eval_errcode(errcode, result, "clGetMemObjectInfo", None::<String>)?;
1538    MemInfoResult::from_bytes(request, result)
1539}
1540
1541
1542/// Get image info.
1543pub fn get_image_info(obj: &Mem, request: ImageInfo) -> OclCoreResult<ImageInfoResult> {
1544    let mut result_size: size_t = 0;
1545
1546    let errcode = unsafe { ffi::clGetImageInfo(
1547        obj.as_ptr() as cl_mem,
1548        request as cl_image_info,
1549        0 as size_t,
1550        ptr::null_mut(),
1551        &mut result_size as *mut size_t,
1552    ) };
1553
1554    eval_errcode(errcode, (), "clGetImageInfo", None::<String>)?;
1555
1556    // If result size is zero, return an empty info result directly:
1557    if result_size == 0 {
1558        return ImageInfoResult::from_bytes(request, vec![]);
1559    }
1560
1561    let mut result: Vec<u8> = iter::repeat(0u8).take(result_size).collect();
1562
1563    let errcode = unsafe { ffi::clGetImageInfo(
1564        obj.as_ptr() as cl_mem,
1565        request as cl_image_info,
1566        result_size,
1567        result.as_mut_ptr() as *mut _ as *mut c_void,
1568        ptr::null_mut(),
1569    ) };
1570
1571    let result = eval_errcode(errcode, result, "clGetImageInfo", None::<String>)?;
1572    ImageInfoResult::from_bytes(request, result)
1573}
1574
1575/// [UNIMPLEMENTED: Please implement me]
1576pub fn set_mem_object_destructor_callback() -> OclCoreResult<()> {
1577    // ffi::clSetMemObjectDestructorCallback(memobj: cl_mem,
1578    //                                     pfn_notify: extern fn (cl_mem, *mut c_void),
1579    //                                     user_data: *mut c_void) -> cl_int;
1580    unimplemented!();
1581}
1582
1583//============================================================================
1584//============================= Sampler APIs =================================
1585//============================================================================
1586
1587/// Creates and returns a new sampler object.
1588///
1589/// [SDK Docs](https://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clCreateSampler.html)
1590pub fn create_sampler<C>(context: C, normalize_coords: bool, addressing_mode: AddressingMode,
1591            filter_mode: FilterMode) -> OclCoreResult<Sampler>
1592        where C: ClContextPtr
1593{
1594    let mut errcode = 0;
1595
1596    let sampler = unsafe { Sampler::from_raw_create_ptr(ffi::clCreateSampler(
1597        context.as_ptr(),
1598        normalize_coords as cl_bool,
1599        addressing_mode as cl_addressing_mode,
1600        filter_mode as cl_filter_mode,
1601        &mut errcode,
1602    )) };
1603
1604    eval_errcode(errcode, sampler, "clCreateSampler", None::<String>)
1605}
1606
1607/// Increments a sampler reference counter.
1608pub unsafe fn retain_sampler(sampler: &Sampler) -> OclCoreResult<()> {
1609    eval_errcode(ffi::clRetainSampler(sampler.as_ptr()), (), "clRetainSampler", None::<String>)
1610}
1611
1612/// Decrements a sampler reference counter.
1613pub unsafe fn release_sampler(sampler: &Sampler) -> OclCoreResult<()> {
1614    eval_errcode(ffi::clReleaseSampler(sampler.as_ptr()), (), "clReleaseSampler", None::<String>)
1615}
1616
1617/// Returns information about the sampler object.
1618///
1619/// [SDK Docs](https://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clGetSamplerInfo.html)
1620pub fn get_sampler_info(obj: &Sampler, request: SamplerInfo,
1621    ) -> OclCoreResult<SamplerInfoResult>
1622{
1623    let mut result_size: size_t = 0;
1624
1625    let errcode = unsafe { ffi::clGetSamplerInfo(
1626        obj.as_ptr() as cl_sampler,
1627        request as cl_sampler_info,
1628        0 as size_t,
1629        ptr::null_mut(),
1630        &mut result_size as *mut size_t,
1631    ) };
1632
1633    // try!(eval_errcode(errcode, result, "clGetSamplerInfo", None::<String>));
1634    // if let Err(err) = eval_errcode(errcode, (), "clGetSamplerInfo", None::<String>) {
1635    //     return SamplerInfoResult::Error(Box::new(err));
1636    // }
1637    eval_errcode(errcode, (), "clGetSamplerInfo", None::<String>)?;
1638
1639    // If result size is zero, return an empty info result directly:
1640    if result_size == 0 {
1641        return SamplerInfoResult::from_bytes(request, vec![]);
1642    }
1643
1644    let mut result: Vec<u8> = iter::repeat(0u8).take(result_size).collect();
1645
1646    let errcode = unsafe { ffi::clGetSamplerInfo(
1647        obj.as_ptr() as cl_sampler,
1648        request as cl_sampler_info,
1649        result_size,
1650        result.as_mut_ptr() as *mut _ as *mut c_void,
1651        ptr::null_mut(),
1652    ) };
1653
1654    let result = eval_errcode(errcode, result, "clGetSamplerInfo", None::<String>)?;
1655    SamplerInfoResult::from_bytes(request, result)
1656}
1657
1658//============================================================================
1659//========================== Program Object APIs =============================
1660//============================================================================
1661
1662/// Creates a new program.
1663pub fn create_program_with_source<C>(
1664            context: C,
1665            src_strings: &[CString],
1666        ) -> OclCoreResult<Program>
1667        where C: ClContextPtr
1668{
1669    // Verify that the context is valid:
1670    r#try!(verify_context(context));
1671
1672    // Lengths (not including \0 terminator) of each string:
1673    let ks_lens: Vec<usize> = src_strings.iter().map(|cs| cs.as_bytes().len()).collect();
1674
1675    // Pointers to each string:
1676    let kern_string_ptrs: Vec<*const _> = src_strings.iter().map(|cs| cs.as_ptr()).collect();
1677
1678    let mut errcode: cl_int = 0;
1679
1680    let program_ptr = unsafe { ffi::clCreateProgramWithSource(
1681        context.as_ptr(),
1682        kern_string_ptrs.len() as cl_uint,
1683        kern_string_ptrs.as_ptr() as *const *const _,
1684        ks_lens.as_ptr() as *const usize,
1685        &mut errcode,
1686    ) };
1687
1688    eval_errcode(errcode, program_ptr, "clCreateProgramWithSource", None::<String>)
1689        .map(|ptr| unsafe { Program::from_raw_create_ptr(ptr) })
1690}
1691
1692
1693/// Creates a program object for a context, and loads the binary bits
1694/// specified by binary into the program object.
1695///
1696/// [SDK Docs]: https://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clCreateProgramWithBinary.html
1697///
1698// [UNTESTED]
1699///
1700pub fn create_program_with_binary<C, D>(
1701            context: C,
1702            devices: &[D],
1703            binaries: &[&[u8]],
1704        ) -> OclCoreResult<Program>
1705        where C: ClContextPtr, D: ClDeviceIdPtr
1706{
1707    if devices.is_empty() {
1708        return Err(ApiWrapperError::CreateProgramWithBinaryDevicesLenZero.into())
1709    }
1710
1711    if devices.len() != binaries.len() {
1712        return Err(ApiWrapperError::CreateProgramWithBinaryDevicesLenMismatch.into())
1713    }
1714
1715    let lengths: Vec<usize> = binaries.iter().map(|bin| bin.len()).collect();
1716    let mut binary_status: Vec<i32> = iter::repeat(0).take(devices.len()).collect();
1717    let mut errcode: cl_int = 0;
1718
1719    let ptrs = binaries.iter().map(|bin| bin.as_ptr()).collect::<Vec<_>>();
1720
1721    let program = unsafe { ffi::clCreateProgramWithBinary(
1722        context.as_ptr(),
1723        devices.len() as u32,
1724        devices.as_ptr() as *const _ as *const cl_device_id,
1725        lengths.as_ptr(),
1726        ptrs.as_ptr() as *const *const u8,
1727        binary_status.as_mut_ptr(),
1728        &mut errcode,
1729    ) };
1730
1731    r#try!(eval_errcode(errcode, (), "clCreateProgramWithBinary", None::<String>));
1732
1733    for (i, item) in binary_status.iter().enumerate() {
1734        r#try!(eval_errcode(*item, (), "clCreateProgramWithBinary", Some(format!("Device [{}]", i))));
1735    }
1736
1737    unsafe { Ok(Program::from_raw_create_ptr(program)) }
1738}
1739
1740/// [UNIMPLEMENTED: Please implement me]
1741///
1742/// [Version Controlled: OpenCL 1.2+] See module docs for more info.
1743pub fn create_program_with_built_in_kernels(device_version: Option<&OpenclVersion>)
1744            -> OclCoreResult<()> {
1745    // clCreateProgramWithBuiltInKernels(context: cl_context,
1746    //                                  num_devices: cl_uint,
1747    //                                  device_list: *const cl_device_id,
1748    //                                  kernel_names: *mut char,
1749    //                                  errcode_ret: *mut cl_int) -> cl_program;
1750    let _ =  device_version;
1751    unimplemented!();
1752}
1753
1754/// Returns a new `Program` loaded with the provided IL bytes.
1755///
1756/// [Version Controlled: OpenCL 2.1+] See module docs for more info.
1757#[cfg(feature = "opencl_version_2_1")]
1758pub fn create_program_with_il<C>(
1759        context: C,
1760        il: &[u8],
1761        device_versions: Option<&[OpenclVersion]>,
1762        ) -> OclCoreResult<Program>
1763        where C: ClContextPtr + ClVersions
1764{
1765    verify_device_versions(device_versions, [2, 1], &context, ApiFunction::CreateProgramWithIl)?;
1766
1767    let mut errcode: cl_int = 0;
1768
1769    let program_ptr = unsafe { ffi::clCreateProgramWithIL(
1770        context.as_ptr(),
1771        il.as_ptr() as *mut c_void,
1772        il.len(),
1773        &mut errcode,
1774    ) };
1775
1776    eval_errcode(errcode, program_ptr, "clCreateProgramWithIL", None::<String>)
1777        .map(|ptr| unsafe { Program::from_raw_create_ptr(ptr) })
1778}
1779
1780/// Increments a program reference counter.
1781pub unsafe fn retain_program(program: &Program) -> OclCoreResult<()> {
1782    eval_errcode(ffi::clRetainProgram(program.as_ptr()), (), "clRetainProgram", None::<String>)
1783}
1784
1785/// Decrements a program reference counter.
1786pub unsafe fn release_program(program: &Program) -> OclCoreResult<()> {
1787    eval_errcode(ffi::clReleaseProgram(program.as_ptr()), (), "clReleaseKernel", None::<String>)
1788}
1789
1790pub struct UserDataPh(usize);
1791
1792impl UserDataPh {
1793    fn unwrapped(&self) -> *mut c_void {
1794        ptr::null_mut()
1795    }
1796}
1797
1798/// Builds a program.
1799///
1800/// Callback functions are not yet supported. Please file an issue if you have
1801/// need of this functionality.
1802///
1803//
1804// [NOTE]: Despite what the spec says, some platforms segfault when `null` is
1805// passed for `devices_ptr`.
1806pub fn build_program<D: ClDeviceIdPtr>(
1807            program: &Program,
1808            devices: Option<&[D]>,
1809            options: &CString,
1810            pfn_notify: Option<BuildProgramCallbackFn>,
1811            user_data: Option<Box<UserDataPh>>,
1812        ) -> OclCoreResult<()>
1813{
1814    assert!(pfn_notify.is_none() && user_data.is_none(),
1815        "ocl::core::build_program(): Callback functions not yet implemented.");
1816
1817    let device_ptrs = DevicePtrList::from(devices);
1818
1819    let user_data = match user_data {
1820        Some(ud) => ud.unwrapped(),
1821        None => ptr::null_mut(),
1822    };
1823
1824    let errcode = unsafe { ffi::clBuildProgram(
1825        program.as_ptr() as cl_program,
1826        device_ptrs.num(),
1827        device_ptrs.as_ptr(),
1828        options.as_ptr(),
1829        pfn_notify,
1830        user_data,
1831    ) };
1832
1833    if errcode == Status::CL_BUILD_PROGRAM_FAILURE as i32 {
1834        if let Some(ds) = devices {
1835            program_build_err(program, ds).map_err(|err| err.into())
1836        } else {
1837            let ds = program.devices()?;
1838            program_build_err(program, &ds).map_err(|err| err.into())
1839        }
1840    } else {
1841        eval_errcode(errcode, (), "clBuildProgram", None::<String>)
1842    }
1843}
1844
1845/// Compiles a program’s source for all the devices or a specific device(s) in
1846/// the OpenCL context associated with program.
1847///
1848/// [Version Controlled: OpenCL 1.2+] See module docs for more info.
1849#[cfg(feature = "opencl_version_1_2")]
1850pub fn compile_program<D: ClDeviceIdPtr>(
1851            program: &Program,
1852            devices: Option<&[D]>,
1853            options: &CString,
1854            input_headers: &[&Program],
1855            header_include_names: &[CString],
1856            pfn_notify: Option<BuildProgramCallbackFn>,
1857            user_data: Option<Box<UserDataPh>>,
1858            device_versions: Option<&[OpenclVersion]>,
1859        ) -> OclCoreResult<()>
1860{
1861    verify_device_versions(device_versions, [1, 2], program, ApiFunction::CompileProgram)?;
1862
1863    assert!(pfn_notify.is_none() && user_data.is_none(),
1864        "ocl::core::compile_program(): Callback functions not yet implemented.");
1865
1866    assert!(input_headers.len() == header_include_names.len(),
1867        "ocl::core::compile_program(): Length of input_headers and header_include_names should be equal.");
1868
1869    let device_ptrs = DevicePtrList::new(devices);
1870
1871    let input_hdrs_ptrs: Vec<_> = input_headers.iter().map(|cs| cs.as_ptr()).collect();
1872    let hdrs_names_ptrs: Vec<*const _> = header_include_names.iter().map(|cs| cs.as_ptr()).collect();
1873
1874    // Will crash if ptrs is not NULL, but len is 0
1875    let (input_ptr, names_ptr) = if input_headers.is_empty() {
1876        (ptr::null(), ptr::null())
1877    } else {
1878        (input_hdrs_ptrs.as_ptr(), hdrs_names_ptrs.as_ptr())
1879    };
1880
1881    let user_data = match user_data {
1882        Some(ud) => ud.unwrapped(),
1883        None => ptr::null_mut(),
1884    };
1885
1886    let errcode = unsafe { ffi::clCompileProgram(
1887        program.as_ptr() as cl_program,
1888        device_ptrs.num(),
1889        device_ptrs.as_ptr(),
1890        options.as_ptr(),
1891        input_hdrs_ptrs.len() as cl_uint,
1892        input_ptr as *const cl_program,
1893        names_ptr as *const *const _,
1894        pfn_notify,
1895        user_data,
1896    ) };
1897
1898    if errcode == Status::CL_COMPILE_PROGRAM_FAILURE as i32 {
1899        if let Some(ds) = devices {
1900            program_build_err(program, ds).map_err(|err| err.into())
1901        } else {
1902            let ds = program.devices()?;
1903            program_build_err(program, &ds).map_err(|err| err.into())
1904        }
1905    } else {
1906        eval_errcode(errcode, (), "clCompileProgram", None::<String>)
1907    }
1908}
1909
1910/// Links a set of compiled program objects and libraries for all the devices
1911/// or a specific device(s) in the OpenCL context and creates an executable.
1912///
1913/// [Version Controlled: OpenCL 1.2+] See module docs for more info.
1914#[cfg(feature = "opencl_version_1_2")]
1915pub fn link_program<D: ClDeviceIdPtr, C: ClContextPtr>(
1916            context: C,
1917            devices: Option<&[D]>,
1918            options: &CString,
1919            input_programs: &[&Program],
1920            pfn_notify: Option<BuildProgramCallbackFn>,
1921            user_data: Option<Box<UserDataPh>>,
1922            device_versions: Option<&[OpenclVersion]>,
1923        ) -> OclCoreResult<Program>
1924{
1925    r#try!(verify_context(context));
1926    verify_device_versions(device_versions, [1, 2], &context.as_ptr(), ApiFunction::LinkProgram)?;
1927
1928    assert!(pfn_notify.is_none() && user_data.is_none(),
1929        "ocl::core::link_program(): Callback functions not yet implemented.");
1930
1931    let device_ptrs = DevicePtrList::new(devices);
1932
1933    let input_programs_ptrs: Vec<_> = input_programs.iter().map(|cs| cs.as_ptr()).collect();
1934
1935    let user_data = match user_data {
1936        Some(ud) => ud.unwrapped(),
1937        None => ptr::null_mut(),
1938    };
1939
1940    let mut errcode: cl_int = 0;
1941
1942    let program_ptr = unsafe { ffi::clLinkProgram(
1943        context.as_ptr(),
1944        device_ptrs.num(),
1945        device_ptrs.as_ptr(),
1946        options.as_ptr(),
1947        input_programs_ptrs.len() as cl_uint,
1948        input_programs_ptrs.as_ptr() as *const cl_program,
1949        pfn_notify,
1950        user_data,
1951        &mut errcode,
1952    ) };
1953
1954    eval_errcode(errcode, program_ptr, "clLinkProgram", None::<String>)
1955        .map(|ptr| unsafe { Program::from_raw_create_ptr(ptr) })
1956}
1957
1958// [DISABLED DUE TO PLATFORM INCOMPATABILITY]
1959// /// [UNTESTED]
1960// /// Unloads a platform compiler.
1961// ///
1962// /// [Version Controlled: OpenCL 1.2+] See module docs for more info.
1963// pub fn unload_platform_compiler(platform: &PlatformId,
1964//          device_version: Option<&OpenclVersion>) -> OclCoreResult<()> {
1965//     unsafe { eval_errcode("clUnloadPlatformCompiler", "",
1966//         ffi::clUnloadPlatformCompiler(platform.as_ptr())) }
1967// }
1968
1969
1970fn get_program_info_raw(program: &Program, request: ProgramInfo) -> OclCoreResult<Vec<u8>> {
1971    let mut result_size: size_t = 0;
1972
1973    let errcode = unsafe { ffi::clGetProgramInfo(
1974        program.as_ptr() as cl_program,
1975        request as cl_program_info,
1976        0 as size_t,
1977        ptr::null_mut(),
1978        &mut result_size as *mut size_t,
1979    ) };
1980
1981    eval_errcode(errcode, (), "clGetProgramInfo", None::<String>)?;
1982
1983    // If result size is zero, return an empty result directly:
1984    if result_size == 0 {
1985        return Ok(vec![]);
1986    }
1987
1988    let mut result: Vec<u8> = iter::repeat(0u8).take(result_size).collect();
1989
1990    let errcode = unsafe { ffi::clGetProgramInfo(
1991        program.as_ptr() as cl_program,
1992        request as cl_program_info,
1993        result_size,
1994        result.as_mut_ptr() as *mut _ as *mut c_void,
1995        ptr::null_mut(),
1996    ) };
1997
1998    eval_errcode(errcode, result, "clGetProgramInfo", None::<String>)
1999}
2000
2001/// Returns a `Vec` containing one `Vec<u8>` for each device associated with
2002/// `program`.
2003fn get_program_info_binaries(program: &Program) -> OclCoreResult<Vec<Vec<u8>>> {
2004    let binary_sizes_raw = get_program_info_raw(program, ProgramInfo::BinarySizes)?;
2005    let binary_sizes = unsafe { crate::util::bytes_into_vec::<usize>(binary_sizes_raw)? };
2006
2007    let binaries = binary_sizes.into_iter().map(|size| {
2008        vec![0u8; size]
2009    }).collect::<Vec<Vec<u8>>>();
2010
2011    let mut binary_ptrs = binaries.iter().map(|vec| {
2012        vec.as_ptr()
2013    }).collect::<Vec<_>>();
2014
2015    let errcode = unsafe { ffi::clGetProgramInfo(
2016        program.as_ptr() as cl_program,
2017        ProgramInfo::Binaries as cl_program_info,
2018        mem::size_of::<*mut c_void>() * binary_ptrs.len(),
2019        binary_ptrs.as_mut_ptr() as *mut _ as *mut c_void,
2020        ptr::null_mut(),
2021    ) };
2022
2023    eval_errcode(errcode, binaries, "clGetProgramInfo", None::<String>)
2024}
2025
2026/// Get program info.
2027pub fn get_program_info(program: &Program, request: ProgramInfo) -> OclCoreResult<ProgramInfoResult> {
2028    match request {
2029        ProgramInfo::Binaries => {
2030            get_program_info_binaries(program).map(ProgramInfoResult::Binaries)
2031        },
2032        _ => {
2033            let result = get_program_info_raw(program, request)?;
2034            ProgramInfoResult::from_bytes(request, result)
2035        },
2036    }
2037}
2038
2039/// Get program build info.
2040pub fn get_program_build_info<D: ClDeviceIdPtr + fmt::Debug>(obj: &Program, device_obj: D,
2041            request: ProgramBuildInfo) -> OclCoreResult<ProgramBuildInfoResult>
2042{
2043    let mut result_size: size_t = 0;
2044
2045    let errcode = unsafe { ffi::clGetProgramBuildInfo(
2046        obj.as_ptr() as cl_program,
2047        device_obj.as_ptr() as cl_device_id,
2048        request as cl_program_build_info,
2049        0 as size_t,
2050        ptr::null_mut(),
2051        &mut result_size as *mut size_t,
2052    ) };
2053
2054    eval_errcode(errcode, (), "clGetProgramBuildInfo", None::<String>)?;
2055
2056    // If result size is zero, return an empty info result directly:
2057    if result_size == 0 {
2058        return ProgramBuildInfoResult::from_bytes(request, vec![]);
2059    }
2060
2061    let mut result: Vec<u8> = iter::repeat(0u8).take(result_size).collect();
2062
2063    let errcode = unsafe { ffi::clGetProgramBuildInfo(
2064        obj.as_ptr() as cl_program,
2065        device_obj.as_ptr() as cl_device_id,
2066        request as cl_program_build_info,
2067        result_size as size_t,
2068        result.as_mut_ptr() as *mut _ as *mut c_void,
2069        ptr::null_mut(),
2070    ) };
2071
2072    let result = eval_errcode(errcode, result, "clGetProgramBuildInfo", None::<String>)?;
2073    ProgramBuildInfoResult::from_bytes(request, result)
2074}
2075
2076//============================================================================
2077//========================== Kernel Object APIs ==============================
2078//============================================================================
2079
2080/// Returns a new kernel.
2081pub fn create_kernel<S: AsRef<str>>(program: &Program, name: S) -> OclCoreResult<Kernel> {
2082    let mut err: cl_int = 0;
2083
2084    unsafe {
2085        let kernel_ptr = ffi::clCreateKernel(
2086            program.as_ptr(),
2087            r#try!(CString::new(name.as_ref().as_bytes())).as_ptr(),
2088            &mut err,
2089        );
2090
2091        eval_errcode(err, kernel_ptr, "clCreateKernel", Some(name.as_ref()))
2092            .map(|ptr| Kernel::from_raw_create_ptr(ptr))
2093    }
2094}
2095
2096/// [UNIMPLEMENTED: Please implement me]
2097pub fn create_kernels_in_program() -> OclCoreResult<()> {
2098    // ffi::clCreateKernelsInProgram(program: cl_program,
2099    //                             num_kernels: cl_uint,
2100    //                             kernels: *mut cl_kernel,
2101    //                             num_kernels_ret: *mut cl_uint) -> cl_int;
2102    unimplemented!();
2103}
2104
2105/// Increments a kernel reference counter.
2106pub unsafe fn retain_kernel(kernel: &Kernel) -> OclCoreResult<()> {
2107    eval_errcode(ffi::clRetainKernel(kernel.as_ptr()), (), "clRetainKernel", None::<String>)
2108}
2109
2110/// Decrements a kernel reference counter.
2111pub unsafe fn release_kernel(kernel: &Kernel) -> OclCoreResult<()> {
2112    eval_errcode(ffi::clReleaseKernel(kernel.as_ptr()), (), "clReleaseKernel", None::<String>)
2113}
2114
2115
2116/// Sets the argument value for the kernel argument at `index`.
2117///
2118/// ### Example:
2119///
2120/// ```rust, ignore
2121/// let kernel = core::create_kernel(&program, "multiply")?;
2122/// core::set_kernel_arg(&kernel, 0, ArgVal::scalar(&10.0f32))?;
2123/// core::set_kernel_arg(&kernel, 1, ArgVal::mem(&buffer))?;
2124/// ```
2125///
2126/// [SDK Documentation](https://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clSetKernelArg.html)
2127pub fn set_kernel_arg(kernel: &Kernel, index: u32, arg_val: ArgVal)
2128        -> OclCoreResult<()>
2129{
2130    let (size, value) = arg_val.as_raw();
2131
2132    let err = unsafe { ffi::clSetKernelArg(
2133            kernel.as_ptr(),
2134            index,
2135            size,
2136            value,
2137    ) };
2138
2139    if err != Status::CL_SUCCESS as i32 {
2140        let name = get_kernel_name(kernel)?;
2141        eval_errcode(err, (), "clSetKernelArg", Some(name))
2142    } else {
2143        Ok(())
2144    }
2145}
2146
2147/// Get kernel info.
2148pub fn get_kernel_info(obj: &Kernel, request: KernelInfo) -> OclCoreResult<KernelInfoResult> {
2149    let mut result_size: size_t = 0;
2150
2151    let errcode = unsafe { ffi::clGetKernelInfo(
2152        obj.as_ptr() as cl_kernel,
2153        request as cl_kernel_info,
2154        0 as size_t,
2155        ptr::null_mut(),
2156        &mut result_size as *mut size_t,
2157    ) };
2158
2159    eval_errcode(errcode, (), "clGetKernelInfo", None::<String>)?;
2160
2161    // If result size is zero, return an empty info result directly:
2162    if result_size == 0 {
2163        return KernelInfoResult::from_bytes(request, vec![]);
2164    }
2165
2166    let mut result: Vec<u8> = iter::repeat(0u8).take(result_size).collect();
2167
2168    let errcode = unsafe { ffi::clGetKernelInfo(
2169        obj.as_ptr() as cl_kernel,
2170        request as cl_kernel_info,
2171        result_size,
2172        result.as_mut_ptr() as *mut _ as *mut c_void,
2173        ptr::null_mut(),
2174    ) };
2175
2176    let result = eval_errcode(errcode, result, "clGetKernelInfo", None::<String>)?;
2177    KernelInfoResult::from_bytes(request, result)
2178}
2179
2180/// Get kernel arg info.
2181///
2182/// [Version Controlled: OpenCL 1.2+] See module docs for more info.
2183pub fn get_kernel_arg_info(obj: &Kernel, arg_index: u32, request: KernelArgInfo,
2184        device_versions: Option<&[OpenclVersion]>) -> OclCoreResult<KernelArgInfoResult>
2185{
2186    // Verify device version:
2187    // if let Err(err) = verify_device_versions(device_versions, [1, 2], obj,
2188    //         ApiFunction::GetKernelArgInfo) {
2189    //     return Err(OclCoreError::from(err));
2190    // }
2191
2192    // Verify device version:
2193    verify_device_versions(device_versions, [1, 2], obj, ApiFunction::GetKernelArgInfo)?;
2194
2195    let mut result_size: size_t = 0;
2196
2197    let errcode = unsafe { ffi::clGetKernelArgInfo(
2198        obj.as_ptr() as cl_kernel,
2199        arg_index as cl_uint,
2200        request as cl_kernel_arg_info,
2201        0 as size_t,
2202        ptr::null_mut(),
2203        &mut result_size as *mut size_t,
2204    ) };
2205
2206    // try!(eval_errcode(errcode, result, "clGetKernelArgInfo", None::<String>));
2207    // if let Err(err) = eval_errcode(errcode, (), "clGetKernelArgInfo", None::<String>) {
2208    //     return KernelArgInfoResult::from(err);
2209    // }
2210    eval_errcode(errcode, (), "clGetKernelArgInfo", None::<String>)?;
2211
2212    // If result size is zero, return an empty info result directly:
2213    if result_size == 0 {
2214        return KernelArgInfoResult::from_bytes(request, vec![]);
2215    }
2216
2217    let mut result: Vec<u8> = iter::repeat(0u8).take(result_size).collect();
2218
2219    let errcode = unsafe { ffi::clGetKernelArgInfo(
2220        obj.as_ptr() as cl_kernel,
2221        arg_index as cl_uint,
2222        request as cl_kernel_arg_info,
2223        result_size,
2224        result.as_mut_ptr() as *mut _ as *mut c_void,
2225        ptr::null_mut(),
2226    ) };
2227
2228    let result = eval_errcode(errcode, result, "clGetKernelArgInfo", None::<String>)?;
2229    KernelArgInfoResult::from_bytes(request, result)
2230}
2231
2232/// Get kernel work group info.
2233pub fn get_kernel_work_group_info<D: ClDeviceIdPtr>(obj: &Kernel, device_obj: D,
2234            request: KernelWorkGroupInfo) -> OclCoreResult<KernelWorkGroupInfoResult>
2235{
2236    let mut result_size: size_t = 0;
2237
2238    let errcode = unsafe { ffi::clGetKernelWorkGroupInfo(
2239        obj.as_ptr() as cl_kernel,
2240        device_obj.as_ptr() as cl_device_id,
2241        request as cl_kernel_work_group_info,
2242        0 as size_t,
2243        ptr::null_mut(),
2244        &mut result_size as *mut size_t,
2245    ) };
2246
2247    // Make printing certain platform-specific errors less scary looking:
2248    if let Err(err) = eval_errcode(errcode, (), "clGetKernelWorkGroupInfo", None::<String>) {
2249        if let Some(status) = err.api_status() {
2250            // NVIDIA / APPLE (i think):
2251            if request == KernelWorkGroupInfo::GlobalWorkSize &&
2252                    status == Status::CL_INVALID_VALUE {
2253                return Ok(KernelWorkGroupInfoResult::CustomBuiltinOnly);
2254            }
2255
2256            // APPLE (bleh):
2257            if status == Status::CL_INVALID_DEVICE {
2258                return Ok(KernelWorkGroupInfoResult::Unavailable(status));
2259            }
2260        }
2261
2262        return Err(err);
2263    }
2264
2265    // If result size is zero, return an empty info result directly:
2266    if result_size == 0 {
2267        return KernelWorkGroupInfoResult::from_bytes(request, vec![]);
2268    }
2269
2270    let mut result: Vec<u8> = iter::repeat(0u8).take(result_size).collect();
2271
2272    let errcode = unsafe { ffi::clGetKernelWorkGroupInfo(
2273        obj.as_ptr() as cl_kernel,
2274        device_obj.as_ptr() as cl_device_id,
2275        request as cl_kernel_work_group_info,
2276        result_size,
2277        result.as_mut_ptr() as *mut _ as *mut c_void,
2278        ptr::null_mut(),
2279    ) };
2280
2281    let result = eval_errcode(errcode, result, "clGetKernelWorkGroupInfo", None::<String>)?;
2282    KernelWorkGroupInfoResult::from_bytes(request, result)
2283}
2284
2285//============================================================================
2286//========================== Event Object APIs ===============================
2287//============================================================================
2288
2289/// Blocks until the first `num_events` events in `event_list` are complete.
2290pub fn wait_for_events(num_events: u32, event_list: &dyn ClWaitListPtr) -> OclCoreResult<()> {
2291    assert!(event_list.count() >= num_events);
2292
2293    let errcode = unsafe {
2294        ffi::clWaitForEvents(num_events, event_list.as_ptr_ptr())
2295    };
2296
2297    eval_errcode(errcode, (), "clWaitForEvents", None::<String>)
2298}
2299
2300/// Get event info.
2301pub fn get_event_info<'e, E: ClEventPtrRef<'e>>(event: &'e E, request: EventInfo) -> OclCoreResult<EventInfoResult> {
2302    let mut result_size: size_t = 0;
2303
2304    let errcode = unsafe { ffi::clGetEventInfo(
2305        *event.as_ptr_ref(),
2306        request as cl_event_info,
2307        0 as size_t,
2308        ptr::null_mut(),
2309        &mut result_size as *mut size_t,
2310    ) };
2311
2312    eval_errcode(errcode, (), "clGetEventInfo", None::<String>)?;
2313
2314    // If result size is zero, return an empty info result directly:
2315    if result_size == 0 {
2316        return EventInfoResult::from_bytes(request, vec![]);
2317    }
2318
2319    let mut result: Vec<u8> = iter::repeat(0u8).take(result_size).collect();
2320
2321    let errcode = unsafe { ffi::clGetEventInfo(
2322        *event.as_ptr_ref(),
2323        request as cl_event_info,
2324        result_size,
2325        result.as_mut_ptr() as *mut _ as *mut c_void,
2326        ptr::null_mut(),
2327    ) };
2328
2329    let result = eval_errcode(errcode, result, "clGetEventInfo", None::<String>)?;
2330    EventInfoResult::from_bytes(request, result)
2331}
2332
2333/// Creates an event not already associated with any command.
2334pub fn create_user_event<C>(context: C) -> OclCoreResult<Event>
2335        where C: ClContextPtr
2336{
2337    let mut errcode = 0;
2338    let event = unsafe { Event::from_raw_create_ptr(ffi::clCreateUserEvent(context.as_ptr(), &mut errcode)) };
2339    eval_errcode(errcode, event, "clCreateUserEvent", None::<String>)
2340}
2341
2342/// Increments an event's reference counter.
2343pub unsafe fn retain_event<'e, E: ClEventPtrRef<'e>>(event: &'e E) -> OclCoreResult<()> {
2344    eval_errcode(ffi::clRetainEvent(*event.as_ptr_ref()), (), "clRetainEvent", None::<String>)
2345}
2346
2347/// Decrements an event's reference counter.
2348pub unsafe fn release_event<'e, E: ClEventPtrRef<'e>>(event: &'e E) -> OclCoreResult<()> {
2349    eval_errcode(ffi::clReleaseEvent(*event.as_ptr_ref()), (), "clReleaseEvent", None::<String>)
2350}
2351
2352/// Updates a user events status.
2353///
2354/// Setting status to completion will cause commands waiting upon this event
2355/// to execute.
2356///
2357/// Will return an error if the event is not a 'user' event (created with
2358/// `::create_user_event`).
2359///
2360/// Valid options are (for OpenCL versions 1.1 - 2.1):
2361///
2362/// `CommandExecutionStatus::Complete`
2363/// `CommandExecutionStatus::Running`
2364/// `CommandExecutionStatus::Submitted`
2365/// `CommandExecutionStatus::Queued`
2366///
2367/// To the best of the author's knowledge, the only variant that matters is
2368/// `::Complete`. Everything else is functionally equivalent and is useful
2369/// only for debugging or profiling purposes (this may change in the future).
2370///
2371pub fn set_user_event_status<'e,E: ClEventPtrRef<'e>>(event: &'e E,
2372            execution_status: CommandExecutionStatus) -> OclCoreResult<()>
2373{
2374    unsafe {
2375        #[cfg(feature = "event_debug_print")]
2376        println!("::set_user_event_status: Setting user event status for event: {:?}", *event.as_ptr_ref());
2377
2378        eval_errcode(ffi::clSetUserEventStatus(*event.as_ptr_ref(), execution_status as cl_int),
2379            (), "clSetUserEventStatus", None::<String>)
2380    }
2381}
2382
2383/// Sets a callback function which is called as soon as the `callback_trigger`
2384/// status is reached.
2385///
2386/// ## Safety
2387///
2388///
2389///
2390pub unsafe fn set_event_callback<'e, E: ClEventPtrRef<'e>>(
2391            event: &'e E,
2392            callback_trigger: CommandExecutionStatus,
2393            callback_receiver: Option<EventCallbackFn>,
2394            user_data: *mut c_void,
2395        ) -> OclCoreResult<()>
2396{
2397    eval_errcode(ffi::clSetEventCallback(
2398        *event.as_ptr_ref(),
2399        callback_trigger as cl_int,
2400        callback_receiver,
2401        user_data,
2402    ), (), "clSetEventCallback", None::<String>)
2403}
2404
2405//============================================================================
2406//============================ Profiling APIs ================================
2407//============================================================================
2408
2409/// Get event profiling info (for debugging / benchmarking).
2410pub fn get_event_profiling_info<'e, E: ClEventPtrRef<'e>>(event: &'e E, request: ProfilingInfo)
2411        -> OclCoreResult<ProfilingInfoResult> {
2412    // Apple compatibile value:
2413    let max_result_size_bytes = 8;
2414    let mut result_size: size_t = 0;
2415    let event: cl_event = unsafe { *event.as_ptr_ref() };
2416
2417    let errcode = unsafe { ffi::clGetEventProfilingInfo(
2418        event,
2419        request as cl_profiling_info,
2420        max_result_size_bytes,
2421        ptr::null_mut(),
2422        &mut result_size as *mut size_t,
2423    ) };
2424
2425    // Make sure our assumption about the maximum value was correct:
2426    assert!(result_size <= max_result_size_bytes);
2427
2428    // Don't generate a full error report for `CL_INVALID_VALUE` it just means
2429    // that event profiling info is not available on this platform.
2430    if errcode < 0 && Status::from_i32(errcode).unwrap() == Status::CL_INVALID_VALUE {
2431        return Err(OclCoreError::from("<unavailable (CL_INVALID_VALUE)>"));
2432    }
2433
2434    eval_errcode(errcode, (), "clGetEventProfilingInfo", None::<String>)?;
2435
2436    // If result size is zero, return an empty info result directly:
2437    if result_size == 0 {
2438        return ProfilingInfoResult::from_bytes(request, vec![]);
2439    }
2440
2441    let mut result: Vec<u8> = iter::repeat(0u8).take(result_size).collect();
2442
2443    let errcode = unsafe { ffi::clGetEventProfilingInfo(
2444        event,
2445        request as cl_profiling_info,
2446        result_size,
2447        result.as_mut_ptr() as *mut _ as *mut c_void,
2448        ptr::null_mut(),
2449    ) };
2450
2451    let result = eval_errcode(errcode, result, "clGetEventProfilingInfo", None::<String>)?;
2452    ProfilingInfoResult::from_bytes(request, result)
2453}
2454
2455//============================================================================
2456//========================= Flush and Finish APIs ============================
2457//============================================================================
2458
2459/// Flushes a command queue.
2460///
2461/// Issues all previously queued OpenCL commands in a command-queue to the
2462/// device associated with the command-queue.
2463pub fn flush(command_queue: &CommandQueue) -> OclCoreResult<()> {
2464    unsafe { eval_errcode(ffi::clFlush(command_queue.as_ptr()), (), "clFlush", None::<String>) }
2465}
2466
2467/// Waits for a queue to finish.
2468///
2469/// Blocks until all previously queued OpenCL commands in a command-queue are
2470/// issued to the associated device and have completed.
2471pub fn finish(command_queue: &CommandQueue) -> OclCoreResult<()> {
2472    unsafe {
2473        let errcode = ffi::clFinish(command_queue.as_ptr());
2474        eval_errcode(errcode, (), "clFinish", None::<String>)
2475    }
2476}
2477
2478//============================================================================
2479//======================= Enqueued Commands APIs =============================
2480//============================================================================
2481
2482/// Enqueues a read from device memory referred to by `buffer` to device memory,
2483/// `data`.
2484///
2485/// ## Safety
2486///
2487/// Caller must ensure that `data` lives until the read is complete. Use
2488/// `new_event` to monitor it (use [`core::EventList::last_clone`] if passing
2489/// an event list as `new_event`).
2490///
2491///
2492/// [`core::EventList::get_clone`]: struct.EventList.html#method.last_clone
2493///
2494pub unsafe fn enqueue_read_buffer<T, M, En, Ewl>(
2495        command_queue: &CommandQueue,
2496        buffer: M,
2497        block: bool,
2498        offset: usize,
2499        data: &mut [T],
2500        wait_list: Option<Ewl>,
2501        new_event: Option<En>,
2502        ) -> OclCoreResult<()>
2503        where T: OclPrm, En: ClNullEventPtr, Ewl: ClWaitListPtr, M: AsMem<T> + MemCmdRw
2504{
2505    let (wait_list_len, wait_list_ptr, new_event_ptr) =
2506        resolve_event_ptrs(wait_list, new_event);
2507
2508    let offset_bytes = offset * mem::size_of::<T>();
2509
2510    let errcode = ffi::clEnqueueReadBuffer(
2511        command_queue.as_ptr(),
2512        buffer.as_mem().as_ptr(),
2513        block as cl_uint,
2514        offset_bytes,
2515        (data.len() * mem::size_of::<T>()) as size_t,
2516        data.as_ptr() as cl_mem,
2517        wait_list_len,
2518        wait_list_ptr,
2519        new_event_ptr,
2520    );
2521
2522    eval_errcode(errcode, (), "clEnqueueReadBuffer", None::<String>)
2523}
2524
2525/// Enqueues a command to read from a rectangular region from a buffer object to host memory.
2526///
2527/// ## Safety
2528///
2529/// Caller must ensure that `data` lives until the read is complete. Use
2530/// `new_event` to monitor it (use [`core::EventList::last_clone`] if passing
2531/// an event list as `new_event`).
2532///
2533/// ## Official Documentation
2534///
2535/// [SDK - clEnqueueReadBufferRect](https://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clEnqueueReadBufferRect.html)
2536///
2537///
2538/// [`core::EventList::get_clone`]: struct.EventList.html#method.last_clone
2539///
2540pub unsafe fn enqueue_read_buffer_rect<T, M, En, Ewl>(
2541            command_queue: &CommandQueue,
2542            buffer: M,
2543            block: bool,
2544            buffer_origin: [usize; 3],
2545            host_origin: [usize; 3],
2546            region: [usize; 3],
2547            buffer_row_pitch_bytes: usize,
2548            buffer_slc_pitch_bytes: usize,
2549            host_row_pitch_bytes: usize,
2550            host_slc_pitch_bytes: usize,
2551            data: &mut [T],
2552            wait_list: Option<Ewl>,
2553            new_event: Option<En>,
2554        ) -> OclCoreResult<()>
2555        where T: OclPrm, En: ClNullEventPtr, Ewl: ClWaitListPtr, M: AsMem<T> + MemCmdRw
2556{
2557    let buffer_origin_bytes = [buffer_origin[0] * mem::size_of::<T>(),
2558        buffer_origin[1], buffer_origin[2]];
2559    let host_origin_bytes = [host_origin[0] * mem::size_of::<T>(),
2560        host_origin[1], host_origin[2]];
2561    let region_bytes = [region[0] * mem::size_of::<T>(), region[1], region[2]];
2562
2563    // DEBUG:
2564    if false {
2565        println!("buffer_origin_bytes: {:?}, host_origin_bytes: {:?}, region_bytes: {:?}",
2566            buffer_origin_bytes, host_origin_bytes, region_bytes);
2567        println!("buffer_row_pitch_bytes: {}, buffer_slc_pitch_bytes: {}, \
2568            host_row_pitch_bytes: {}, host_slc_pitch_bytes: {}",
2569            buffer_row_pitch_bytes, buffer_slc_pitch_bytes, host_row_pitch_bytes, host_slc_pitch_bytes);
2570    }
2571
2572    let (wait_list_len, wait_list_ptr, new_event_ptr) =
2573        resolve_event_ptrs(wait_list, new_event);
2574
2575    let errcode = ffi::clEnqueueReadBufferRect(
2576        command_queue.as_ptr(),
2577        buffer.as_mem().as_ptr(),
2578        block as cl_uint,
2579        &buffer_origin_bytes as *const _ as *const usize,
2580        &host_origin_bytes as *const _ as *const usize,
2581        &region_bytes as *const _ as *const usize,
2582        buffer_row_pitch_bytes,
2583        buffer_slc_pitch_bytes,
2584        host_row_pitch_bytes,
2585        host_slc_pitch_bytes,
2586        data.as_ptr() as cl_mem,
2587        wait_list_len,
2588        wait_list_ptr,
2589        new_event_ptr,
2590    );
2591
2592    eval_errcode(errcode, (), "clEnqueueReadBufferRect", None::<String>)
2593}
2594
2595/// Enqueues a write from host memory, `data`, to device memory referred to by
2596/// `buffer`.
2597///
2598/// ## Safety
2599///
2600/// Caller must ensure that `data` lives until the read is complete. Use
2601/// `new_event` to monitor it (use [`core::EventList::last_clone`] if passing
2602/// an event list as `new_event`).
2603///
2604pub unsafe fn enqueue_write_buffer<T, M, En, Ewl>(
2605            command_queue: &CommandQueue,
2606            buffer: M,
2607            block: bool,
2608            offset: usize,
2609            data: &[T],
2610            wait_list: Option<Ewl>,
2611            new_event: Option<En>,
2612        ) -> OclCoreResult<()>
2613        where T: OclPrm, En: ClNullEventPtr, Ewl: ClWaitListPtr, M: AsMem<T> + MemCmdRw
2614{
2615    let (wait_list_len, wait_list_ptr, new_event_ptr) =
2616        resolve_event_ptrs(wait_list, new_event);
2617
2618    let offset_bytes = offset * mem::size_of::<T>();
2619
2620    let errcode = ffi::clEnqueueWriteBuffer(
2621        command_queue.as_ptr(),
2622        buffer.as_mem().as_ptr(),
2623        block as cl_uint,
2624        offset_bytes,
2625        (data.len() * mem::size_of::<T>()) as size_t,
2626        data.as_ptr() as cl_mem,
2627        wait_list_len,
2628        wait_list_ptr,
2629        new_event_ptr,
2630    );
2631    eval_errcode(errcode, (), "clEnqueueWriteBuffer", None::<String>)
2632}
2633
2634/// Enqueues a command to write from a rectangular region from host memory to a buffer object.
2635///
2636/// ## Safety
2637///
2638/// Caller must ensure that `data` lives until the read is complete. Use
2639/// `new_event` to monitor it (use [`core::EventList::last_clone`] if passing
2640/// an event list as `new_event`).
2641///
2642/// ## Official Documentation
2643///
2644/// [SDK - clEnqueueWriteBufferRect]
2645///
2646/// [SDK - clEnqueueWriteBufferRect]: https://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clEnqueueWriteBufferRect.html
2647///
2648pub unsafe fn enqueue_write_buffer_rect<T, M, En, Ewl>(
2649            command_queue: &CommandQueue,
2650            buffer: M,
2651            block: bool,
2652            buffer_origin: [usize; 3],
2653            host_origin: [usize; 3],
2654            region: [usize; 3],
2655            buffer_row_pitch_bytes: usize,
2656            buffer_slc_pitch_bytes: usize,
2657            host_row_pitch_bytes: usize,
2658            host_slc_pitch_bytes: usize,
2659            data: &[T],
2660            wait_list: Option<Ewl>,
2661            new_event: Option<En>,
2662    ) -> OclCoreResult<()>
2663    where T: OclPrm, En: ClNullEventPtr, Ewl: ClWaitListPtr, M: AsMem<T> + MemCmdRw
2664{
2665    let (wait_list_len, wait_list_ptr, new_event_ptr) =
2666        resolve_event_ptrs(wait_list, new_event);
2667
2668    let buffer_origin_bytes = [buffer_origin[0] * mem::size_of::<T>(),
2669        buffer_origin[1], buffer_origin[2]];
2670    let host_origin_bytes = [host_origin[0] * mem::size_of::<T>(),
2671        host_origin[1], host_origin[2]];
2672    let region_bytes = [region[0] * mem::size_of::<T>(), region[1], region[2]];
2673
2674    let errcode = ffi::clEnqueueWriteBufferRect(
2675        command_queue.as_ptr(),
2676        buffer.as_mem().as_ptr(),
2677        block as cl_uint,
2678        &buffer_origin_bytes as *const _ as *const usize,
2679        &host_origin_bytes as *const _ as *const usize,
2680        &region_bytes as *const _ as *const usize,
2681        buffer_row_pitch_bytes,
2682        buffer_slc_pitch_bytes,
2683        host_row_pitch_bytes,
2684        host_slc_pitch_bytes,
2685        data.as_ptr() as cl_mem,
2686        wait_list_len,
2687        wait_list_ptr,
2688        new_event_ptr,
2689    );
2690    eval_errcode(errcode, (), "clEnqueueWriteBufferRect", None::<String>)
2691}
2692
2693/// Enqueues a command to fill a buffer object with a pattern of a given pattern size.
2694///
2695/// ## Pattern (from [SDK Docs](https://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clEnqueueFillBuffer.html))
2696///
2697/// [Version Controlled: OpenCL 1.2+] See module docs for more info.
2698#[cfg(not(feature="opencl_vendor_mesa"))]
2699pub fn enqueue_fill_buffer<T, M, En, Ewl>(
2700            command_queue: &CommandQueue,
2701            buffer: M,
2702            pattern: T,
2703            offset: usize,
2704            len: usize,
2705            wait_list: Option<Ewl>,
2706            new_event: Option<En>,
2707            device_version: Option<&OpenclVersion>
2708        ) -> OclCoreResult<()>
2709        where T: OclPrm, En: ClNullEventPtr, Ewl: ClWaitListPtr, M: AsMem<T> + MemCmdRw
2710{
2711    verify_device_version(device_version, [1, 2], command_queue,
2712            ApiFunction::EnqueueFillBuffer)?;
2713
2714    let pattern_size = mem::size_of::<T>();
2715    let offset_bytes = offset * mem::size_of::<T>();
2716    let size_bytes = len * mem::size_of::<T>();
2717
2718    let (wait_list_len, wait_list_ptr, new_event_ptr)
2719        = resolve_event_ptrs(wait_list, new_event);
2720
2721    let errcode = unsafe { ffi::clEnqueueFillBuffer(
2722        command_queue.as_ptr(),
2723        buffer.as_mem().as_ptr(),
2724        &pattern as *const _ as *const c_void,
2725        pattern_size,
2726        offset_bytes,
2727        size_bytes,
2728        wait_list_len,
2729        wait_list_ptr,
2730        new_event_ptr,
2731    ) };
2732    eval_errcode(errcode, (), "clEnqueueFillBuffer", None::<String>)
2733}
2734
2735/// Copies the contents of one buffer to another.
2736pub fn enqueue_copy_buffer<T, M, En, Ewl>(
2737            command_queue: &CommandQueue,
2738            src_buffer: M,
2739            dst_buffer: M,
2740            src_offset: usize,
2741            dst_offset: usize,
2742            len: usize,
2743            wait_list: Option<Ewl>,
2744            new_event: Option<En>,
2745        ) -> OclCoreResult<()>
2746        where T: OclPrm, En: ClNullEventPtr, Ewl: ClWaitListPtr, M: AsMem<T> + MemCmdAll
2747{
2748    let (wait_list_len, wait_list_ptr, new_event_ptr)
2749        = resolve_event_ptrs(wait_list, new_event);
2750
2751    let src_offset_bytes = src_offset * mem::size_of::<T>();
2752    let dst_offset_bytes = dst_offset * mem::size_of::<T>();
2753    let len_bytes = len * mem::size_of::<T>();
2754
2755    let errcode = unsafe { ffi::clEnqueueCopyBuffer(
2756        command_queue.as_ptr(),
2757        src_buffer.as_mem().as_ptr(),
2758        dst_buffer.as_mem().as_ptr(),
2759        src_offset_bytes,
2760        dst_offset_bytes,
2761        len_bytes,
2762        wait_list_len,
2763        wait_list_ptr,
2764        new_event_ptr,
2765    ) };
2766    eval_errcode(errcode, (), "clEnqueueCopyBuffer", None::<String>)
2767}
2768
2769/// Enqueues a command to copy a rectangular region from a buffer object to
2770/// another buffer object.
2771///
2772/// [SDK Docs](https://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clEnqueueCopyBufferRect.html)
2773///
2774pub fn enqueue_copy_buffer_rect<T, M, En, Ewl>(
2775            command_queue: &CommandQueue,
2776            src_buffer: M,
2777            dst_buffer: M,
2778            src_origin: [usize; 3],
2779            dst_origin: [usize; 3],
2780            region: [usize; 3],
2781            src_row_pitch_bytes: usize,
2782            src_slc_pitch_bytes: usize,
2783            dst_row_pitch_bytes: usize,
2784            dst_slc_pitch_bytes: usize,
2785            wait_list: Option<Ewl>,
2786            new_event: Option<En>,
2787        ) -> OclCoreResult<()>
2788        where T: OclPrm, En: ClNullEventPtr, Ewl: ClWaitListPtr, M: AsMem<T> + MemCmdAll
2789{
2790    let (wait_list_len, wait_list_ptr, new_event_ptr) =
2791        resolve_event_ptrs(wait_list, new_event);
2792
2793    let src_origin_bytes = [src_origin[0] * mem::size_of::<T>(),
2794        src_origin[1], src_origin[2]];
2795    let dst_origin_bytes = [dst_origin[0] * mem::size_of::<T>(),
2796        dst_origin[1], dst_origin[2]];
2797    let region_bytes = [region[0] * mem::size_of::<T>(), region[1], region[2]];
2798
2799    let errcode = unsafe { ffi::clEnqueueCopyBufferRect(
2800        command_queue.as_ptr(),
2801        src_buffer.as_mem().as_ptr(),
2802        dst_buffer.as_mem().as_ptr(),
2803        &src_origin_bytes as *const _ as *const usize,
2804        &dst_origin_bytes as *const _ as *const usize,
2805        &region_bytes as *const _ as *const usize,
2806        src_row_pitch_bytes,
2807        src_slc_pitch_bytes,
2808        dst_row_pitch_bytes,
2809        dst_slc_pitch_bytes,
2810        wait_list_len,
2811        wait_list_ptr,
2812        new_event_ptr,
2813    ) };
2814    eval_errcode(errcode, (), "clEnqueueCopyBufferRect", None::<String>)
2815}
2816
2817/// Acquire OpenCL memory objects (buffers and images) that have been created
2818/// from OpenGL objects.
2819///
2820/// To create a slice from a single `Mem` reference without any cost, use
2821/// something like: `unsafe { ::std::slice::from_raw_parts(&core_mem, 1) };`.
2822///
2823#[cfg(not(feature="opencl_vendor_mesa"))]
2824pub fn enqueue_acquire_gl_objects<En, Ewl>(
2825            command_queue: &CommandQueue,
2826            buffers: &[Mem],
2827            wait_list: Option<Ewl>,
2828            new_event: Option<En>,
2829        ) -> OclCoreResult<()>
2830        where En: ClNullEventPtr, Ewl: ClWaitListPtr
2831{
2832    let (wait_list_len, wait_list_ptr, new_event_ptr) =
2833        resolve_event_ptrs(wait_list, new_event);
2834
2835    let errcode = unsafe { clEnqueueAcquireGLObjects(
2836        command_queue.as_ptr(),
2837        buffers.len() as u32,
2838        buffers.as_ptr() as *const cl_mem,
2839        wait_list_len,
2840        wait_list_ptr,
2841        new_event_ptr
2842    ) };
2843    eval_errcode(errcode, (), "clEnqueueAcquireGLObjects", None::<String>)
2844}
2845
2846/// Release OpenCL memory objects (buffers and images) that have been created
2847/// from OpenGL objects.
2848///
2849/// To create a slice from a single `Mem` reference without any cost, use
2850/// something like: `unsafe { ::std::slice::from_raw_parts(&core_mem, 1) };`.
2851///
2852#[cfg(not(feature="opencl_vendor_mesa"))]
2853pub fn enqueue_release_gl_objects<En, Ewl>(
2854            command_queue: &CommandQueue,
2855            buffers: &[Mem],
2856            wait_list: Option<Ewl>,
2857            new_event: Option<En>,
2858        ) -> OclCoreResult<()>
2859        where En: ClNullEventPtr, Ewl: ClWaitListPtr
2860{
2861    let (wait_list_len, wait_list_ptr, new_event_ptr) =
2862        resolve_event_ptrs(wait_list, new_event);
2863
2864    let errcode = unsafe { clEnqueueReleaseGLObjects(
2865        command_queue.as_ptr(),
2866        buffers.len() as u32,
2867        buffers.as_ptr() as *const cl_mem,
2868        wait_list_len,
2869        wait_list_ptr,
2870        new_event_ptr
2871    ) };
2872    eval_errcode(errcode, (), "clEnqueueReleaseGLObjects", None::<String>)
2873}
2874
2875
2876/// Reads an image from device to host memory.
2877///
2878/// ## Safety
2879///
2880/// Caller must ensure that `data` lives until the read is complete. Use
2881/// `new_event` to monitor it (use [`core::EventList::last_clone`] if passing
2882/// an event list as `new_event`).
2883///
2884/// [`core::EventList::get_clone`]: struct.EventList.html#method.last_clone
2885///
2886// pub unsafe fn enqueue_read_image<T>(
2887pub unsafe fn enqueue_read_image<T, M, En, Ewl>(
2888            command_queue: &CommandQueue,
2889            image: M,
2890            block: bool,
2891            origin: [usize; 3],
2892            region: [usize; 3],
2893            row_pitch_bytes: usize,
2894            slc_pitch_bytes: usize,
2895            data: &mut [T],
2896            wait_list: Option<Ewl>,
2897            new_event: Option<En>,
2898        ) -> OclCoreResult<()>
2899        where T: OclPrm, En: ClNullEventPtr, Ewl: ClWaitListPtr, M: AsMem<T> + MemCmdRw
2900{
2901    let (wait_list_len, wait_list_ptr, new_event_ptr)
2902        = resolve_event_ptrs(wait_list, new_event);
2903
2904    let errcode = ffi::clEnqueueReadImage(
2905        command_queue.as_ptr(),
2906        image.as_mem().as_ptr(),
2907        block as cl_uint,
2908        &origin as *const _ as *const usize,
2909        &region as *const _ as *const usize,
2910        row_pitch_bytes,
2911        slc_pitch_bytes,
2912        data.as_ptr() as cl_mem,
2913        wait_list_len,
2914        wait_list_ptr,
2915        new_event_ptr,
2916    );
2917    eval_errcode(errcode, (), "clEnqueueReadImage", None::<String>)
2918}
2919
2920
2921/// Enqueues a command to write to an image or image array object from host memory.
2922///
2923/// ## Safety
2924///
2925/// Caller must ensure that `data` lives until the read is complete. Use
2926/// `new_event` to monitor it (use [`core::EventList::last_clone`] if passing
2927/// an event list as `new_event`).
2928///
2929// TODO:
2930// * Size check (rather than leaving it to API).
2931// * Consider safetyness: local host data could change during write.
2932//
2933pub unsafe fn enqueue_write_image<T, M, En, Ewl>(
2934            command_queue: &CommandQueue,
2935            image: M,
2936            block: bool,
2937            origin: [usize; 3],
2938            region: [usize; 3],
2939            input_row_pitch_bytes: usize,
2940            input_slc_pitch_bytes: usize,
2941            data: &[T],
2942            wait_list: Option<Ewl>,
2943            new_event: Option<En>,
2944        ) -> OclCoreResult<()>
2945        where T: OclPrm, En: ClNullEventPtr, Ewl: ClWaitListPtr, M: AsMem<T> + MemCmdRw
2946{
2947    let (wait_list_len, wait_list_ptr, new_event_ptr)
2948        = resolve_event_ptrs(wait_list, new_event);
2949
2950    let errcode = ffi::clEnqueueWriteImage(
2951        command_queue.as_ptr(),
2952        image.as_mem().as_ptr(),
2953        block as cl_uint,
2954        &origin as *const _ as *const usize,
2955        &region as *const _ as *const usize,
2956        input_row_pitch_bytes,
2957        input_slc_pitch_bytes,
2958        data.as_ptr() as cl_mem,
2959        wait_list_len,
2960        wait_list_ptr,
2961        new_event_ptr,
2962    );
2963    eval_errcode(errcode, (), "clEnqueueWriteImage", None::<String>)
2964}
2965
2966/// Enqueues a command to fill an image object with a specified color.
2967///
2968/// ## Fill Color (from [SDK docs](https://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clEnqueueFillImage.html)
2969///
2970/// The fill color. The fill color is a four component RGBA floating-point color
2971/// value if the image channel data type is not an unnormalized signed and
2972/// unsigned integer type, is a four component signed integer value if the image
2973/// channel data type is an unnormalized signed integer type and is a four
2974/// component unsigned integer value if the image channel data type is an
2975/// unormalized unsigned integer type. The fill color will be converted to the
2976/// appropriate image channel format and order associated with image.
2977///
2978/// TODO: Trait constraints for `T`. Presumably it should be 32bits? Testing needed.
2979///
2980/// [Version Controlled: OpenCL 1.2+] See module docs for more info.
2981///
2982// [UNTESTED]
2983//
2984pub fn enqueue_fill_image<T, M, En, Ewl>(
2985            command_queue: &CommandQueue,
2986            image: M,
2987            color: &[T],
2988            origin: [usize; 3],
2989            region: [usize; 3],
2990            wait_list: Option<Ewl>,
2991            new_event: Option<En>,
2992            device_version: Option<&OpenclVersion>
2993        ) -> OclCoreResult<()>
2994        where T: OclPrm, En: ClNullEventPtr, Ewl: ClWaitListPtr, M: AsMem<T> + MemCmdAll
2995{
2996    // Verify device version:
2997    verify_device_version(device_version, [1, 2], command_queue,
2998        ApiFunction::EnqueueFillImage)?;
2999
3000    let (wait_list_len, wait_list_ptr, new_event_ptr)
3001        = resolve_event_ptrs(wait_list, new_event);
3002
3003    let errcode = unsafe { ffi::clEnqueueFillImage(
3004        command_queue.as_ptr(),
3005        image.as_mem().as_ptr(),
3006        color as *const _ as *const c_void,
3007        &origin as *const _ as *const usize,
3008        &region as *const _ as *const usize,
3009        wait_list_len,
3010        wait_list_ptr,
3011        new_event_ptr,
3012    ) };
3013    eval_errcode(errcode, (), "clEnqueueFillImage", None::<String>)
3014}
3015
3016
3017/// Enqueues a command to copy image objects.
3018///
3019/// [SDK Docs](https://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clEnqueueCopyImage.html)
3020pub fn enqueue_copy_image<En, Ewl>(
3021            command_queue: &CommandQueue,
3022            src_image: &Mem,
3023            dst_image: &Mem,
3024            src_origin: [usize; 3],
3025            dst_origin: [usize; 3],
3026            region: [usize; 3],
3027            wait_list: Option<Ewl>,
3028            new_event: Option<En>,
3029        ) -> OclCoreResult<()>
3030        where En: ClNullEventPtr, Ewl: ClWaitListPtr
3031{
3032    let (wait_list_len, wait_list_ptr, new_event_ptr)
3033        = resolve_event_ptrs(wait_list, new_event);
3034
3035    let errcode = unsafe { ffi::clEnqueueCopyImage(
3036        command_queue.as_ptr(),
3037        src_image.as_ptr(),
3038        dst_image.as_ptr(),
3039        &src_origin as *const _ as *const usize,
3040        &dst_origin as *const _ as *const usize,
3041        &region as *const _ as *const usize,
3042        wait_list_len,
3043        wait_list_ptr,
3044        new_event_ptr,
3045    ) };
3046    eval_errcode(errcode, (), "clEnqueueCopyImage", None::<String>)
3047}
3048
3049/// Enqueues a command to copy an image object to a buffer object.
3050///
3051/// [SDK Docs](https://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clEnqueueCopyImageToBuffer.html)
3052///
3053// [UNTESTED]
3054//
3055pub fn enqueue_copy_image_to_buffer<T, M, En, Ewl>(
3056            command_queue: &CommandQueue,
3057            src_image: M,
3058            dst_buffer: M,
3059            src_origin: [usize; 3],
3060            region: [usize; 3],
3061            dst_offset: usize,
3062            wait_list: Option<Ewl>,
3063            new_event: Option<En>,
3064        ) -> OclCoreResult<()>
3065        where T: OclPrm, En: ClNullEventPtr, Ewl: ClWaitListPtr, M: AsMem<T> + MemCmdAll
3066{
3067    let dst_offset_bytes = dst_offset * mem::size_of::<T>();
3068
3069    let (wait_list_len, wait_list_ptr, new_event_ptr)
3070        = resolve_event_ptrs(wait_list, new_event);
3071
3072    let errcode = unsafe { ffi::clEnqueueCopyImageToBuffer(
3073        command_queue.as_ptr(),
3074        src_image.as_mem().as_ptr(),
3075        dst_buffer.as_mem().as_ptr(),
3076        &src_origin as *const _ as *const usize,
3077        &region as *const _ as *const usize,
3078        dst_offset_bytes,
3079        wait_list_len,
3080        wait_list_ptr,
3081        new_event_ptr,
3082    ) };
3083    eval_errcode(errcode, (), "clEnqueueCopyImageToBuffer", None::<String>)
3084}
3085
3086/// Enqueues a command to copy a buffer object to an image object.
3087///
3088/// [SDK Docs](https://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clEnqueueCopyBufferToImage.html)
3089///
3090// [UNTESTED]
3091//
3092pub fn enqueue_copy_buffer_to_image<T, M, En, Ewl>(
3093            command_queue: &CommandQueue,
3094            src_buffer: M,
3095            dst_image: M,
3096            src_offset: usize,
3097            dst_origin: [usize; 3],
3098            region: [usize; 3],
3099            wait_list: Option<Ewl>,
3100            new_event: Option<En>,
3101        ) -> OclCoreResult<()>
3102        where T: OclPrm, En: ClNullEventPtr, Ewl: ClWaitListPtr, M: AsMem<T> + MemCmdAll
3103{
3104    let src_offset_bytes = src_offset * mem::size_of::<T>();
3105
3106    let (wait_list_len, wait_list_ptr, new_event_ptr)
3107        = resolve_event_ptrs(wait_list, new_event);
3108
3109    let errcode = unsafe { ffi::clEnqueueCopyBufferToImage(
3110        command_queue.as_ptr(),
3111        src_buffer.as_mem().as_ptr(),
3112        dst_image.as_mem().as_ptr(),
3113        src_offset_bytes,
3114        &dst_origin as *const _ as *const usize,
3115        &region as *const _ as *const usize,
3116        wait_list_len,
3117        wait_list_ptr,
3118        new_event_ptr,
3119    ) };
3120    eval_errcode(errcode, (), "clEnqueueCopyBufferToImage", None::<String>)
3121}
3122
3123#[inline]
3124unsafe fn _enqueue_map_buffer<T, M>(
3125        command_queue: &CommandQueue,
3126        buffer: M,
3127        block: bool,
3128        map_flags: MapFlags,
3129        offset: usize,
3130        len: usize,
3131        wait_list_len: cl_uint,
3132        wait_list_ptr: *const cl_event,
3133        new_event_ptr: *mut cl_event,
3134        ) -> OclCoreResult<*mut T>
3135        where T: OclPrm, M: AsMem<T> + MemCmdAll
3136{
3137    let offset_bytes = offset * mem::size_of::<T>();
3138    let size_bytes = len * mem::size_of::<T>();
3139
3140    let mut errcode = 0i32;
3141
3142    let mapped_ptr = ffi::clEnqueueMapBuffer(
3143        command_queue.as_ptr(),
3144        buffer.as_mem().as_ptr(),
3145        block as cl_uint,
3146        map_flags.bits(),
3147        offset_bytes,
3148        size_bytes,
3149        wait_list_len,
3150        wait_list_ptr,
3151        new_event_ptr,
3152        &mut errcode,
3153    );
3154
3155    eval_errcode(errcode, mapped_ptr as *mut T, "clEnqueueMapBuffer", None::<String>)
3156}
3157
3158/// Enqueues a command to map a region of the buffer object given
3159/// by `buffer` into the host address space and returns a pointer to this
3160/// mapped region.
3161///
3162/// [SDK Docs](https://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clEnqueueMapBuffer.html)
3163///
3164/// ## Safety
3165///
3166/// Caller must ensure that the returned pointer is not used until the map is
3167/// complete. Use `new_event` to monitor it. It also must be ensured that
3168/// memory referred to by the returned pointer is not dropped, reused, or
3169/// otherwise interfered with until `enqueue_unmap_mem_object` is called.
3170///
3171///
3172/// [`EventList::get_clone`]: struct.EventList.html#method.last_clone
3173///
3174pub unsafe fn enqueue_map_buffer<T, M, En, Ewl>(
3175            command_queue: &CommandQueue,
3176            buffer: M,
3177            block: bool,
3178            map_flags: MapFlags,
3179            offset: usize,
3180            len: usize,
3181            wait_list: Option<Ewl>,
3182            new_event: Option<En>,
3183        ) -> OclCoreResult<MemMap<T>>
3184        where T: OclPrm, En: ClNullEventPtr, Ewl: ClWaitListPtr, M: AsMem<T> + MemCmdAll
3185{
3186    let (wait_list_len, wait_list_ptr, new_event_ptr) =
3187        resolve_event_ptrs(wait_list, new_event);
3188
3189    let mapped_ptr_res = _enqueue_map_buffer(command_queue, buffer.as_mem(), block, map_flags, offset, len,
3190        wait_list_len, wait_list_ptr, new_event_ptr);
3191
3192    mapped_ptr_res.map(|ptr| MemMap::from_raw(ptr))
3193}
3194
3195/// Enqueues a command to map a region of the image object given by `image` into
3196/// the host address space and returns a pointer to this mapped region.
3197///
3198/// [SDK Docs](https://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clEnqueueMapBuffer.html)
3199///
3200/// ## Safety
3201///
3202/// Caller must ensure that the returned pointer is not used until the map is
3203/// complete. Use `new_event` to monitor it. It also must be ensured that
3204/// memory referred to by the returned pointer is not dropped, reused, or
3205/// otherwise interfered with until `enqueue_unmap_mem_object` is called.
3206///
3207///
3208/// [`EventList::get_clone`]: struct.EventList.html#method.last_clone
3209///
3210///
3211///
3212// [UNTESTED]
3213//
3214pub unsafe fn enqueue_map_image<T, M, En, Ewl>(
3215            command_queue: &CommandQueue,
3216            image: M,
3217            block: bool,
3218            map_flags: MapFlags,
3219            origin: [usize; 3],
3220            region: [usize; 3],
3221            row_pitch_bytes: &mut usize,
3222            slc_pitch_bytes: &mut usize,
3223            wait_list: Option<Ewl>,
3224            new_event: Option<En>,
3225        ) -> OclCoreResult<MemMap<T>>
3226        where T: OclPrm, En: ClNullEventPtr, Ewl: ClWaitListPtr, M: AsMem<T> + MemCmdAll
3227{
3228    let (wait_list_len, wait_list_ptr, new_event_ptr) =
3229        resolve_event_ptrs(wait_list, new_event);
3230
3231    let mut errcode = 0i32;
3232
3233    let mapped_ptr = ffi::clEnqueueMapImage(
3234        command_queue.as_ptr(),
3235        image.as_mem().as_ptr(),
3236        block as cl_uint,
3237        map_flags.bits(),
3238        &origin as *const _ as *const usize,
3239        &region as *const _ as *const usize,
3240        row_pitch_bytes,
3241        slc_pitch_bytes,
3242        wait_list_len,
3243        wait_list_ptr,
3244        new_event_ptr,
3245        &mut errcode,
3246    );
3247
3248    // let map_event_core = if !new_event_ptr.is_null() {
3249    //     *new_event_ptr = map_event;
3250    //     Event::from_raw_copied_ptr(map_event)?
3251    // } else {
3252    //     Event::from_raw_create_ptr(map_event)
3253    // };
3254
3255    // eval_errcode(errcode, MemMap::new(mapped_ptr as *mut T, slc_pitch * region[2],
3256    //     None, image.as_mem().clone(), command_queue.clone()), "clEnqueueMapImage", None::<String>)
3257
3258    eval_errcode(errcode, mapped_ptr, "clEnqueueMapImage", None::<String>)
3259        .map(|ptr| MemMap::from_raw(ptr as *mut _ as *mut T))
3260}
3261
3262/// Enqueues a command to unmap a previously mapped region of a memory object.
3263///
3264/// [SDK Docs](https://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clEnqueueUnmapMemObject.html)
3265///
3266pub fn enqueue_unmap_mem_object<T, M, En, Ewl>(
3267            command_queue: &CommandQueue,
3268            memobj: M,
3269            mapped_mem: &MemMap<T>,
3270            wait_list: Option<Ewl>,
3271            new_event: Option<En>,
3272        ) -> OclCoreResult<()>
3273        where T: OclPrm, En: ClNullEventPtr, Ewl: ClWaitListPtr, M: AsMem<T> + MemCmdAll
3274{
3275    let (wait_list_len, wait_list_ptr, new_event_ptr) =
3276        resolve_event_ptrs(wait_list, new_event);
3277
3278    let errcode = unsafe { ffi::clEnqueueUnmapMemObject(
3279        command_queue.as_ptr(),
3280        memobj.as_mem().as_ptr(),
3281        mapped_mem.as_void_ptr(),
3282        wait_list_len,
3283        wait_list_ptr,
3284        new_event_ptr,
3285    ) };
3286
3287    eval_errcode(errcode, (), "clEnqueueUnmapMemObject", None::<String>)
3288}
3289
3290/// Enqueues a command to indicate which device a set of memory objects should
3291/// be associated with.
3292///
3293/// [SDK Docs](https://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clEnqueueMigrateMemObjects.html)
3294///
3295/// [Version Controlled: OpenCL 1.2+] See module docs for more info.
3296///
3297// [UNTESTED]
3298//
3299pub fn enqueue_migrate_mem_objects<En: ClNullEventPtr, Ewl: ClWaitListPtr>(
3300            command_queue: &CommandQueue,
3301            mem_objects: &[Mem],
3302            flags: MemMigrationFlags,
3303            wait_list: Option<Ewl>,
3304            new_event: Option<En>,
3305            device_version: Option<&OpenclVersion>
3306        ) -> OclCoreResult<()>
3307{
3308    // Verify device version:
3309    verify_device_version(device_version, [1, 2], command_queue,
3310        ApiFunction::EnqueueMigrateMemObjects)?;
3311
3312    let (wait_list_len, wait_list_ptr, new_event_ptr)
3313        = resolve_event_ptrs(wait_list, new_event);
3314
3315    let errcode = unsafe { ffi::clEnqueueMigrateMemObjects(
3316        command_queue.as_ptr(),
3317        mem_objects.len() as u32,
3318        mem_objects.as_ptr() as *const _ as *const cl_mem,
3319        flags.bits(),
3320        wait_list_len,
3321        wait_list_ptr,
3322        new_event_ptr,
3323    ) };
3324    eval_errcode(errcode, (), "clEnqueueMigrateMemObjects", None::<String>)
3325}
3326
3327/// Enqueues a command to execute a kernel on a device.
3328///
3329/// ## Safety
3330///
3331/// Running any kernel is an inherently unsafe process. The API call itself is
3332/// safe but the kernel execution is not.
3333///
3334/// ## Stability
3335///
3336/// * Work dimension/offset sizes *may* eventually be wrapped up in
3337///   specialized types.
3338///
3339/// [SDK Docs](https://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clEnqueueNDRangeKernel.html)
3340pub unsafe fn enqueue_kernel<En: ClNullEventPtr, Ewl: ClWaitListPtr> (
3341            command_queue: &CommandQueue,
3342            kernel: &Kernel,
3343            work_dims: u32,
3344            global_work_offset: Option<[usize; 3]>,
3345            global_work_dims: &[usize; 3],
3346            local_work_dims: Option<[usize; 3]>,
3347            wait_list: Option<Ewl>,
3348            new_event: Option<En>,
3349        ) -> OclCoreResult<()>
3350{
3351    #[cfg(feature="kernel_debug_sleep")]
3352    #[allow(unused_imports)] use std::thread;
3353    #[cfg(feature="kernel_debug_sleep")]
3354    #[allow(unused_imports)] use std::time::Duration;
3355
3356    #[cfg(feature="kernel_debug_print")]
3357    println!("Resolving events: wait_list: {:?}, new_event: {:?}", wait_list, new_event);
3358
3359    let (wait_list_len, wait_list_ptr, new_event_ptr) =
3360        resolve_event_ptrs(wait_list, new_event);
3361
3362    #[cfg(feature="kernel_debug_print")]
3363    println!("Resolving global work offset: {:?}...", global_work_offset);
3364
3365    let gwo = resolve_work_dims(global_work_offset.as_ref());
3366
3367    #[cfg(feature="kernel_debug_print")]
3368    println!("Assigning global work size: {:?}...", global_work_dims);
3369
3370    let gws = global_work_dims as *const size_t;
3371
3372    #[cfg(feature="kernel_debug_print")]
3373    println!("Resolving local work size: {:?}...", local_work_dims);
3374
3375    let lws = resolve_work_dims(local_work_dims.as_ref());
3376
3377    #[cfg(feature="kernel_debug_print")]
3378    println!("Preparing to print all details...");
3379
3380    #[cfg(feature="kernel_debug_print")]
3381    print!("core::enqueue_kernel('{}': \
3382        work_dims: {}, \
3383        gwo: {:?}, \
3384        gws: {:?}, \
3385        lws: {:?}, \
3386        wait_list_len: {}, \
3387        wait_list_ptr: {:?}, \
3388        new_event_ptr: {:?}) \
3389        ",
3390        get_kernel_name(&kernel),
3391        work_dims,
3392        global_work_offset,
3393        global_work_dims,
3394        local_work_dims,
3395        wait_list_len,
3396        wait_list_ptr,
3397        new_event_ptr,
3398    );
3399
3400    let errcode = ffi::clEnqueueNDRangeKernel(
3401        command_queue.as_ptr(),
3402        kernel.as_ptr() as cl_kernel,
3403        work_dims,
3404        gwo,
3405        gws,
3406        lws,
3407        wait_list_len,
3408        wait_list_ptr,
3409        new_event_ptr,
3410    );
3411
3412    if cfg!(feature="kernel_debug_print") { println!("-> Status: {}.", errcode); }
3413    if cfg!(feature="kernel_debug_sleep") {
3414        thread::sleep(Duration::from_millis(KERNEL_DEBUG_SLEEP_DURATION_MS));
3415    }
3416
3417    if errcode != 0 {
3418        let name = get_kernel_name(kernel)?;
3419        eval_errcode(errcode, (), "clEnqueueNDRangeKernel", Some(name))
3420    } else {
3421        Ok(())
3422    }
3423}
3424
3425/// Enqueues a command to execute a kernel on a device.
3426///
3427/// The kernel is executed using a single work-item.
3428///
3429/// From [SDK]: clEnqueueTask is equivalent to calling clEnqueueNDRangeKernel
3430/// with work_dim = 1, global_work_offset = NULL, global_work_size[0] set to 1,
3431/// and local_work_size[0] set to 1.
3432///
3433/// ## Safety
3434///
3435/// Running any kernel is an inherently unsafe process. The API call itself is
3436/// safe but the kernel execution is not.
3437///
3438///
3439/// [SDK]: https://www.khronos.org/registry/cl/sdk/1.0/docs/man/xhtml/clEnqueueTask.html
3440///
3441// [UNTESTED]
3442//
3443pub unsafe fn enqueue_task<En: ClNullEventPtr, Ewl: ClWaitListPtr>(
3444            command_queue: &CommandQueue,
3445            kernel: &Kernel,
3446            wait_list: Option<Ewl>,
3447            new_event: Option<En>,
3448            kernel_name: Option<&str>
3449        ) -> OclCoreResult<()>
3450{
3451    let (wait_list_len, wait_list_ptr, new_event_ptr) =
3452        resolve_event_ptrs(wait_list, new_event);
3453
3454    let errcode = ffi::clEnqueueTask(
3455        command_queue.as_ptr(),
3456        kernel.as_ptr() as cl_kernel,
3457        wait_list_len,
3458        wait_list_ptr,
3459        new_event_ptr,
3460    );
3461    eval_errcode(errcode, (), "clEnqueueTask", kernel_name)
3462}
3463
3464/// [UNIMPLEMENTED: Please implement me]
3465pub fn enqueue_native_kernel() -> OclCoreResult<()> {
3466    // ffi::clEnqueueNativeKernel(command_queue: cl_command_queue,
3467    //                          user_func: extern fn (*mut c_void),
3468    //                          args: *mut c_void,
3469    //                          cb_args: size_t,
3470    //                          num_mem_objects: cl_uint,
3471    //                          mem_list: *const cl_mem,
3472    //                          args_mem_loc: *const *const c_void,
3473    //                          num_events_in_wait_list: cl_uint,
3474    //                          event_wait_list: *const cl_event,
3475    //                          event: *mut cl_event) -> cl_int;
3476    unimplemented!();
3477}
3478
3479/// Enqueues a marker command which waits for either a list of events to
3480/// complete, or all previously enqueued commands to complete.
3481///
3482/// [SDK Docs](https://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clEnqueueMarkerWithWaitList.html)
3483///
3484/// [Version Controlled: OpenCL 1.2+] See module docs for more info.
3485pub fn enqueue_marker_with_wait_list<En, Ewl>(
3486            command_queue: &CommandQueue,
3487            wait_list: Option<Ewl>,
3488            new_event: Option<En>,
3489            device_version: Option<&OpenclVersion>
3490        ) -> OclCoreResult<()>
3491        where En: ClNullEventPtr, Ewl: ClWaitListPtr
3492{
3493    // Verify device version:
3494    verify_device_version(device_version, [1, 2], command_queue,
3495        ApiFunction::EnqueueMarkerWithWaitList)?;
3496
3497    let (wait_list_len, wait_list_ptr, new_event_ptr) =
3498        resolve_event_ptrs(wait_list, new_event);
3499
3500    let errcode = unsafe { ffi::clEnqueueMarkerWithWaitList(
3501        command_queue.as_ptr(),
3502        wait_list_len,
3503        wait_list_ptr,
3504        new_event_ptr,
3505    ) };
3506    eval_errcode(errcode, (), "clEnqueueMarkerWithWaitList", None::<String>)
3507}
3508
3509/// A synchronization point that enqueues a barrier operation.
3510///
3511/// [SDK Docs](https://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clEnqueueBarrierWithWaitList.html)
3512///
3513/// [Version Controlled: OpenCL 1.2+] See module docs for more info.
3514pub fn enqueue_barrier_with_wait_list<En, Ewl>(
3515            command_queue: &CommandQueue,
3516            wait_list: Option<Ewl>,
3517            new_event: Option<En>,
3518            device_version: Option<&OpenclVersion>
3519        ) -> OclCoreResult<()>
3520        where En: ClNullEventPtr, Ewl: ClWaitListPtr
3521{
3522    // Verify device version:
3523    verify_device_version(device_version, [1, 2], command_queue,
3524        ApiFunction::EnqueueBarrierWithWaitList)?;
3525
3526    let (wait_list_len, wait_list_ptr, new_event_ptr) =
3527        resolve_event_ptrs(wait_list, new_event);
3528
3529    let errcode = unsafe { ffi::clEnqueueBarrierWithWaitList(
3530        command_queue.as_ptr(),
3531        wait_list_len,
3532        wait_list_ptr,
3533        new_event_ptr,
3534    ) };
3535    eval_errcode(errcode, (), "clEnqueueBarrierWithWaitList", None::<String>)
3536}
3537
3538
3539
3540// Extension function access
3541//
3542// Returns the extension function address for the given function name,
3543// or NULL if a valid function can not be found. The client must
3544// check to make sure the address is not NULL, before using or
3545// or calling the returned function address.
3546//
3547// A non-NULL return value for clGetExtensionFunctionAddressForPlatform does
3548// not guarantee that an extension function is actually supported by the
3549// platform. The application must also make a corresponding query using
3550// clGetPlatformInfo (platform, CL_PLATFORM_EXTENSIONS, ... ) or
3551// clGetDeviceInfo (device,CL_DEVICE_EXTENSIONS, ... ) to determine if an
3552// extension is supported by the OpenCL implementation.
3553//
3554// [FIXME]: Return a generic that implements `Fn` (or `FnMut/Once`?).
3555// TODO: Create another function which will handle the second check described
3556// above in addition to calling this.
3557//
3558// ////////////////////////////////////////////////////////////////////////////
3559/// Returns the address of the extension function named by
3560/// `func_name` for a given platform.
3561///
3562/// The pointer returned should be cast to a function pointer type matching
3563/// the extension function's definition defined in the appropriate extension
3564/// specification and header file.
3565///
3566///
3567/// A non-NULL return value does
3568/// not guarantee that an extension function is actually supported by the
3569/// platform. The application must also make a corresponding query using
3570/// `ocl::core::get_platform_info(platform_core, CL_PLATFORM_EXTENSIONS, ... )` or
3571/// `ocl::core::get_device_info(device_core, CL_DEVICE_EXTENSIONS, ... )`
3572/// to determine if an extension is supported by the OpenCL implementation.
3573///
3574/// [FIXME]: Update enum names above to the wrapped types.
3575///
3576/// ## Errors
3577///
3578/// Returns an error if:
3579///
3580/// - `func_name` cannot be converted to a `CString`.
3581/// - The specified function does not exist for the implementation.
3582/// - 'platform' is not a valid platform.
3583///
3584/// [Version Controlled: OpenCL 1.2+] See module docs for more info.
3585///
3586// [UNTESTED]
3587//
3588pub unsafe fn get_extension_function_address_for_platform(
3589            platform: &PlatformId,
3590            func_name: &str,
3591            platform_version: Option<&OpenclVersion>
3592        ) -> OclCoreResult<*mut c_void>
3593{
3594    // Verify platform version:
3595    verify_platform_version(platform_version, [1, 2], platform,
3596        ApiFunction::GetExtensionFunctionAddressForPlatform)?;
3597
3598    let func_name_c = r#try!(CString::new(func_name));
3599
3600    let ext_fn = ffi::clGetExtensionFunctionAddressForPlatform(
3601        platform.as_ptr(),
3602        func_name_c.as_ptr(),
3603    );
3604
3605    if ext_fn.is_null() {
3606        Err(ApiWrapperError::GetExtensionFunctionAddressForPlatformInvalidFunction.into())
3607    } else {
3608        Ok(ext_fn)
3609    }
3610}
3611
3612//============================================================================
3613//============================================================================
3614//=========================== DERIVED FUNCTIONS ==============================
3615//============================================================================
3616//============================================================================
3617
3618
3619/// Returns a list of versions for devices.
3620pub fn device_versions(device_ids: &[DeviceId]) -> OclCoreResult<Vec<OpenclVersion>> {
3621    let mut d_versions = Vec::with_capacity(device_ids.len());
3622
3623    for device_id in device_ids {
3624        d_versions.push(r#try!(device_id.version()));
3625    }
3626
3627    Ok(d_versions)
3628}
3629
3630/// Returns the default platform if set by an environment variable or config
3631/// file.
3632pub fn default_platform_idx() -> usize {
3633    match env::var("OCL_DEFAULT_PLATFORM_IDX") {
3634        Ok(s) => s.parse::<usize>().unwrap_or(0),
3635        Err(_) => 0,
3636    }
3637}
3638
3639/// Returns the default or first platform.
3640pub fn default_platform() -> OclCoreResult<PlatformId> {
3641    let platform_list = r#try!(get_platform_ids());
3642
3643    if platform_list.is_empty() {
3644        Err(ApiWrapperError::DefaultPlatformNoPlatforms.into())
3645    } else {
3646        let default_platform_idx = default_platform_idx();
3647        if default_platform_idx > platform_list.len() - 1 {
3648            Err(ApiWrapperError::DefaultPlatformEnvVarBadIdx {
3649                    default_platform_idx, max_idx: platform_list.len() - 1}.into())
3650        } else {
3651            Ok(platform_list[default_platform_idx])
3652        }
3653    }
3654}
3655
3656/// Returns the default device type bitflags as specified by environment
3657/// variable or else `DEVICE_TYPE_ALL`.
3658pub fn default_device_type() -> OclCoreResult<DeviceType> {
3659    match env::var("OCL_DEFAULT_DEVICE_TYPE") {
3660        Ok(ref s) => match s.trim() {
3661            "DEFAULT" => Ok(DeviceType::DEFAULT),
3662            "CPU" => Ok(DeviceType::CPU),
3663            "GPU" => Ok(DeviceType::GPU),
3664            "ACCELERATOR" => Ok(DeviceType::ACCELERATOR),
3665            "CUSTOM" => Ok(DeviceType::CUSTOM),
3666            "ALL" => Ok(DeviceType::ALL),
3667            _ => Err(ApiWrapperError::DefaultDeviceTypeInvalidType(s.to_owned()).into()),
3668        },
3669        // `DeviceType::ALL` is used to avoid the potentially confusing
3670        // platform-dependent behavior of `DeviceType::DEFAULT`.
3671        Err(_) => Ok(DeviceType::ALL),
3672    }
3673}
3674
3675/// Returns the name of a kernel.
3676pub fn get_kernel_name(kernel: &Kernel) -> OclCoreResult<String> {
3677    let result = get_kernel_info(kernel, KernelInfo::FunctionName)?;
3678    Ok(result.into())
3679}
3680
3681/// Creates, builds, and returns a new program pointer from `src_strings`.
3682///
3683/// TODO: Break out create and build parts into requisite functions then call
3684/// from here.
3685pub fn create_build_program<C, D>(
3686            context: C,
3687            src_strings: &[CString],
3688            device_ids: Option<&[D]>,
3689            cmplr_opts: &CString,
3690        ) -> OclCoreResult<Program>
3691        where C: ClContextPtr, D: ClDeviceIdPtr + fmt::Debug
3692{
3693    let program = r#try!(create_program_with_source(context, src_strings));
3694    r#try!(build_program(&program, device_ids, cmplr_opts, None, None));
3695    Ok(program)
3696}
3697
3698
3699#[allow(dead_code)]
3700/// Blocks until an event is complete.
3701pub fn wait_for_event<'e, E: ClEventPtrRef<'e>>(event: &'e E) -> OclCoreResult<()> {
3702    let errcode = unsafe {
3703        ffi::clWaitForEvents(1, event.as_ptr_ref())
3704    };
3705    eval_errcode(errcode, (), "clWaitForEvents", None::<String>)
3706}
3707
3708/// Returns the status of `event`.
3709pub fn event_status<'e, E: ClEventPtrRef<'e>>(event: &'e E) -> OclCoreResult<CommandExecutionStatus> {
3710    let mut status_int: cl_int = 0;
3711
3712    let errcode = unsafe {
3713        ffi::clGetEventInfo(
3714            *event.as_ptr_ref(),
3715            ffi::CL_EVENT_COMMAND_EXECUTION_STATUS,
3716            mem::size_of::<cl_int>(),
3717            &mut status_int as *mut _ as *mut c_void,
3718            ptr::null_mut(),
3719        )
3720    };
3721    r#try!(eval_errcode(errcode, (), "clGetEventInfo", None::<String>));
3722
3723    CommandExecutionStatus::from_i32(status_int).ok_or_else(|| OclCoreError::from("Error converting \
3724        'clGetEventInfo' status output."))
3725}
3726
3727/// Returns true if an event is complete, false if not complete.
3728pub fn event_is_complete<'e, E: ClEventPtrRef<'e>>(event: &'e E) -> OclCoreResult<bool> {
3729    let mut status_int: cl_int = 0;
3730
3731    let errcode = unsafe {
3732        ffi::clGetEventInfo(
3733            *event.as_ptr_ref(),
3734            ffi::CL_EVENT_COMMAND_EXECUTION_STATUS,
3735            mem::size_of::<cl_int>(),
3736            &mut status_int as *mut _ as *mut c_void,
3737            ptr::null_mut(),
3738        )
3739    };
3740
3741    #[cfg(feature = "event_debug_print")]
3742    unsafe {
3743        println!("Event Status: {:?} (ptr: {:?})",
3744            CommandExecutionStatus::from_i32(status_int).unwrap(),
3745            *event.as_ptr_ref());
3746    }
3747
3748    eval_errcode(errcode, status_int == CommandExecutionStatus::Complete as i32,
3749        "clEventGetInfo", Some("CL_EVENT_COMMAND_EXECUTION_STATUS"))
3750}
3751
3752
3753
3754/// Verifies that the `context` is in fact a context object pointer.
3755///
3756/// ## Assumptions
3757///
3758/// Some (most?/all?) OpenCL implementations do not correctly error if non-
3759/// context pointers are passed. This function relies on the fact that passing
3760/// the `CL_CONTEXT_DEVICES` as the `param_name` to `clGetContextInfo` will
3761/// (at least on my AMD implementation) often return a huge result size if
3762/// `context` is not actually a `cl_context` pointer due to the fact that it's
3763/// reading from some random memory location on non-context structs. Also
3764/// checks for zero because a context must have at least one device (true?).
3765/// Should probably choose a value lower than 10kB because it seems unlikely
3766/// any result would be that big but w/e.
3767///
3768/// [UPDATE]: This function may no longer be necessary now that the core
3769/// pointers have wrappers but it still prevents a hard to track down bug so
3770/// it will stay intact for now.
3771///
3772#[inline]
3773pub fn verify_context<C>(context: C) -> OclCoreResult<()>
3774        where C: ClContextPtr
3775{
3776    // context_info(context, ffi::CL_CONTEXT_REFERENCE_COUNT)
3777    if cfg!(release) {
3778        Ok(())
3779    } else {
3780        match get_context_info(context, ContextInfo::Devices) {
3781            Err(err) => Err(err),
3782            _ => Ok(()),
3783        }
3784    }
3785}
3786
3787
3788/// Checks to see if a device supports the `CL_GL_SHARING_EXT` extension.
3789fn device_supports_cl_gl_sharing<D: ClDeviceIdPtr>(device: D) -> OclCoreResult<bool> {
3790    match get_device_info(device, DeviceInfo::Extensions) {
3791        Ok(DeviceInfoResult::Extensions(extensions)) => Ok(extensions.contains(CL_GL_SHARING_EXT)),
3792        // Ok(DeviceInfoResult::Error(err)) => Err(*err),
3793        Err(err) => Err(err),
3794        _ => unreachable!(),
3795    }
3796}
3797
3798
3799/// Returns the context for a command queue, bypassing extra processing.
3800pub fn get_command_queue_context_ptr(queue: &CommandQueue) -> OclCoreResult<cl_context> {
3801    let mut result = 0 as cl_context;
3802    let result_size = mem::size_of::<cl_context>();
3803
3804    let errcode = unsafe { ffi::clGetCommandQueueInfo(
3805        queue.as_ptr(),
3806        CommandQueueInfo::Context as cl_command_queue_info,
3807        result_size,
3808        &mut result as *mut _ as *mut c_void,
3809        ptr::null_mut(),
3810    ) };
3811
3812    eval_errcode(errcode, result, "clGetCommandQueueInfo",
3813        Some("functions::get_command_queue_context_ptr"))
3814}
3815
3816
3817//============================================================================
3818//============================================================================
3819//====================== Wow, you made it this far? ==========================
3820//============================================================================
3821//============================================================================