ocl_core/types/
abs.rs

1//! Abstract data type wrappers.
2//!
3//! ### Reference
4//!
5//! The following table describes abstract data types supported by OpenCL
6//! (from [SDK]):
7//!
8//! * cl_platform_id: The ID for a platform.
9//! * cl_device_id: The ID for a device.
10//! * cl_context: A context.
11//! * cl_command_queue: A command queue.
12//! * cl_mem: A memory object.
13//! * cl_program: A program.
14//! * cl_kernel: A kernel.
15//! * cl_event: An event.
16//! * cl_sampler: A sampler.
17//!
18//! The following new derived wrappers are also included in this module:
19//!
20//! * cl_events: A list of events.
21//!
22//!
23//! ### Who cares. Why bother?
24//!
25//! These types ensure as best they can that stored pointers to any of the
26//! above objects will be valid until that pointer is dropped by the Rust
27//! runtime (which obviously is not a 100% guarantee).
28//!
29//! What this means is that you can share, clone, store, and throw away these
30//! types, and any types that contain them, among multiple threads, for as
31//! long as you'd like, with an insignificant amount of overhead, without
32//! having to worry about the dangers of dereferencing those types later on.
33//! As good as the OpenCL library generally is about this, it fails in many
34//! cases to provide complete protection against segfaults due to
35//! dereferencing old pointers particularly on certain *ahem* platforms.
36//!
37//!
38//!
39//! [SDK]: https://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/abstractDataTypes.html
40
41use crate::error::Result as OclCoreResult;
42use crate::ffi::{
43    c_void, cl_command_queue, cl_context, cl_device_id, cl_event, cl_kernel, cl_mem,
44    cl_platform_id, cl_program, cl_sampler,
45};
46use crate::functions::{self, ApiFunction, VersionKind};
47use crate::{
48    CommandExecutionStatus, CommandQueueInfo, CommandQueueInfoResult, ContextInfo,
49    ContextInfoResult, DeviceInfo, DeviceInfoResult, DeviceType, EventCallbackFn, EventInfo,
50    EventInfoResult, KernelInfo, KernelInfoResult, OclPrm, OpenclVersion, PlatformInfo,
51    ProgramInfo, ProgramInfoResult, Status,
52};
53use std::cell::Ref;
54use std::fmt::Debug;
55use std::mem;
56use std::ptr;
57use std::slice;
58
59//=============================================================================
60//================================ CONSTANTS ==================================
61//=============================================================================
62
63// const DEBUG_PRINT: bool = false;
64
65//=============================================================================
66//================================== TRAITS ===================================
67//=============================================================================
68
69/// `AsRef` with a type being carried along for convenience.
70pub trait AsMem<T>
71where
72    T: OclPrm,
73{
74    fn as_mem(&self) -> &Mem;
75}
76
77impl<'a, T, M> AsMem<T> for &'a M
78where
79    T: OclPrm,
80    M: AsMem<T>,
81{
82    fn as_mem(&self) -> &Mem {
83        (**self).as_mem()
84    }
85}
86
87impl<'a, T, M> AsMem<T> for &'a mut M
88where
89    T: OclPrm,
90    M: AsMem<T>,
91{
92    fn as_mem(&self) -> &Mem {
93        (**self).as_mem()
94    }
95}
96
97// /// Types which can be represented by a `Mem` reference.
98// pub trait AsMem {
99//     fn as_mem(&self) -> &Mem;
100// }
101
102// impl<'a, M> AsMem for &'a M where M: AsMem {
103//     fn as_mem(&self) -> &Mem {
104//         (**self).as_mem()
105//     }
106// }
107
108// impl<'a, M> AsMem for &'a mut M where M: AsMem {
109//     fn as_mem(&self) -> &Mem {
110//         (**self).as_mem()
111//     }
112// }
113
114/// Types which can be passed as the primary (`ptr`) argument value to
115/// `::enqueue_read_buffer`, `::enqueue_write_buffer`,
116/// `::enqueue_read_buffer_rect`, `::enqueue_write_buffer_rect`,
117/// `::enqueue_read_image`, or `::enqueue_write_image`.
118///
119/// These may be device or host side memory buffers.
120///
121/// Types returned from `::enqueue_map_...` and all of their derivatives as
122/// well as types created with `::create_buffer` and `::create_image` all
123/// implement this trait.
124///
125pub unsafe trait MemCmdRw {}
126
127/// Types which can be passed to any and all `::enqueue_...` functions as the
128/// primary (`ptr`) argument and can also be passed as kernel `cl_mem` arguments.
129///
130/// These are strictly device side memory buffers.
131///
132/// Types created with `::create_buffer` and `::create_image` implement this
133/// trait.
134pub unsafe trait MemCmdAll {}
135
136/// Types with a fixed set of associated devices and an associated platform.
137pub trait ClVersions {
138    fn device_versions(&self) -> OclCoreResult<Vec<OpenclVersion>>;
139    fn platform_version(&self) -> OclCoreResult<OpenclVersion>;
140
141    fn verify_device_versions(&self, required_version: [u16; 2]) -> OclCoreResult<()> {
142        functions::verify_versions(
143            &self.device_versions()?,
144            required_version,
145            ApiFunction::None,
146            VersionKind::Device,
147        )
148    }
149
150    fn verify_platform_version(&self, required_version: [u16; 2]) -> OclCoreResult<()> {
151        let ver = [self.platform_version()?];
152        functions::verify_versions(
153            &ver,
154            required_version,
155            ApiFunction::None,
156            VersionKind::Platform,
157        )
158    }
159}
160
161impl ClVersions for cl_context {
162    fn device_versions(&self) -> OclCoreResult<Vec<OpenclVersion>> {
163        let devices = match functions::get_context_info(self, ContextInfo::Devices) {
164            Ok(ContextInfoResult::Devices(ds)) => Ok(ds),
165            Err(err) => Err(err),
166            _ => unreachable!(),
167        };
168
169        let devices = match devices {
170            Ok(d) => d,
171            Err(e) => return Err(e),
172        };
173
174        functions::device_versions(&devices)
175    }
176
177    fn platform_version(&self) -> OclCoreResult<OpenclVersion> {
178        let devices = match functions::get_context_info(self, ContextInfo::Devices) {
179            Ok(ContextInfoResult::Devices(ds)) => Ok(ds),
180            Err(err) => Err(err),
181            _ => unreachable!(),
182        };
183
184        let devices = match devices {
185            Ok(d) => d,
186            Err(e) => return Err(e),
187        };
188
189        devices[0].platform_version()
190    }
191}
192
193/// Types with a reference to a raw event pointer.
194pub unsafe trait ClEventPtrRef<'e> {
195    unsafe fn as_ptr_ref(&'e self) -> &'e cl_event;
196}
197
198unsafe impl<'e> ClEventPtrRef<'e> for &'e cl_event {
199    unsafe fn as_ptr_ref(&'e self) -> &'e cl_event {
200        self
201    }
202}
203
204unsafe impl<'e, L> ClEventPtrRef<'e> for &'e L
205where
206    L: ClEventPtrRef<'e>,
207{
208    unsafe fn as_ptr_ref(&'e self) -> &'e cl_event {
209        (*self).as_ptr_ref()
210    }
211}
212
213/// Types with a mutable pointer to a new, null raw event pointer.
214///
215pub unsafe trait ClNullEventPtr: Debug {
216    fn alloc_new(&mut self) -> *mut cl_event;
217    unsafe fn clone_from<E: AsRef<Event>>(&mut self, ev: E);
218}
219
220unsafe impl ClNullEventPtr for () {
221    fn alloc_new(&mut self) -> *mut cl_event {
222        panic!("Void events may not be used.");
223    }
224
225    unsafe fn clone_from<E: AsRef<Event>>(&mut self, _: E) {
226        panic!("Void events may not be used.");
227    }
228}
229
230/// Types with a reference to a raw event array and an associated element
231/// count.
232///
233/// [TODO]: Create an enum to be used with this trait.
234///
235pub unsafe trait ClWaitListPtr: Debug {
236    /// Returns a pointer to the first pointer in this list.
237    unsafe fn as_ptr_ptr(&self) -> *const cl_event;
238    /// Returns the number of items in this wait list.
239    fn count(&self) -> u32;
240}
241
242unsafe impl<'a, W> ClWaitListPtr for Ref<'a, W>
243where
244    W: ClWaitListPtr,
245{
246    unsafe fn as_ptr_ptr(&self) -> *const cl_event {
247        (*(*self)).as_ptr_ptr()
248    }
249
250    fn count(&self) -> u32 {
251        0 as u32
252    }
253}
254
255unsafe impl<'a> ClWaitListPtr for &'a [cl_event] {
256    unsafe fn as_ptr_ptr(&self) -> *const cl_event {
257        self.as_ptr()
258    }
259
260    fn count(&self) -> u32 {
261        self.len() as u32
262    }
263}
264
265unsafe impl<'a> ClWaitListPtr for &'a [Event] {
266    unsafe fn as_ptr_ptr(&self) -> *const cl_event {
267        self.as_ptr() as *const _ as *const cl_event
268    }
269
270    fn count(&self) -> u32 {
271        self.len() as u32
272    }
273}
274
275unsafe impl<'a> ClWaitListPtr for () {
276    unsafe fn as_ptr_ptr(&self) -> *const cl_event {
277        ptr::null() as *const _ as *const cl_event
278    }
279
280    fn count(&self) -> u32 {
281        0 as u32
282    }
283}
284
285/// Types with a reference to a raw platform_id pointer.
286// pub unsafe trait ClPlatformIdPtr: Sized + Debug {
287pub unsafe trait ClPlatformIdPtr: Debug + Copy {
288    fn as_ptr(&self) -> cl_platform_id;
289}
290
291unsafe impl<'a, P> ClPlatformIdPtr for &'a P
292where
293    P: ClPlatformIdPtr,
294{
295    fn as_ptr(&self) -> cl_platform_id {
296        (*self).as_ptr()
297    }
298}
299
300unsafe impl ClPlatformIdPtr for () {
301    fn as_ptr(&self) -> cl_platform_id {
302        ptr::null_mut() as *mut _ as cl_platform_id
303    }
304}
305
306/// Types with a reference to a raw device_id pointer.
307// pub unsafe trait ClDeviceIdPtr: Sized + Debug {
308pub unsafe trait ClDeviceIdPtr: Debug + Copy {
309    fn as_ptr(&self) -> cl_device_id;
310}
311
312unsafe impl ClDeviceIdPtr for () {
313    fn as_ptr(&self) -> cl_device_id {
314        ptr::null_mut() as *mut _ as cl_device_id
315    }
316}
317
318/// Types with a copy of a context pointer.
319pub unsafe trait ClContextPtr: Debug + Copy {
320    fn as_ptr(&self) -> cl_context;
321}
322
323unsafe impl ClContextPtr for cl_context {
324    fn as_ptr(&self) -> cl_context {
325        *self
326    }
327}
328
329unsafe impl<'a> ClContextPtr for &'a cl_context {
330    fn as_ptr(&self) -> cl_context {
331        **self
332    }
333}
334
335//=============================================================================
336//=================================== TYPES ===================================
337//=============================================================================
338
339/// Wrapper used by `EventList` to send event pointers to core functions
340/// cheaply.
341#[repr(C)]
342pub struct EventRefWrapper(cl_event);
343
344impl EventRefWrapper {
345    pub unsafe fn new(ptr: cl_event) -> EventRefWrapper {
346        EventRefWrapper(ptr)
347    }
348}
349
350unsafe impl<'e> ClEventPtrRef<'e> for EventRefWrapper {
351    unsafe fn as_ptr_ref(&'e self) -> &'e cl_event {
352        &self.0
353    }
354}
355
356/// cl_platform_id
357#[repr(C)]
358#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
359pub struct PlatformId(cl_platform_id);
360
361impl PlatformId {
362    /// Creates a new `PlatformId` wrapper from a raw pointer.
363    pub unsafe fn from_raw(ptr: cl_platform_id) -> PlatformId {
364        // assert!(!ptr.is_null(), "Null pointer passed.");
365        PlatformId(ptr)
366    }
367
368    /// Returns an invalid `PlatformId` used for initializing data structures
369    /// meant to be filled with valid ones.
370    pub unsafe fn null() -> PlatformId {
371        PlatformId(ptr::null_mut())
372    }
373
374    /// Returns a pointer.
375    pub fn as_ptr(&self) -> cl_platform_id {
376        self.0
377    }
378
379    /// Returns the queried and parsed OpenCL version for this platform.
380    pub fn version(&self) -> OclCoreResult<OpenclVersion> {
381        if !self.0.is_null() {
382            functions::get_platform_info(self, PlatformInfo::Version)?.as_opencl_version()
383        } else {
384            Err("PlatformId::version(): This platform_id is invalid.".into())
385        }
386    }
387}
388
389unsafe impl ClPlatformIdPtr for PlatformId {
390    fn as_ptr(&self) -> cl_platform_id {
391        self.0
392    }
393}
394
395unsafe impl Sync for PlatformId {}
396unsafe impl Send for PlatformId {}
397
398impl ClVersions for PlatformId {
399    fn device_versions(&self) -> OclCoreResult<Vec<OpenclVersion>> {
400        let devices = functions::get_device_ids(self, Some(DeviceType::ALL), None)?;
401        functions::device_versions(&devices)
402    }
403
404    // [FIXME]: TEMPORARY; [UPDATE]: Why is this marked temporary?
405    fn platform_version(&self) -> OclCoreResult<OpenclVersion> {
406        self.version()
407    }
408}
409
410/// cl_device_id
411#[repr(C)]
412#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
413pub struct DeviceId(cl_device_id);
414
415impl DeviceId {
416    /// Creates a new `DeviceId` wrapper from a raw pointer.
417    pub unsafe fn from_raw(ptr: cl_device_id) -> DeviceId {
418        assert!(!ptr.is_null(), "Null pointer passed.");
419        DeviceId(ptr)
420    }
421
422    /// Returns an invalid `DeviceId` used for initializing data structures
423    /// meant to be filled with valid ones.
424    pub unsafe fn null() -> DeviceId {
425        DeviceId(ptr::null_mut())
426    }
427
428    /// Returns a pointer.
429    pub fn as_raw(&self) -> cl_device_id {
430        self.0
431    }
432
433    /// Returns the queried and parsed OpenCL version for this device.
434    pub fn version(&self) -> OclCoreResult<OpenclVersion> {
435        if !self.0.is_null() {
436            functions::get_device_info(self, DeviceInfo::Version)?.as_opencl_version()
437        } else {
438            Err("DeviceId::device_versions(): This device_id is invalid.".into())
439        }
440    }
441}
442
443unsafe impl ClDeviceIdPtr for DeviceId {
444    fn as_ptr(&self) -> cl_device_id {
445        self.0
446    }
447}
448
449unsafe impl<'a> ClDeviceIdPtr for &'a DeviceId {
450    fn as_ptr(&self) -> cl_device_id {
451        self.0
452    }
453}
454
455unsafe impl Sync for DeviceId {}
456unsafe impl Send for DeviceId {}
457
458impl ClVersions for DeviceId {
459    fn device_versions(&self) -> OclCoreResult<Vec<OpenclVersion>> {
460        self.version().map(|dv| vec![dv])
461    }
462
463    fn platform_version(&self) -> OclCoreResult<OpenclVersion> {
464        let platform = match functions::get_device_info(self, DeviceInfo::Platform) {
465            Ok(DeviceInfoResult::Platform(p)) => p,
466            // Ok(DeviceInfoResult::Error(e)) => return Err(*e),
467            Err(err) => return Err(err),
468            _ => unreachable!(),
469        };
470
471        functions::get_platform_info(&platform, PlatformInfo::Version)?.as_opencl_version()
472    }
473}
474
475/// cl_context
476#[repr(C)]
477#[derive(Debug)]
478pub struct Context(cl_context);
479
480impl Context {
481    /// Only call this when passing **the original** newly created pointer
482    /// directly from `clCreate...`. Do not use this to clone or copy.
483    pub unsafe fn from_raw_create_ptr(ptr: cl_context) -> Context {
484        assert!(!ptr.is_null(), "Null pointer passed.");
485        Context(ptr)
486    }
487
488    /// Only call this when passing a copied pointer such as from an
489    /// `clGet*****Info` function.
490    pub unsafe fn from_raw_copied_ptr(ptr: cl_context) -> Context {
491        assert!(!ptr.is_null(), "Null pointer passed.");
492        let copy = Context(ptr);
493        functions::retain_context(&copy).unwrap();
494        copy
495    }
496
497    /// Returns a pointer, do not store it.
498    pub fn as_ptr(&self) -> cl_context {
499        self.0
500    }
501
502    /// Returns the devices associated with this context.
503    pub fn devices(&self) -> OclCoreResult<Vec<DeviceId>> {
504        match functions::get_context_info(self, ContextInfo::Devices) {
505            Ok(ContextInfoResult::Devices(ds)) => Ok(ds),
506            Err(err) => Err(err),
507            _ => unreachable!(),
508        }
509    }
510
511    /// Returns the platform associated with this context, if any.
512    ///
513    /// Errors upon the usual OpenCL errors.
514    ///
515    /// Returns `None` if the context properties do not specify a platform.
516    pub fn platform(&self) -> OclCoreResult<Option<PlatformId>> {
517        functions::get_context_platform(self)
518    }
519}
520
521unsafe impl Sync for Context {}
522unsafe impl Send for Context {}
523
524impl Clone for Context {
525    fn clone(&self) -> Context {
526        unsafe {
527            functions::retain_context(self).unwrap();
528        }
529        Context(self.0)
530    }
531}
532
533impl Drop for Context {
534    /// Panics in the event of an error of type `Error::Status` except when
535    /// the status code is `CL_INVALID_CONTEXT` (which is ignored).
536    ///
537    /// This is done because certain platforms error with `CL_INVALID_CONTEXT`
538    /// for unknown reasons and as far as we know can be safely ignored.
539    ///
540    fn drop(&mut self) {
541        unsafe {
542            if let Err(e) = functions::release_context(self as &Context) {
543                if let Some(Status::CL_INVALID_CONTEXT) = e.api_status() {
544                    return;
545                }
546                panic!("{:?}", e);
547            }
548        }
549    }
550}
551
552impl PartialEq<Context> for Context {
553    fn eq(&self, other: &Context) -> bool {
554        self.0 == other.0
555    }
556}
557
558unsafe impl<'a> ClContextPtr for &'a Context {
559    fn as_ptr(&self) -> cl_context {
560        self.0
561    }
562}
563
564impl ClVersions for Context {
565    fn device_versions(&self) -> OclCoreResult<Vec<OpenclVersion>> {
566        let devices = self.devices()?;
567        functions::device_versions(&devices)
568    }
569
570    fn platform_version(&self) -> OclCoreResult<OpenclVersion> {
571        let devices = self.devices()?;
572        devices[0].platform_version()
573    }
574}
575
576impl<'a> ClVersions for &'a Context {
577    fn device_versions(&self) -> OclCoreResult<Vec<OpenclVersion>> {
578        (*self).device_versions()
579    }
580
581    fn platform_version(&self) -> OclCoreResult<OpenclVersion> {
582        (*self).platform_version()
583    }
584}
585
586/// cl_command_queue
587#[repr(C)]
588#[derive(Debug)]
589pub struct CommandQueue(cl_command_queue);
590
591impl CommandQueue {
592    /// Only call this when passing **the original** newly created pointer
593    /// directly from `clCreate...`. Do not use this to clone or copy.
594    pub unsafe fn from_raw_create_ptr(ptr: cl_command_queue) -> CommandQueue {
595        assert!(!ptr.is_null(), "Null pointer passed.");
596        CommandQueue(ptr)
597    }
598
599    /// Only call this when passing a copied pointer such as from an
600    /// `clGet*****Info` function.
601    pub unsafe fn from_raw_copied_ptr(ptr: cl_command_queue) -> CommandQueue {
602        assert!(!ptr.is_null(), "Null pointer passed.");
603        let copy = CommandQueue(ptr);
604        functions::retain_command_queue(&copy).unwrap();
605        copy
606    }
607
608    /// Returns a pointer, do not store it.
609    pub fn as_ptr(&self) -> cl_command_queue {
610        self.0
611    }
612
613    /// Returns the `DeviceId` associated with this command queue.
614    pub fn device(&self) -> OclCoreResult<DeviceId> {
615        match functions::get_command_queue_info(self, CommandQueueInfo::Device) {
616            Ok(CommandQueueInfoResult::Device(d)) => Ok(d),
617            Err(err) => Err(err),
618            _ => unreachable!(),
619        }
620    }
621
622    /// Returns the `Context` associated with this command queue.
623    pub fn context(&self) -> OclCoreResult<Context> {
624        self.context_ptr()
625            .map(|ptr| unsafe { Context::from_raw_copied_ptr(ptr) })
626    }
627
628    /// Returns the `cl_context` associated with this command queue.
629    pub fn context_ptr(&self) -> OclCoreResult<cl_context> {
630        functions::get_command_queue_context_ptr(self)
631    }
632}
633
634impl Clone for CommandQueue {
635    fn clone(&self) -> CommandQueue {
636        unsafe {
637            functions::retain_command_queue(self).unwrap();
638        }
639        CommandQueue(self.0)
640    }
641}
642
643impl Drop for CommandQueue {
644    fn drop(&mut self) {
645        unsafe {
646            functions::release_command_queue(self).unwrap();
647        }
648    }
649}
650
651impl AsRef<CommandQueue> for CommandQueue {
652    fn as_ref(&self) -> &CommandQueue {
653        self
654    }
655}
656
657unsafe impl<'a> ClContextPtr for &'a CommandQueue {
658    fn as_ptr(&self) -> cl_context {
659        self.context_ptr().expect(
660            "<&CommandQueue as ClContextPtr>::as_ptr: \
661            Unable to obtain a context pointer.",
662        )
663    }
664}
665
666unsafe impl Sync for CommandQueue {}
667unsafe impl Send for CommandQueue {}
668
669impl ClVersions for CommandQueue {
670    fn device_versions(&self) -> OclCoreResult<Vec<OpenclVersion>> {
671        let device = self.device()?;
672        device.version().map(|dv| vec![dv])
673    }
674
675    fn platform_version(&self) -> OclCoreResult<OpenclVersion> {
676        self.device()?.platform_version()
677    }
678}
679
680/// cl_mem
681#[repr(C)]
682#[derive(Debug)]
683pub struct Mem(cl_mem);
684
685impl Mem {
686    /// Only call this when passing **the original** newly created pointer
687    /// directly from `clCreate...`. Do not use this to clone or copy.
688    pub unsafe fn from_raw_create_ptr(ptr: cl_mem) -> Mem {
689        assert!(!ptr.is_null(), "Null pointer passed.");
690        Mem(ptr)
691    }
692
693    /// Only call this when passing a copied pointer such as from an
694    /// `clGet*****Info` function.
695    pub unsafe fn from_raw_copied_ptr(ptr: cl_mem) -> Mem {
696        assert!(!ptr.is_null(), "Null pointer passed.");
697        let copy = Mem(ptr);
698        functions::retain_mem_object(&copy).unwrap();
699        copy
700    }
701
702    /// Returns a pointer, do not store it.
703    #[inline(always)]
704    pub fn as_ptr(&self) -> cl_mem {
705        self.0
706    }
707}
708
709impl Clone for Mem {
710    fn clone(&self) -> Mem {
711        unsafe {
712            functions::retain_mem_object(self).unwrap();
713        }
714        Mem(self.0)
715    }
716}
717
718impl Drop for Mem {
719    fn drop(&mut self) {
720        unsafe {
721            functions::release_mem_object(self).unwrap();
722        }
723    }
724}
725
726impl<T: OclPrm> AsMem<T> for Mem {
727    #[inline(always)]
728    fn as_mem(&self) -> &Mem {
729        self
730    }
731}
732
733unsafe impl<'a> MemCmdRw for Mem {}
734unsafe impl<'a> MemCmdRw for &'a Mem {}
735unsafe impl<'a> MemCmdRw for &'a mut Mem {}
736unsafe impl<'a> MemCmdRw for &'a &'a Mem {}
737unsafe impl<'a> MemCmdRw for &'a &'a mut Mem {}
738unsafe impl<'a> MemCmdAll for Mem {}
739unsafe impl<'a> MemCmdAll for &'a Mem {}
740unsafe impl<'a> MemCmdAll for &'a mut Mem {}
741unsafe impl<'a> MemCmdAll for &'a &'a Mem {}
742unsafe impl<'a> MemCmdAll for &'a &'a mut Mem {}
743unsafe impl Sync for Mem {}
744unsafe impl Send for Mem {}
745
746/// A pointer to a region of mapped (pinned) memory.
747//
748// [NOTE]: Do not derive/impl `Clone` or `Sync`. Will not be thread safe
749// without a mutex.
750//
751#[repr(C)]
752#[derive(Debug)]
753pub struct MemMap<T>(*mut T);
754
755impl<T: OclPrm> MemMap<T> {
756    #[inline(always)]
757    /// Only call this when passing **the original** newly created pointer
758    /// directly from `clCreate...`. Do not use this to clone or copy.
759    pub unsafe fn from_raw(ptr: *mut T) -> MemMap<T> {
760        assert!(!ptr.is_null(), "MemMap::from_raw: Null pointer passed.");
761        MemMap(ptr)
762    }
763
764    #[inline(always)]
765    pub fn as_ptr(&self) -> *const T {
766        self.0
767    }
768
769    #[inline(always)]
770    pub fn as_mut_ptr(&mut self) -> *mut T {
771        self.0
772    }
773
774    #[inline(always)]
775    pub fn as_void_ptr(&self) -> *mut c_void {
776        self.0 as *mut _ as *mut c_void
777    }
778
779    #[inline(always)]
780    pub unsafe fn as_slice<'a>(&self, len: usize) -> &'a [T] {
781        slice::from_raw_parts(self.0, len)
782    }
783
784    #[inline(always)]
785    pub unsafe fn as_slice_mut<'a>(&mut self, len: usize) -> &'a mut [T] {
786        slice::from_raw_parts_mut(self.0, len)
787    }
788}
789
790impl<T> AsMem<T> for MemMap<T>
791where
792    T: OclPrm,
793{
794    #[inline(always)]
795    fn as_mem(&self) -> &Mem {
796        unsafe { &*(self as *const _ as *const Mem) }
797    }
798}
799
800unsafe impl<T: OclPrm> MemCmdRw for MemMap<T> {}
801unsafe impl<'a, T: OclPrm> MemCmdRw for &'a MemMap<T> {}
802unsafe impl<'a, T: OclPrm> MemCmdRw for &'a mut MemMap<T> {}
803unsafe impl<T: OclPrm> Send for MemMap<T> {}
804// unsafe impl<T: OclPrm> Sync for MemMap<T> {}
805
806/// cl_program
807#[repr(C)]
808#[derive(Debug)]
809pub struct Program(cl_program);
810
811impl Program {
812    /// Only call this when passing **the original** newly created pointer
813    /// directly from `clCreate...`. Do not use this to clone or copy.
814    pub unsafe fn from_raw_create_ptr(ptr: cl_program) -> Program {
815        assert!(!ptr.is_null(), "Null pointer passed.");
816        Program(ptr)
817    }
818
819    /// Only call this when passing a copied pointer such as from an
820    /// `clGet*****Info` function.
821    pub unsafe fn from_raw_copied_ptr(ptr: cl_program) -> Program {
822        assert!(!ptr.is_null(), "Null pointer passed.");
823        let copy = Program(ptr);
824        functions::retain_program(&copy).unwrap();
825        copy
826    }
827
828    /// Returns a pointer, do not store it.
829    #[inline(always)]
830    pub fn as_ptr(&self) -> cl_program {
831        self.0
832    }
833
834    /// Returns the devices associated with this program.
835    pub fn devices(&self) -> OclCoreResult<Vec<DeviceId>> {
836        match functions::get_program_info(self, ProgramInfo::Devices) {
837            Ok(ProgramInfoResult::Devices(d)) => Ok(d),
838            Err(err) => Err(err),
839            _ => unreachable!(),
840        }
841    }
842}
843
844impl Clone for Program {
845    fn clone(&self) -> Program {
846        unsafe {
847            functions::retain_program(self).unwrap();
848        }
849        Program(self.0)
850    }
851}
852
853impl Drop for Program {
854    fn drop(&mut self) {
855        unsafe {
856            functions::release_program(self).unwrap();
857        }
858    }
859}
860
861unsafe impl Sync for Program {}
862unsafe impl Send for Program {}
863
864impl ClVersions for Program {
865    fn device_versions(&self) -> OclCoreResult<Vec<OpenclVersion>> {
866        let devices = self.devices()?;
867        functions::device_versions(&devices)
868    }
869
870    fn platform_version(&self) -> OclCoreResult<OpenclVersion> {
871        let devices = self.devices()?;
872        devices[0].platform_version()
873    }
874}
875
876/// cl_kernel
877///
878/// ### Thread Safety
879///
880/// Currently not thread safe: does not implement `Send` or `Sync`. It's
881/// probably possible to implement one or both with some work but it's
882/// potentially problematic on certain (all?) platforms due to issues while
883/// setting arguments. If you need to transfer a kernel you're better off
884/// creating another one in the other thread or using some other mechanism
885/// such as channels to manipulate kernels in other threads. This issue will
886/// be revisited in the future (please provide input by filing an issue if you
887/// have any thoughts on the matter).
888///
889/// [UPDATE]: Enabling `Send` for a while to test.
890///
891///
892#[repr(C)]
893#[derive(Debug)]
894pub struct Kernel(cl_kernel);
895
896impl Kernel {
897    /// Only call this when passing **the original** newly created pointer
898    /// directly from `clCreate...`. Do not use this to clone or copy.
899    pub unsafe fn from_raw_create_ptr(ptr: cl_kernel) -> Kernel {
900        assert!(!ptr.is_null(), "Null pointer passed.");
901        Kernel(ptr)
902    }
903
904    /// Only call this when passing a copied pointer such as from an
905    /// `clGet*****Info` function.
906    ///
907    // [TODO]: Evaluate usefulness.
908    pub unsafe fn from_raw_copied_ptr(ptr: cl_kernel) -> Kernel {
909        assert!(!ptr.is_null(), "Null pointer passed.");
910        let copy = Kernel(ptr);
911        functions::retain_kernel(&copy).unwrap();
912        copy
913    }
914
915    /// Returns a pointer, do not store it.
916    #[inline(always)]
917    pub fn as_ptr(&self) -> cl_kernel {
918        self.0
919    }
920
921    /// Returns the program associated with this kernel.
922    pub fn program(&self) -> OclCoreResult<Program> {
923        match functions::get_kernel_info(self, KernelInfo::Program) {
924            Ok(KernelInfoResult::Program(d)) => Ok(d),
925            Err(err) => Err(err),
926            _ => unreachable!(),
927        }
928    }
929
930    pub fn devices(&self) -> OclCoreResult<Vec<DeviceId>> {
931        self.program().and_then(|p| p.devices())
932    }
933}
934
935impl Clone for Kernel {
936    fn clone(&self) -> Kernel {
937        unsafe {
938            functions::retain_kernel(self).unwrap();
939        }
940        Kernel(self.0)
941    }
942}
943
944impl Drop for Kernel {
945    fn drop(&mut self) {
946        unsafe {
947            functions::release_kernel(self).unwrap();
948        }
949    }
950}
951
952impl ClVersions for Kernel {
953    fn device_versions(&self) -> OclCoreResult<Vec<OpenclVersion>> {
954        let devices = self.program()?.devices()?;
955        functions::device_versions(&devices)
956    }
957
958    fn platform_version(&self) -> OclCoreResult<OpenclVersion> {
959        let devices = self.program()?.devices()?;
960        devices[0].platform_version()
961    }
962}
963
964unsafe impl Send for Kernel {}
965
966/// cl_event
967#[repr(C)]
968#[derive(Debug, Hash, PartialEq, Eq)]
969pub struct Event(cl_event);
970
971impl Event {
972    /// For passage directly to an 'event creation' function (such as enqueue...).
973    #[inline]
974    pub fn null() -> Event {
975        Event(0 as cl_event)
976    }
977
978    /// Creates and returns a new 'user' event.
979    ///
980    /// User events are events which are meant to have their completion status
981    /// set from the host side (that means you).
982    ///
983    #[inline]
984    pub fn user<C: ClContextPtr>(context: C) -> OclCoreResult<Event> {
985        functions::create_user_event(context)
986    }
987
988    /// Only call this when passing **the original** newly created pointer
989    /// directly from `clCreate...`. Do not use this to clone or copy.
990    #[inline]
991    pub unsafe fn from_raw_create_ptr(ptr: cl_event) -> Event {
992        assert!(
993            !ptr.is_null(),
994            "ocl_core::Event::from_raw_create_ptr: Null pointer passed."
995        );
996        Event(ptr)
997    }
998
999    /// Only use when cloning or copying from a pre-existing and valid
1000    /// `cl_event`.
1001    #[inline]
1002    pub unsafe fn from_raw_copied_ptr(ptr: cl_event) -> OclCoreResult<Event> {
1003        assert!(
1004            !ptr.is_null(),
1005            "ocl_core::Event::from_raw_copied_ptr: Null pointer passed."
1006        );
1007        let copy = Event(ptr);
1008        functions::retain_event(&copy)?;
1009        Ok(copy)
1010    }
1011
1012    /// Sets this user created event to `CommandExecutionStatus::Complete`.
1013    ///
1014    /// Will return an error if this event is not a 'user' event (created
1015    /// with `::user()`).
1016    ///
1017    #[inline]
1018    pub fn set_complete(&self) -> OclCoreResult<()> {
1019        functions::set_user_event_status(self, CommandExecutionStatus::Complete)
1020    }
1021
1022    /// Queries the command status associated with this event and returns true
1023    /// if it is complete, false if incomplete or upon error.
1024    ///
1025    /// This is the fastest possible way to determine event status.
1026    ///
1027    #[inline]
1028    pub fn is_complete(&self) -> OclCoreResult<bool> {
1029        functions::event_is_complete(self)
1030    }
1031
1032    /// Causes the command queue to wait until this event is complete before returning.
1033    #[inline]
1034    pub fn wait_for(&self) -> OclCoreResult<()> {
1035        crate::wait_for_event(self)
1036    }
1037
1038    /// Returns whether or not this event is associated with a command or is a
1039    /// user event.
1040    #[inline]
1041    pub fn is_null(&self) -> bool {
1042        self.0.is_null()
1043    }
1044
1045    /// [FIXME]: ADD VALIDITY CHECK BY CALLING '_INFO' OR SOMETHING:
1046    /// NULL CHECK IS NOT ENOUGH
1047    ///
1048    /// This still leads to crazy segfaults when non-event pointers (random
1049    /// whatever addresses) are passed. Need better check.
1050    ///
1051    #[inline]
1052    pub fn is_valid(&self) -> bool {
1053        !self.0.is_null()
1054    }
1055
1056    /// Sets a callback function, `callback_receiver`, to trigger upon
1057    /// completion of this event with an optional pointer to user data.
1058    ///
1059    /// The callback function must have a signature matching:
1060    /// `extern "C" fn (ffi::cl_event, i32, *mut libc::c_void)`
1061    ///
1062    /// # Safety
1063    ///
1064    /// `user_data` must be guaranteed to still exist if and when `callback_receiver`
1065    /// is ever called.
1066    ///
1067    /// TODO: Create a safer type wrapper for `callback_receiver` (using an
1068    /// `Arc`?, etc.) within `ocl`.
1069    ///
1070    //
1071    // [NOTE]: Making callback_receiver optional is pointless. There is no way
1072    // to unset a previously set callback.
1073    pub unsafe fn set_callback(
1074        &self,
1075        callback_receiver: EventCallbackFn,
1076        user_data_ptr: *mut c_void,
1077    ) -> OclCoreResult<()> {
1078        if self.is_valid() {
1079            crate::set_event_callback(
1080                self,
1081                CommandExecutionStatus::Complete,
1082                Some(callback_receiver),
1083                user_data_ptr as *mut _ as *mut c_void,
1084            )
1085        } else {
1086            Err(
1087                "ocl_core::Event::set_callback: This event is null. Cannot set callback until \
1088                internal event pointer is actually created by a `clCreate...` function."
1089                    .into(),
1090            )
1091        }
1092    }
1093
1094    /// Returns the `Context` associated with this event.
1095    pub fn context(&self) -> OclCoreResult<Context> {
1096        match functions::get_event_info(self, EventInfo::Context) {
1097            Ok(EventInfoResult::Context(c)) => Ok(c),
1098            Err(err) => Err(err),
1099            _ => unreachable!(),
1100        }
1101    }
1102
1103    /// Returns an immutable reference to a pointer, do not deref and store it unless
1104    /// you will manage its associated reference count carefully.
1105    ///
1106    ///
1107    /// ### Warning
1108    ///
1109    /// DO NOT store this pointer.
1110    ///
1111    /// DO NOT send this pointer across threads unless you are incrementing
1112    /// the reference count before sending and decrementing after sending.
1113    ///
1114    /// Use `::into_raw` for these purposes. Thank you.
1115    ///
1116    #[inline]
1117    pub unsafe fn as_ptr_ref(&self) -> &cl_event {
1118        &self.0
1119    }
1120
1121    /// Returns a mutable reference to a pointer, do not deref then modify or store it
1122    /// unless you will manage its associated reference count carefully.
1123    ///
1124    ///
1125    /// ### Warning
1126    ///
1127    /// DO NOT store this pointer.
1128    ///
1129    /// DO NOT send this pointer across threads unless you are incrementing
1130    /// the reference count before sending and decrementing after sending.
1131    ///
1132    /// Use `::into_raw` for these purposes. Thank you.
1133    ///
1134    #[inline]
1135    pub unsafe fn as_ptr_mut(&mut self) -> &mut cl_event {
1136        &mut self.0
1137    }
1138
1139    /// Consumes the `Event`, returning the wrapped `cl_event` pointer.
1140    ///
1141    /// To avoid a memory leak the pointer must be converted back to an `Event` using
1142    /// [`Event::from_raw`][from_raw].
1143    ///
1144    /// [from_raw]: struct.Event.html#method.from_raw
1145    ///
1146    pub fn into_raw(self) -> cl_event {
1147        let ptr = self.0;
1148        mem::forget(self);
1149        ptr
1150    }
1151
1152    /// Constructs an `Event` from a raw `cl_event` pointer.
1153    ///
1154    /// The raw pointer must have been previously returned by a call to a
1155    /// [`Event::into_raw`][into_raw].
1156    ///
1157    /// [into_raw]: struct.Event.html#method.into_raw
1158    #[inline]
1159    pub unsafe fn from_raw(ptr: cl_event) -> Event {
1160        assert!(!ptr.is_null(), "Null pointer passed.");
1161        Event(ptr)
1162    }
1163
1164    /// Ensures this contains a null event and returns a mutable pointer to it.
1165    fn _alloc_new(&mut self) -> *mut cl_event {
1166        assert!(
1167            self.0.is_null(),
1168            "ocl_core::Event::alloc_new: An 'Event' cannot be \
1169            used as target for event creation (as a new event) more than once."
1170        );
1171        &mut self.0
1172    }
1173
1174    /// Returns a pointer pointer expected when used as a wait list.
1175    unsafe fn _as_ptr_ptr(&self) -> *const cl_event {
1176        if self.0.is_null() {
1177            ptr::null()
1178        } else {
1179            &self.0 as *const cl_event
1180        }
1181    }
1182
1183    /// Returns a count expected when used as a wait list.
1184    fn _count(&self) -> u32 {
1185        if self.0.is_null() {
1186            0
1187        } else {
1188            1
1189        }
1190    }
1191}
1192
1193unsafe impl<'a> ClNullEventPtr for &'a mut Event {
1194    #[inline(always)]
1195    fn alloc_new(&mut self) -> *mut cl_event {
1196        self._alloc_new()
1197    }
1198
1199    #[inline(always)]
1200    unsafe fn clone_from<E: AsRef<Event>>(&mut self, ev: E) {
1201        let ptr = ev.as_ref().clone().into_raw();
1202        assert!(!ptr.is_null());
1203        self.0 = ptr;
1204    }
1205}
1206
1207unsafe impl ClWaitListPtr for Event {
1208    #[inline(always)]
1209    unsafe fn as_ptr_ptr(&self) -> *const cl_event {
1210        self._as_ptr_ptr()
1211    }
1212    #[inline(always)]
1213    fn count(&self) -> u32 {
1214        self._count()
1215    }
1216}
1217
1218unsafe impl<'a> ClWaitListPtr for &'a Event {
1219    #[inline(always)]
1220    unsafe fn as_ptr_ptr(&self) -> *const cl_event {
1221        self._as_ptr_ptr()
1222    }
1223    #[inline(always)]
1224    fn count(&self) -> u32 {
1225        self._count()
1226    }
1227}
1228
1229unsafe impl<'e> ClEventPtrRef<'e> for Event {
1230    #[inline(always)]
1231    unsafe fn as_ptr_ref(&'e self) -> &'e cl_event {
1232        &self.0
1233    }
1234}
1235
1236impl AsRef<Event> for Event {
1237    fn as_ref(&self) -> &Event {
1238        self
1239    }
1240}
1241
1242impl Clone for Event {
1243    fn clone(&self) -> Event {
1244        assert!(
1245            !self.0.is_null(),
1246            "ocl_core::Event::clone: \
1247            Cannot clone a null (empty) event."
1248        );
1249        unsafe {
1250            functions::retain_event(self).expect("core::Event::clone");
1251        }
1252        Event(self.0)
1253    }
1254}
1255
1256impl Drop for Event {
1257    fn drop(&mut self) {
1258        if !self.0.is_null() {
1259            unsafe {
1260                functions::release_event(self).unwrap();
1261            }
1262        }
1263    }
1264}
1265
1266// unsafe impl EventPtr for Event {}
1267unsafe impl Sync for Event {}
1268unsafe impl Send for Event {}
1269
1270/// cl_sampler
1271#[repr(C)]
1272#[derive(Debug)]
1273pub struct Sampler(cl_sampler);
1274
1275impl Sampler {
1276    /// Only call this when passing a newly created pointer directly from
1277    /// `clCreate...`. Do not use this to clone or copy.
1278    pub unsafe fn from_raw_create_ptr(ptr: cl_sampler) -> Sampler {
1279        assert!(!ptr.is_null(), "Null pointer passed.");
1280        Sampler(ptr)
1281    }
1282
1283    /// Returns a pointer, do not store it.
1284    pub unsafe fn as_ptr(&self) -> cl_sampler {
1285        self.0
1286    }
1287}
1288
1289impl Clone for Sampler {
1290    fn clone(&self) -> Sampler {
1291        unsafe {
1292            functions::retain_sampler(self).unwrap();
1293        }
1294        Sampler(self.0)
1295    }
1296}
1297
1298impl Drop for Sampler {
1299    fn drop(&mut self) {
1300        unsafe {
1301            functions::release_sampler(self).unwrap();
1302        }
1303    }
1304}
1305
1306unsafe impl Sync for Sampler {}
1307unsafe impl Send for Sampler {}