ocl_core/types/
structs.rs

1//! Rust implementations of various structs used by the OpenCL API.
2
3use crate::error::{Error as OclCoreError, Result as OclCoreResult};
4use crate::ffi::{
5    self, c_void, cl_buffer_region, cl_context_properties, cl_mem, cl_platform_id, cl_sampler,
6    size_t,
7};
8use crate::{
9    ContextProperty, ImageChannelDataType, ImageChannelOrder, Mem, MemObjectType, OclPrm,
10    PlatformId, Sampler,
11};
12use num_traits::FromPrimitive;
13use std;
14use std::collections::HashMap;
15use std::marker::PhantomData;
16use std::mem;
17use std::ptr;
18
19// Until everything can be implemented:
20pub type TemporaryPlaceholderType = ();
21
22/// A reference to a kernel argument value.
23///
24/// ### Example:
25///
26/// ```rust, ignore
27/// let kernel = core::create_kernel(&program, "multiply")?;
28/// core::set_kernel_arg(&kernel, 0, ArgVal::scalar(&10.0f32))?;
29/// core::set_kernel_arg(&kernel, 1, ArgVal::mem(&buffer))?;
30/// ```
31///
32#[derive(Debug, Clone)]
33pub struct ArgVal<'a> {
34    size: size_t,
35    value: *const c_void,
36    is_mem: bool,
37    _p: PhantomData<&'a c_void>,
38}
39
40impl<'a> ArgVal<'a> {
41    /// Returns a new `ArgVal` referring to a `Mem` object.
42    pub fn mem(mem: &'a Mem) -> ArgVal<'a> {
43        ArgVal {
44            size: mem::size_of::<cl_mem>() as size_t,
45            value: mem as *const _ as *const c_void,
46            is_mem: true,
47            _p: PhantomData,
48        }
49    }
50
51    /// Returns a new `ArgVal` corresponding to a null `Mem` object.
52    pub fn mem_null() -> ArgVal<'a> {
53        ArgVal {
54            size: mem::size_of::<cl_mem>() as size_t,
55            value: ptr::null(),
56            is_mem: true,
57            _p: PhantomData,
58        }
59    }
60
61    /// Returns a new `ArgVal` referring to a `Sampler` object.
62    pub fn sampler(sampler: &'a Sampler) -> ArgVal<'a> {
63        ArgVal {
64            size: mem::size_of::<cl_sampler>() as size_t,
65            value: sampler as *const _ as *const c_void,
66            is_mem: false,
67            _p: PhantomData,
68        }
69    }
70
71    /// Returns a new `ArgVal` referring to a null `Sampler` object.
72    pub fn sampler_null() -> ArgVal<'a> {
73        ArgVal {
74            size: mem::size_of::<cl_sampler>() as size_t,
75            value: ptr::null(),
76            is_mem: false,
77            _p: PhantomData,
78        }
79    }
80
81    /// Returns a new `ArgVal` referring to a scalar or vector primitive.
82    //
83    // `::scalar` and `::vector` exist in case, at a future time, scalar and
84    // vector types need to be differentiated, at which point this method
85    // would be deprecated.
86    pub fn primitive<T>(prm: &'a T) -> ArgVal<'a>
87    where
88        T: OclPrm,
89    {
90        ArgVal {
91            size: mem::size_of::<T>() as size_t,
92            value: prm as *const T as *const c_void,
93            is_mem: false,
94            _p: PhantomData,
95        }
96    }
97
98    /// Returns a new `ArgVal` referring to a scalar primitive.
99    pub fn scalar<T>(scalar: &'a T) -> ArgVal<'a>
100    where
101        T: OclPrm,
102    {
103        ArgVal::primitive(scalar)
104    }
105
106    /// Returns a new `ArgVal` referring to a vector primitive.
107    pub fn vector<T>(vector: &'a T) -> ArgVal<'a>
108    where
109        T: OclPrm,
110    {
111        ArgVal::primitive(vector)
112    }
113
114    /// Returns a new `ArgVal` corresponding to a `__local` argument.
115    ///
116    /// To specify a `__local` argument size in bytes, use `::raw` instead
117    /// (with `value`: `std::ptr::null()`).
118    pub fn local<T>(length: &usize) -> ArgVal<'a>
119    where
120        T: OclPrm,
121    {
122        ArgVal {
123            size: (mem::size_of::<T>() * length) as size_t,
124            value: ptr::null(),
125            is_mem: false,
126            _p: PhantomData,
127        }
128    }
129
130    /// Returns a new `ArgVal` containing the size in bytes and a raw pointer
131    /// to the argument value.
132    ///
133    /// ### Safety
134    ///
135    /// Caller must ensure that the value pointed to by `value` lives until
136    /// the call to `::set_kernel_arg` returns and that `size` accurately
137    /// reflects the total number of bytes that should be read.
138    pub unsafe fn from_raw(size: size_t, value: *const c_void, is_mem: bool) -> ArgVal<'a> {
139        ArgVal {
140            size,
141            value,
142            is_mem,
143            _p: PhantomData,
144        }
145    }
146
147    /// Returns the size (in bytes) and raw pointer to the contained kernel
148    /// argument value.
149    pub fn as_raw(&self) -> (size_t, *const c_void) {
150        (self.size, self.value)
151    }
152
153    /// Returns `true` if this `ArgVal` represents a null `Mem` or `Sampler`
154    /// object.
155    pub fn is_mem_null(&self) -> bool {
156        self.is_mem && self.value.is_null()
157    }
158}
159
160/// Parsed OpenCL version in the layout `({major}, {minor})`.
161///
162/// ex.: 'OpenCL 1.2' -> `OpenclVersion(1, 2)`.
163///
164#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
165pub struct OpenclVersion {
166    ver: [u16; 2],
167}
168
169impl OpenclVersion {
170    pub fn new(major: u16, minor: u16) -> OpenclVersion {
171        OpenclVersion {
172            ver: [major, minor],
173        }
174    }
175
176    pub fn max(&self) -> OpenclVersion {
177        OpenclVersion {
178            ver: [u16::max_value(), u16::max_value()],
179        }
180    }
181
182    pub fn to_raw(&self) -> (u16, u16) {
183        (self.ver[0], self.ver[1])
184    }
185
186    /// Parse the string `ver` and return a dual-integer result as
187    /// `OpenclVersion`.
188    ///
189    /// Looks for the sequence of chars, "OpenCL" (non-case-sensitive), then
190    /// splits the word just after that (at '.') and parses the two results
191    /// into integers (major and minor version numbers).
192    pub fn from_info_str(ver: &str) -> OclCoreResult<OpenclVersion> {
193        let mut version_word_idx: Option<usize> = None;
194        let mut version: Option<OpenclVersion> = None;
195
196        for (word_idx, word) in ver.split_whitespace().enumerate() {
197            if let Some(wi) = version_word_idx {
198                assert!(wi == word_idx);
199                let nums: Vec<_> = word.split('.').collect();
200
201                if nums.len() == 2 {
202                    let (major, minor) = (nums[0].parse::<u16>(), nums[1].parse::<u16>());
203
204                    if major.is_ok() && minor.is_ok() {
205                        version = Some(OpenclVersion::new(major.unwrap(), minor.unwrap()));
206                    }
207                }
208                break;
209            }
210
211            for (ch_idx, ch) in word.chars().enumerate() {
212                match ch_idx {
213                    0 => {
214                        if ch != 'O' && ch != 'o' {
215                            break;
216                        }
217                    }
218                    1 => {
219                        if ch != 'P' && ch != 'p' {
220                            break;
221                        }
222                    }
223                    2 => {
224                        if ch != 'E' && ch != 'e' {
225                            break;
226                        }
227                    }
228                    3 => {
229                        if ch != 'N' && ch != 'n' {
230                            break;
231                        }
232                    }
233                    4 => {
234                        if ch != 'C' && ch != 'c' {
235                            break;
236                        }
237                    }
238                    5 => {
239                        if ch == 'L' || ch == 'l' {
240                            version_word_idx = Some(word_idx + 1);
241                            break;
242                        }
243                    }
244                    _ => break,
245                }
246            }
247        }
248
249        match version {
250            Some(cl_ver) => Ok(cl_ver),
251            None => Err(format!(
252                "DeviceInfoResult::as_opencl_version(): \
253                Error parsing version from the string: '{}'.",
254                ver
255            )
256            .into()),
257        }
258    }
259}
260
261impl From<[u16; 2]> for OpenclVersion {
262    fn from(ver: [u16; 2]) -> OpenclVersion {
263        OpenclVersion { ver }
264    }
265}
266
267impl std::fmt::Display for OpenclVersion {
268    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
269        write!(f, "{}.{}", self.ver[0], self.ver[1])
270    }
271}
272
273// cl_context_properties enum  Property value  Description
274//
275// CL_CONTEXT_PLATFORM cl_platform_id  Specifies the platform to use.
276//
277// CL_CONTEXT_INTEROP_USER_SYNC    cl_bool Specifies whether the user is
278// responsible for synchronization between OpenCL and other APIs. Please refer
279// to the specific sections in the OpenCL 1.2 extension specification that
280// describe sharing with other APIs for restrictions on using this flag.
281//
282//    - If CL_CONTEXT_INTEROP_USER_ SYNC is not specified, a default of
283//      CL_FALSE is assumed.
284//
285// CL_CONTEXT_D3D10_DEVICE_KHR ID3D10Device*   If the cl_khr_d3d10_sharing
286// extension is enabled, specifies the ID3D10Device* to use for Direct3D 10
287// interoperability. The default value is NULL.
288//
289// CL_GL_CONTEXT_KHR   0, OpenGL context handle    OpenGL context to
290// associated the OpenCL context with (available if the cl_khr_gl_sharing
291// extension is enabled)
292//
293// CL_EGL_DISPLAY_KHR  EGL_NO_DISPLAY, EGLDisplay handle   EGLDisplay an
294// OpenGL context was created with respect to (available if the
295// cl_khr_gl_sharing extension is enabled)
296//
297// CL_GLX_DISPLAY_KHR  None, X handle  X Display an OpenGL context was created
298// with respect to (available if the cl_khr_gl_sharing extension is enabled)
299//
300// CL_CGL_SHAREGROUP_KHR   0, CGL share group handle   CGL share group to
301// associate the OpenCL context with (available if the cl_khr_gl_sharing
302// extension is enabled)
303//
304// CL_WGL_HDC_KHR  0, HDC handle   HDC an OpenGL context was created with
305// respect to (available if the cl_khr_gl_sharing extension is enabled)
306//
307// CL_CONTEXT_ADAPTER_D3D9_KHR IDirect3DDevice9 *  Specifies an
308// IDirect3DDevice9 to use for D3D9 interop (if the cl_khr_dx9_media_sharing
309// extension is supported).
310//
311// CL_CONTEXT_ADAPTER_D3D9EX_KHR   IDirect3DDeviceEx*  Specifies an
312// IDirect3DDevice9Ex to use for D3D9 interop (if the cl_khr_dx9_media_sharing
313// extension is supported).
314//
315// CL_CONTEXT_ADAPTER_DXVA_KHR IDXVAHD_Device *    Specifies an IDXVAHD_Device
316// to use for DXVA interop (if the cl_khr_dx9_media_sharing extension is
317// supported).
318//
319// CL_CONTEXT_D3D11_DEVICE_KHR ID3D11Device *  Specifies the ID3D11Device * to
320// use for Direct3D 11 interoperability. The default value is NULL.
321//
322#[derive(Clone, Debug)]
323pub enum ContextPropertyValue {
324    Platform(PlatformId),
325    InteropUserSync(bool),
326    // Not sure about this type:
327    D3d10DeviceKhr(*mut ffi::cl_d3d10_device_source_khr),
328    GlContextKhr(*mut c_void),
329    EglDisplayKhr(ffi::CLeglDisplayKHR),
330    // Not sure about this type:
331    GlxDisplayKhr(*mut c_void),
332    // Not sure about this type:
333    CglSharegroupKhr(*mut c_void),
334    // Not sure about this type:
335    WglHdcKhr(*mut c_void),
336    AdapterD3d9Khr(isize),
337    AdapterD3d9exKhr(isize),
338    AdapterDxvaKhr(isize),
339    D3d11DeviceKhr(*mut c_void),
340}
341
342unsafe impl Send for ContextPropertyValue {}
343unsafe impl Sync for ContextPropertyValue {}
344
345/// Context properties list.
346///
347/// [MINIMALLY TESTED]
348///
349/// TODO: Check for duplicate property assignments.
350#[derive(Clone, Debug)]
351pub struct ContextProperties {
352    props: HashMap<ContextProperty, ContextPropertyValue>,
353    contains_gl_context_or_sharegroup: bool,
354}
355
356impl ContextProperties {
357    /// Returns an empty new list of context properties
358    pub fn new() -> ContextProperties {
359        ContextProperties {
360            props: HashMap::with_capacity(16),
361            contains_gl_context_or_sharegroup: false,
362        }
363    }
364
365    /// Specifies a platform (builder-style).
366    pub fn platform<P: Into<PlatformId>>(mut self, platform: P) -> ContextProperties {
367        self.set_platform(platform);
368        self
369    }
370
371    /// Specifies whether the user is responsible for synchronization between
372    /// OpenCL and other APIs (builder-style).
373    pub fn interop_user_sync(mut self, sync: bool) -> ContextProperties {
374        self.set_interop_user_sync(sync);
375        self
376    }
377
378    /// Specifies an OpenGL context handle (builder-style).
379    pub fn gl_context(mut self, gl_ctx: *mut c_void) -> ContextProperties {
380        self.set_gl_context(gl_ctx);
381        self
382    }
383
384    /// Specifies a Display pointer for the GLX context (builder-style).
385    pub fn glx_display(mut self, glx_disp: *mut c_void) -> ContextProperties {
386        self.set_glx_display(glx_disp);
387        self
388    }
389
390    /// Specifies a Display pointer for the WGL HDC (builder-style).
391    pub fn wgl_hdc(mut self, wgl_hdc: *mut c_void) -> ContextProperties {
392        self.set_wgl_hdc(wgl_hdc);
393        self
394    }
395
396    /// Specifies an OpenGL context CGL share group to associate the OpenCL
397    /// context with (builder-style).
398    pub fn cgl_sharegroup(mut self, gl_sharegroup: *mut c_void) -> ContextProperties {
399        self.set_cgl_sharegroup(gl_sharegroup);
400        self
401    }
402
403    /// Specifies a pointer for the EGL display (builder-style).
404    pub fn egl_display(mut self, egl_disp: *mut c_void) -> ContextProperties {
405        self.set_egl_display(egl_disp);
406        self
407    }
408
409    /// Pushes a `ContextPropertyValue` onto this list of properties
410    /// (builder-style).
411    pub fn property_value(mut self, prop: ContextPropertyValue) -> ContextProperties {
412        self.set_property_value(prop);
413        self
414    }
415
416    /// Specifies a platform.
417    pub fn set_platform<P: Into<PlatformId>>(&mut self, platform: P) {
418        self.props.insert(
419            ContextProperty::Platform,
420            ContextPropertyValue::Platform(platform.into()),
421        );
422    }
423
424    /// Specifies whether the user is responsible for synchronization between
425    /// OpenCL and other APIs.
426    pub fn set_interop_user_sync(&mut self, sync: bool) {
427        self.props.insert(
428            ContextProperty::InteropUserSync,
429            ContextPropertyValue::InteropUserSync(sync),
430        );
431    }
432
433    /// Specifies an OpenGL context handle.
434    pub fn set_gl_context(&mut self, gl_ctx: *mut c_void) {
435        self.props.insert(
436            ContextProperty::GlContextKhr,
437            ContextPropertyValue::GlContextKhr(gl_ctx),
438        );
439        self.contains_gl_context_or_sharegroup = true;
440    }
441
442    /// Specifies a Display pointer for the GLX context.
443    pub fn set_glx_display(&mut self, glx_disp: *mut c_void) {
444        self.props.insert(
445            ContextProperty::GlxDisplayKhr,
446            ContextPropertyValue::GlxDisplayKhr(glx_disp),
447        );
448        self.contains_gl_context_or_sharegroup = true;
449    }
450
451    /// Specifies a Display pointer for the WGL HDC.
452    pub fn set_wgl_hdc(&mut self, wgl_hdc: *mut c_void) {
453        self.props.insert(
454            ContextProperty::WglHdcKhr,
455            ContextPropertyValue::WglHdcKhr(wgl_hdc),
456        );
457        self.contains_gl_context_or_sharegroup = true;
458    }
459
460    /// Specifies an OpenGL context CGL share group to associate the OpenCL
461    /// context with.
462    pub fn set_cgl_sharegroup(&mut self, gl_sharegroup: *mut c_void) {
463        self.props.insert(
464            ContextProperty::CglSharegroupKhr,
465            ContextPropertyValue::CglSharegroupKhr(gl_sharegroup),
466        );
467        self.contains_gl_context_or_sharegroup = true;
468    }
469
470    /// Specifies a pointer for the EGL display.
471    pub fn set_egl_display(&mut self, egl_disp: *mut c_void) {
472        self.props.insert(
473            ContextProperty::EglDisplayKhr,
474            ContextPropertyValue::EglDisplayKhr(egl_disp),
475        );
476        self.contains_gl_context_or_sharegroup = true;
477    }
478
479    /// Pushes a `ContextPropertyValue` onto this list of properties.
480    pub fn set_property_value(&mut self, prop: ContextPropertyValue) {
481        match prop {
482            ContextPropertyValue::Platform(val) => {
483                self.props.insert(
484                    ContextProperty::Platform,
485                    ContextPropertyValue::Platform(val),
486                );
487            }
488            ContextPropertyValue::InteropUserSync(val) => {
489                self.props.insert(
490                    ContextProperty::InteropUserSync,
491                    ContextPropertyValue::InteropUserSync(val),
492                );
493            }
494            ContextPropertyValue::GlContextKhr(val) => {
495                self.props.insert(
496                    ContextProperty::GlContextKhr,
497                    ContextPropertyValue::GlContextKhr(val),
498                );
499                self.contains_gl_context_or_sharegroup = true;
500            }
501            ContextPropertyValue::GlxDisplayKhr(val) => {
502                self.props.insert(
503                    ContextProperty::GlxDisplayKhr,
504                    ContextPropertyValue::GlxDisplayKhr(val),
505                );
506                self.contains_gl_context_or_sharegroup = true;
507            }
508            ContextPropertyValue::WglHdcKhr(val) => {
509                self.props.insert(
510                    ContextProperty::WglHdcKhr,
511                    ContextPropertyValue::WglHdcKhr(val),
512                );
513                self.contains_gl_context_or_sharegroup = true;
514            }
515            ContextPropertyValue::CglSharegroupKhr(val) => {
516                self.props.insert(
517                    ContextProperty::CglSharegroupKhr,
518                    ContextPropertyValue::CglSharegroupKhr(val),
519                );
520                self.contains_gl_context_or_sharegroup = true;
521            }
522            ContextPropertyValue::EglDisplayKhr(val) => {
523                self.props.insert(
524                    ContextProperty::EglDisplayKhr,
525                    ContextPropertyValue::EglDisplayKhr(val),
526                );
527                self.contains_gl_context_or_sharegroup = true;
528            }
529            ContextPropertyValue::D3d11DeviceKhr(val) => {
530                self.props.insert(
531                    ContextProperty::D3d11DeviceKhr,
532                    ContextPropertyValue::D3d11DeviceKhr(val),
533                );
534            }
535            _ => panic!("'{:?}' is not yet a supported variant.", prop),
536        }
537    }
538
539    /// Returns a platform id or none.
540    pub fn get_platform(&self) -> Option<PlatformId> {
541        match self.props.get(&ContextProperty::Platform) {
542            Some(prop_val) => {
543                if let ContextPropertyValue::Platform(ref plat) = *prop_val {
544                    Some(*plat)
545                } else {
546                    panic!("Internal error returning platform.");
547                }
548            }
549            None => None,
550        }
551    }
552
553    /// Returns true if this set of context properties specifies any OpenGL
554    /// context or sharegroup to associate with.
555    pub fn contains_gl_context_or_sharegroup(&self) -> bool {
556        self.contains_gl_context_or_sharegroup
557    }
558
559    /// Converts this list into a packed-word representation as specified
560    /// [here](https://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clCreateContext.html).
561    ///
562    // [NOTE]: Meant to replace `::to_bytes`.
563    //
564    // Return type is `Vec<cl_context_properties>` => `Vec<isize>`
565    //
566    // [FIXME]: Change return type to `Vec<(cl_context_properties, isize)>`
567    pub fn to_raw(&self) -> Vec<isize> {
568        let mut props_raw = Vec::with_capacity(32);
569
570        // For each property ...
571        for (key, val) in self.props.iter() {
572            // convert both the kind of property (a u32 originally) and
573            // the value (variable type/size) to an isize:
574            match *val {
575                ContextPropertyValue::Platform(ref platform_id_core) => {
576                    props_raw.push(*key as isize);
577                    props_raw.push(platform_id_core.as_ptr() as isize);
578                }
579                ContextPropertyValue::InteropUserSync(sync) => {
580                    props_raw.push(*key as isize);
581                    props_raw.push(sync as isize);
582                }
583                ContextPropertyValue::GlContextKhr(sync) => {
584                    props_raw.push(*key as isize);
585                    props_raw.push(sync as isize);
586                }
587                ContextPropertyValue::GlxDisplayKhr(sync) => {
588                    props_raw.push(*key as isize);
589                    props_raw.push(sync as isize);
590                }
591                ContextPropertyValue::WglHdcKhr(sync) => {
592                    props_raw.push(*key as isize);
593                    props_raw.push(sync as isize);
594                }
595                ContextPropertyValue::CglSharegroupKhr(sync) => {
596                    props_raw.push(*key as isize);
597                    props_raw.push(sync as isize);
598                }
599                ContextPropertyValue::EglDisplayKhr(sync) => {
600                    props_raw.push(*key as isize);
601                    props_raw.push(sync as isize);
602                }
603                ContextPropertyValue::D3d11DeviceKhr(sync) => {
604                    props_raw.push(*key as isize);
605                    props_raw.push(sync as isize);
606                }
607                _ => panic!("'{:?}' is not yet a supported variant.", key),
608            };
609        }
610
611        // Add a terminating 0:
612        props_raw.push(0);
613
614        props_raw.shrink_to_fit();
615        props_raw
616    }
617
618    /// Returns a single context property value.
619    pub unsafe fn extract_property_from_raw(
620        property: ContextProperty,
621        raw_context_properties: &[isize],
622    ) -> Option<ContextPropertyValue> {
623        // REMEMBER: It's null terminated;
624
625        // The raw properties **should** be `(isize, isize)` pairs + isize (null) terminator.
626        assert!(raw_context_properties.len() % 2 == 1);
627        assert!(*raw_context_properties.last().unwrap() == 0);
628
629        let pair_count = raw_context_properties.len() / 2;
630
631        match property {
632            ContextProperty::Platform => {
633                for pair_idx in 0..pair_count {
634                    let idz = pair_idx * 2;
635                    let key_raw = *raw_context_properties.get_unchecked(idz);
636                    let val_raw = *raw_context_properties.get_unchecked(idz + 1);
637
638                    if key_raw == property as cl_context_properties {
639                        return Some(ContextPropertyValue::Platform(PlatformId::from_raw(
640                            val_raw as cl_platform_id,
641                        )));
642                    }
643                }
644            }
645            _ => unimplemented!(),
646        }
647
648        None
649    }
650
651    /// Converts raw stuff into other stuff.
652    ///
653    ///
654    #[allow(unused_variables, unused_mut)]
655    pub unsafe fn from_raw(raw_context_properties: &[isize]) -> OclCoreResult<ContextProperties> {
656        // The raw properties **should** be `(isize, isize)` pairs + isize (null) terminator.
657        assert!(mem::size_of::<cl_context_properties>() == mem::size_of::<isize>());
658        assert!(raw_context_properties.len() % 2 == 1);
659        assert!(*raw_context_properties.last().unwrap() == 0);
660
661        let pair_count = raw_context_properties.len() / 2;
662        let mut context_props = ContextProperties {
663            props: HashMap::with_capacity(pair_count),
664            contains_gl_context_or_sharegroup: false,
665        };
666
667        for pair_idx in 0..pair_count {
668            let idz = pair_idx * 2;
669            let key_raw = *raw_context_properties.get_unchecked(idz);
670            let val_raw = *raw_context_properties.get_unchecked(idz + 1);
671
672            let key = ContextProperty::from_isize(key_raw).ok_or_else(|| {
673                OclCoreError::String(format!(
674                    "ContextProperties::from_raw: Unable to convert '{}' using \
675                    'ContextProperty::from_isize'.",
676                    key_raw
677                ))
678            })?;
679
680            match key {
681                ContextProperty::Platform => {
682                    context_props.props.insert(
683                        ContextProperty::Platform,
684                        ContextPropertyValue::Platform(PlatformId::from_raw(
685                            val_raw as cl_platform_id,
686                        )),
687                    );
688                }
689                ContextProperty::InteropUserSync => {
690                    context_props.props.insert(
691                        ContextProperty::InteropUserSync,
692                        ContextPropertyValue::InteropUserSync(val_raw > 0),
693                    );
694                }
695                ContextProperty::D3d10DeviceKhr => {
696                    context_props.props.insert(
697                        ContextProperty::D3d10DeviceKhr,
698                        ContextPropertyValue::D3d10DeviceKhr(
699                            val_raw as *mut ffi::cl_d3d10_device_source_khr,
700                        ),
701                    );
702                }
703                ContextProperty::GlContextKhr => {
704                    context_props.props.insert(
705                        ContextProperty::GlContextKhr,
706                        ContextPropertyValue::GlContextKhr(val_raw as *mut c_void),
707                    );
708                    context_props.contains_gl_context_or_sharegroup = true;
709                }
710                ContextProperty::EglDisplayKhr => {
711                    context_props.props.insert(
712                        ContextProperty::EglDisplayKhr,
713                        ContextPropertyValue::EglDisplayKhr(val_raw as ffi::CLeglDisplayKHR),
714                    );
715                    context_props.contains_gl_context_or_sharegroup = true;
716                }
717                ContextProperty::GlxDisplayKhr => {
718                    context_props.props.insert(
719                        ContextProperty::GlxDisplayKhr,
720                        ContextPropertyValue::GlxDisplayKhr(val_raw as *mut c_void),
721                    );
722                    context_props.contains_gl_context_or_sharegroup = true;
723                }
724                ContextProperty::CglSharegroupKhr => {
725                    context_props.props.insert(
726                        ContextProperty::CglSharegroupKhr,
727                        ContextPropertyValue::CglSharegroupKhr(val_raw as *mut c_void),
728                    );
729                    context_props.contains_gl_context_or_sharegroup = true;
730                }
731                ContextProperty::WglHdcKhr => {
732                    context_props.props.insert(
733                        ContextProperty::WglHdcKhr,
734                        ContextPropertyValue::WglHdcKhr(val_raw as *mut c_void),
735                    );
736                    context_props.contains_gl_context_or_sharegroup = true;
737                }
738                ContextProperty::AdapterD3d9Khr => {
739                    context_props.props.insert(
740                        ContextProperty::AdapterD3d9Khr,
741                        ContextPropertyValue::AdapterD3d9Khr(val_raw),
742                    );
743                }
744                ContextProperty::AdapterD3d9exKhr => {
745                    context_props.props.insert(
746                        ContextProperty::AdapterD3d9exKhr,
747                        ContextPropertyValue::AdapterD3d9exKhr(val_raw),
748                    );
749                }
750                ContextProperty::AdapterDxvaKhr => {
751                    context_props.props.insert(
752                        ContextProperty::AdapterDxvaKhr,
753                        ContextPropertyValue::AdapterDxvaKhr(val_raw),
754                    );
755                }
756                ContextProperty::D3d11DeviceKhr => {
757                    context_props.props.insert(
758                        ContextProperty::D3d11DeviceKhr,
759                        ContextPropertyValue::D3d11DeviceKhr(val_raw as *mut c_void),
760                    );
761                }
762            }
763        }
764
765        Ok(context_props)
766    }
767}
768
769// impl Into<Vec<isize>> for ContextProperties {
770//     fn into(self) -> Vec<isize> {
771//         self.to_raw()
772//     }
773// }
774
775impl From<ContextProperties> for Vec<isize> {
776    fn from(cp: ContextProperties) -> Vec<isize> {
777        cp.to_raw()
778    }
779}
780
781/// Defines a buffer region for creating a sub-buffer.
782///
783/// ### Info (from [SDK](https://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clCreateSubBuffer.html))
784///
785/// (origin, size) defines the offset and size in bytes in buffer.
786///
787/// If buffer is created with CL_MEM_USE_HOST_PTR, the host_ptr associated with
788/// the buffer object returned is host_ptr + origin.
789///
790/// The buffer object returned references the data store allocated for buffer and
791/// points to a specific region given by (origin, size) in this data store.
792///
793/// CL_INVALID_VALUE is returned in errcode_ret if the region specified by
794/// (origin, size) is out of bounds in buffer.
795///
796/// CL_INVALID_BUFFER_SIZE if size is 0.
797///
798/// CL_MISALIGNED_SUB_BUFFER_OFFSET is returned in errcode_ret if there are no
799/// devices in context associated with buffer for which the origin value is
800/// aligned to the CL_DEVICE_MEM_BASE_ADDR_ALIGN value.
801///
802pub struct BufferRegion<T> {
803    origin: usize,
804    len: usize,
805    _data: PhantomData<T>,
806}
807
808impl<T: OclPrm> BufferRegion<T> {
809    pub fn new(origin: usize, len: usize) -> BufferRegion<T> {
810        BufferRegion {
811            origin,
812            len,
813            _data: PhantomData,
814        }
815    }
816
817    pub fn to_bytes(&self) -> cl_buffer_region {
818        cl_buffer_region {
819            origin: self.origin * mem::size_of::<T>(),
820            size: self.len * mem::size_of::<T>(),
821        }
822    }
823
824    pub fn from_bytes(ffi_struct: cl_buffer_region) -> BufferRegion<T> {
825        assert!(ffi_struct.origin % mem::size_of::<T>() == 0);
826        assert!(ffi_struct.size % mem::size_of::<T>() == 0);
827
828        BufferRegion::new(
829            ffi_struct.origin / mem::size_of::<T>(),
830            ffi_struct.size / mem::size_of::<T>(),
831        )
832    }
833}
834
835pub enum ImageFormatParseError {
836    UnknownImageChannelOrder(ffi::cl_channel_order),
837    UnknownImageChannelDataType(ffi::cl_channel_type),
838}
839
840impl ::std::fmt::Debug for ImageFormatParseError {
841    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
842        match *self {
843            ImageFormatParseError::UnknownImageChannelOrder(ord) => {
844                write!(f, "unknown image channel ordering: '{}'", ord)
845            }
846            ImageFormatParseError::UnknownImageChannelDataType(dt) => {
847                write!(f, "unknown image channel data type: '{}'", dt)
848            }
849        }
850    }
851}
852
853impl ::std::fmt::Display for ImageFormatParseError {
854    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
855        write!(f, "{:?}", self)
856    }
857}
858
859impl ::std::error::Error for ImageFormatParseError {
860    fn description(&self) -> &str {
861        match *self {
862            ImageFormatParseError::UnknownImageChannelOrder(_) => "unknown image channel ordering",
863            ImageFormatParseError::UnknownImageChannelDataType(_) => {
864                "unknown image channel data type"
865            }
866        }
867    }
868}
869
870pub type ImageFormatParseResult = Result<ImageFormat, ImageFormatParseError>;
871
872/// Image format properties used by `Image`.
873///
874/// A structure that describes format properties of the image to be allocated. (from SDK)
875///
876/// # Examples (from SDK)
877///
878/// To specify a normalized unsigned 8-bit / channel RGBA image:
879///    image_channel_order = CL_RGBA
880///    image_channel_data_type = CL_UNORM_INT8
881///
882/// image_channel_data_type values of CL_UNORM_SHORT_565, CL_UNORM_SHORT_555
883/// and CL_UNORM_INT_101010 are special cases of packed image formats where
884/// the channels of each element are packed into a single unsigned short or
885/// unsigned int. For these special packed image formats, the channels are
886/// normally packed with the first channel in the most significant bits of the
887/// bitfield, and successive channels occupying progressively less significant
888/// locations. For CL_UNORM_SHORT_565, R is in bits 15:11, G is in bits 10:5
889/// and B is in bits 4:0. For CL_UNORM_SHORT_555, bit 15 is undefined, R is in
890/// bits 14:10, G in bits 9:5 and B in bits 4:0. For CL_UNORM_INT_101010, bits
891/// 31:30 are undefined, R is in bits 29:20, G in bits 19:10 and B in bits
892/// 9:0. OpenCL implementations must maintain the minimum precision specified
893/// by the number of bits in image_channel_data_type. If the image format
894/// specified by image_channel_order, and image_channel_data_type cannot be
895/// supported by the OpenCL implementation, then the call to clCreateImage
896/// will return a NULL memory object.
897///
898#[derive(Debug, Clone)]
899pub struct ImageFormat {
900    pub channel_order: ImageChannelOrder,
901    pub channel_data_type: ImageChannelDataType,
902}
903
904impl ImageFormat {
905    pub fn new(order: ImageChannelOrder, data_type: ImageChannelDataType) -> ImageFormat {
906        ImageFormat {
907            channel_order: order,
908            channel_data_type: data_type,
909        }
910    }
911
912    pub fn new_rgba() -> ImageFormat {
913        ImageFormat {
914            channel_order: ImageChannelOrder::Rgba,
915            channel_data_type: ImageChannelDataType::SnormInt8,
916        }
917    }
918
919    pub fn from_raw(fmt_raw: ffi::cl_image_format) -> ImageFormatParseResult {
920        let channel_order = match ImageChannelOrder::from_u32(fmt_raw.image_channel_order) {
921            Some(ord) => ord,
922            None => {
923                return Err(ImageFormatParseError::UnknownImageChannelOrder(
924                    fmt_raw.image_channel_order,
925                ))
926            }
927        };
928
929        let channel_data_type =
930            match ImageChannelDataType::from_u32(fmt_raw.image_channel_data_type) {
931                Some(dt) => dt,
932                None => {
933                    return Err(ImageFormatParseError::UnknownImageChannelDataType(
934                        fmt_raw.image_channel_data_type,
935                    ))
936                }
937            };
938
939        Ok(ImageFormat {
940            channel_order,
941            channel_data_type,
942        })
943    }
944
945    pub fn list_from_raw(list_raw: Vec<ffi::cl_image_format>) -> Vec<ImageFormatParseResult> {
946        list_raw.into_iter().map(ImageFormat::from_raw).collect()
947    }
948
949    pub fn to_raw(&self) -> ffi::cl_image_format {
950        ffi::cl_image_format {
951            image_channel_order: self.channel_order as ffi::cl_channel_order,
952            image_channel_data_type: self.channel_data_type as ffi::cl_channel_type,
953        }
954    }
955
956    pub fn new_raw() -> ffi::cl_image_format {
957        ffi::cl_image_format {
958            image_channel_order: 0 as ffi::cl_channel_order,
959            image_channel_data_type: 0 as ffi::cl_channel_type,
960        }
961    }
962
963    /// Returns the size in bytes of a pixel using the format specified by this
964    /// `ImageFormat`.
965    ///
966    /// TODO: Add a special case for Depth & DepthStencil
967    /// (https://www.khronos.org/registry/cl/sdk/2.0/docs/man/xhtml/cl_khr_gl_depth_images.html).
968    ///
969    /// TODO: Validate combinations.
970    /// TODO: Use `core::get_image_info` to check these with a test.
971    ///
972    pub fn pixel_bytes(&self) -> usize {
973        let channel_count = match self.channel_order {
974            ImageChannelOrder::R => 1,
975            ImageChannelOrder::A => 1,
976            ImageChannelOrder::Rg => 2,
977            ImageChannelOrder::Ra => 2,
978            // This format can only be used if channel data type = CL_UNORM_SHORT_565, CL_UNORM_SHORT_555 or CL_UNORM_INT101010:
979            ImageChannelOrder::Rgb => 1,
980            ImageChannelOrder::Rgba => 4,
981            // This format can only be used if channel data type = CL_UNORM_INT8, CL_SNORM_INT8, CL_SIGNED_INT8 or CL_UNSIGNED_INT8:
982            ImageChannelOrder::Bgra => 4,
983            // This format can only be used if channel data type = CL_UNORM_INT8, CL_SNORM_INT8, CL_SIGNED_INT8 or CL_UNSIGNED_INT8:
984            ImageChannelOrder::Argb => 4,
985            // This format can only be used if channel data type = CL_UNORM_INT8, CL_UNORM_INT16, CL_SNORM_INT8, CL_SNORM_INT16, CL_HALF_FLOAT, or CL_FLOAT:
986            ImageChannelOrder::Intensity => 4,
987            // This format can only be used if channel data type = CL_UNORM_INT8, CL_UNORM_INT16, CL_SNORM_INT8, CL_SNORM_INT16, CL_HALF_FLOAT, or CL_FLOAT:
988            ImageChannelOrder::Luminance => 4,
989            ImageChannelOrder::Rx => 2,
990            ImageChannelOrder::Rgx => 4,
991            // This format can only be used if channel data type = CL_UNORM_SHORT_565, CL_UNORM_SHORT_555 or CL_UNORM_INT101010:
992            ImageChannelOrder::Rgbx => 4,
993            // Depth => 1,
994            // DepthStencil => 1,
995            _ => 0,
996        };
997
998        let channel_size = match self.channel_data_type {
999            // Each channel component is a normalized signed 8-bit integer value:
1000            ImageChannelDataType::SnormInt8 => 1,
1001            // Each channel component is a normalized signed 16-bit integer value:
1002            ImageChannelDataType::SnormInt16 => 2,
1003            // Each channel component is a normalized unsigned 8-bit integer value:
1004            ImageChannelDataType::UnormInt8 => 1,
1005            // Each channel component is a normalized unsigned 16-bit integer value:
1006            ImageChannelDataType::UnormInt16 => 2,
1007            // Represents a normalized 5-6-5 3-channel RGB image. The channel order must be CL_RGB or CL_RGBx:
1008            ImageChannelDataType::UnormShort565 => 2,
1009            // Represents a normalized x-5-5-5 4-channel xRGB image. The channel order must be CL_RGB or CL_RGBx:
1010            ImageChannelDataType::UnormShort555 => 2,
1011            // Represents a normalized x-10-10-10 4-channel xRGB image. The channel order must be CL_RGB or CL_RGBx:
1012            ImageChannelDataType::UnormInt101010 => 4,
1013            // Each channel component is an unnormalized signed 8-bit integer value:
1014            ImageChannelDataType::SignedInt8 => 1,
1015            // Each channel component is an unnormalized signed 16-bit integer value:
1016            ImageChannelDataType::SignedInt16 => 2,
1017            // Each channel component is an unnormalized signed 32-bit integer value:
1018            ImageChannelDataType::SignedInt32 => 4,
1019            // Each channel component is an unnormalized unsigned 8-bit integer value:
1020            ImageChannelDataType::UnsignedInt8 => 1,
1021            // Each channel component is an unnormalized unsigned 16-bit integer value:
1022            ImageChannelDataType::UnsignedInt16 => 2,
1023            // Each channel component is an unnormalized unsigned 32-bit integer value:
1024            ImageChannelDataType::UnsignedInt32 => 4,
1025            // Each channel component is a 16-bit half-float value:
1026            ImageChannelDataType::HalfFloat => 2,
1027            // Each channel component is a single precision floating-point value:
1028            ImageChannelDataType::Float => 4,
1029            // Each channel component is a normalized unsigned 24-bit integer value:
1030            // UnormInt24 => 3,
1031            _ => 0,
1032        };
1033
1034        channel_count * channel_size
1035    }
1036}
1037
1038/// An image descriptor use in the creation of `Image`.
1039///
1040/// image_type
1041/// Describes the image type and must be either CL_MEM_OBJECT_IMAGE1D, CL_MEM_OBJECT_IMAGE1D_BUFFER, CL_MEM_OBJECT_IMAGE1D_ARRAY, CL_MEM_OBJECT_IMAGE2D, CL_MEM_OBJECT_IMAGE2D_ARRAY, or CL_MEM_OBJECT_IMAGE3D.
1042///
1043/// image_width
1044/// The width of the image in pixels. For a 2D image and image array, the image width must be ≤ CL_DEVICE_IMAGE2D_MAX_WIDTH. For a 3D image, the image width must be ≤ CL_DEVICE_IMAGE3D_MAX_WIDTH. For a 1D image buffer, the image width must be ≤ CL_DEVICE_IMAGE_MAX_BUFFER_SIZE. For a 1D image and 1D image array, the image width must be ≤ CL_DEVICE_IMAGE2D_MAX_WIDTH.
1045///
1046/// image_height
1047/// The height of the image in pixels. This is only used if the image is a 2D, 3D or 2D image array. For a 2D image or image array, the image height must be ≤ CL_DEVICE_IMAGE2D_MAX_HEIGHT. For a 3D image, the image height must be ≤ CL_DEVICE_IMAGE3D_MAX_HEIGHT.
1048///
1049/// image_depth
1050/// The depth of the image in pixels. This is only used if the image is a 3D image and must be a value ≥ 1 and ≤ CL_DEVICE_IMAGE3D_MAX_DEPTH.
1051///
1052/// image_array_size
1053/// The number of images in the image array. This is only used if the image is a 1D or 2D image array. The values for image_array_size, if specified, must be a value ≥ 1 and ≤ CL_DEVICE_IMAGE_MAX_ARRAY_SIZE.
1054///
1055/// Note that reading and writing 2D image arrays from a kernel with image_array_size = 1 may be lower performance than 2D images.
1056///
1057/// image_row_pitch
1058/// The scan-line pitch in bytes. This must be 0 if host_ptr is NULL and can be either 0 or ≥ image_width * size of element in bytes if host_ptr is not NULL. If host_ptr is not NULL and image_row_pitch = 0, image_row_pitch is calculated as image_width * size of element in bytes. If image_row_pitch is not 0, it must be a multiple of the image element size in bytes.
1059///
1060/// image_slice_pitch
1061/// The size in bytes of each 2D slice in the 3D image or the size in bytes of each image in a 1D or 2D image array. This must be 0 if host_ptr is NULL. If host_ptr is not NULL, image_slice_pitch can be either 0 or ≥ image_row_pitch * image_height for a 2D image array or 3D image and can be either 0 or ≥ image_row_pitch for a 1D image array. If host_ptr is not NULL and image_slice_pitch = 0, image_slice_pitch is calculated as image_row_pitch * image_height for a 2D image array or 3D image and image_row_pitch for a 1D image array. If image_slice_pitch is not 0, it must be a multiple of the image_row_pitch.
1062///
1063/// num_mip_level, num_samples
1064/// Must be 0.
1065///
1066/// buffer
1067/// Refers to a valid buffer memory object if image_type is CL_MEM_OBJECT_IMAGE1D_BUFFER. Otherwise it must be NULL. For a 1D image buffer object, the image pixels are taken from the buffer object's data store. When the contents of a buffer object's data store are modified, those changes are reflected in the contents of the 1D image buffer object and vice-versa at corresponding sychronization points. The image_width * size of element in bytes must be ≤ size of buffer object data store.
1068///
1069/// Note
1070/// Concurrent reading from, writing to and copying between both a buffer object and 1D image buffer object associated with the buffer object is undefined. Only reading from both a buffer object and 1D image buffer object associated with the buffer object is defined.
1071#[allow(dead_code)]
1072#[derive(Debug, Clone)]
1073pub struct ImageDescriptor {
1074    pub image_type: MemObjectType,
1075    pub image_width: usize,
1076    pub image_height: usize,
1077    pub image_depth: usize,
1078    pub image_array_size: usize,
1079    pub image_row_pitch: usize,
1080    pub image_slice_pitch: usize,
1081    num_mip_levels: u32,
1082    num_samples: u32,
1083    pub buffer: Option<Mem>,
1084}
1085
1086impl ImageDescriptor {
1087    pub fn new(
1088        image_type: MemObjectType,
1089        width: usize,
1090        height: usize,
1091        depth: usize,
1092        array_size: usize,
1093        row_pitch: usize,
1094        slc_pitch: usize,
1095        buffer: Option<Mem>,
1096    ) -> ImageDescriptor {
1097        ImageDescriptor {
1098            image_type,
1099            image_width: width,
1100            image_height: height,
1101            image_depth: depth,
1102            image_array_size: array_size,
1103            image_row_pitch: row_pitch,
1104            image_slice_pitch: slc_pitch,
1105            num_mip_levels: 0,
1106            num_samples: 0,
1107            buffer,
1108        }
1109    }
1110
1111    pub fn to_raw(&self) -> ffi::cl_image_desc {
1112        ffi::cl_image_desc {
1113            image_type: self.image_type as u32,
1114            image_width: self.image_width,
1115            image_height: self.image_height,
1116            image_depth: self.image_depth,
1117            image_array_size: self.image_array_size,
1118            image_row_pitch: self.image_row_pitch,
1119            image_slice_pitch: self.image_slice_pitch,
1120            num_mip_levels: self.num_mip_levels,
1121            num_samples: self.num_mip_levels,
1122            buffer: match self.buffer {
1123                Some(ref b) => b.as_ptr(),
1124                None => 0 as cl_mem,
1125            },
1126        }
1127    }
1128}