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}