ocl/standard/
device.rs

1//! An OpenCL device identifier and related types.
2
3use crate::core::{
4    self, util, ClDeviceIdPtr, DeviceId as DeviceIdCore, DeviceInfo, DeviceInfoResult, DeviceType,
5};
6use crate::error::{Error as OclError, Result as OclResult};
7use crate::ffi::cl_device_id;
8use crate::standard::Platform;
9use std;
10use std::borrow::Borrow;
11use std::ops::{Deref, DerefMut};
12
13/// A device related error.
14#[derive(Debug, thiserror::Error)]
15pub enum DeviceError {
16    #[error("No devices found on the specified platform.")]
17    NoDevices,
18    #[error("Empty device list provided.")]
19    ResolveIdxsEmptyDeviceList,
20    #[error("An index in the resolve list is out of range (index: {idx}, max: {max})")]
21    ResolveIdxsInvalidIndex { idx: usize, max: usize },
22}
23
24// Perhaps add something like this to the `DeviceSpecifier`.
25//
26// Copied from `https://github.com/TyOverby/ocl-repro/blob/master/src/main.rs`:
27//
28// pub fn first_gpu() -> (Platform, Device) {
29//     let mut out = vec![];
30//     for plat in Platform::list() {
31//         if let Ok(all_devices) = Device::list_all(&plat) {
32//             for dev in all_devices {
33//                 out.push((plat.clone(), dev));
34//             }
35//         }
36//     }
37//
38//     // Prefer GPU
39//     out.sort_by(|&(_, ref a), &(_, ref b)| {
40//         let a_type = a.info(DeviceInfo::Type);
41//         let b_type = b.info(DeviceInfo::Type);
42//         if let (DeviceInfoResult::Type(a_type), DeviceInfoResult::Type(b_type)) = (a_type, b_type) {
43//             b_type.cmp(&a_type)
44//         } else {
45//             (0).cmp(&0)
46//         }
47//     });
48//
49//     out.first().unwrap().clone()
50// }
51
52/// Specifies [what boils down to] a list of devices.
53///
54/// The `Indices` variant is context-specific, not robust, and may lead to a
55/// panic if the context changes. It is useful for convenience only and not
56/// recommended for general use. The `WrappingIndices` variant is somewhat
57/// less dangerous but can still be somewhat machine-specific.
58///
59/// The `TypeFlags` variant is used for specifying a list of devices using a
60/// bitfield (`DeviceType`) and is the most robust / portable.
61///
62///
63/// [FIXME: Add some links to the SDK]
64///
65#[derive(Debug, Clone)]
66pub enum DeviceSpecifier {
67    All,
68    First,
69    Single(Device),
70    List(Vec<Device>),
71    Indices(Vec<usize>),
72    WrappingIndices(Vec<usize>),
73    TypeFlags(DeviceType),
74}
75
76impl DeviceSpecifier {
77    /// Returns a `DeviceSpecifier::All` variant which specifies all
78    /// devices on a platform.
79    ///
80    pub fn all(self) -> DeviceSpecifier {
81        DeviceSpecifier::All
82    }
83
84    /// Returns a `DeviceSpecifier::First` variant which specifies only
85    /// the first device on a platform.
86    ///
87    pub fn first(self) -> DeviceSpecifier {
88        DeviceSpecifier::First
89    }
90
91    /// Returns a `DeviceSpecifier::Single` variant which specifies a single
92    /// device.
93    ///
94    pub fn single(self, device: Device) -> DeviceSpecifier {
95        DeviceSpecifier::Single(device)
96    }
97
98    /// Returns a `DeviceSpecifier::List` variant which specifies a list of
99    /// devices.
100    ///
101    pub fn list(self, list: Vec<Device>) -> DeviceSpecifier {
102        DeviceSpecifier::List(list)
103    }
104
105    /// Returns a `DeviceSpecifier::Indices` variant which specifies a list of
106    /// devices by index.
107    ///
108    ///
109    /// ### Safety
110    ///
111    /// This variant is context-specific, not robust, and may lead to a panic
112    /// if the context changes. It is useful for convenience only and not
113    /// recommended for general use.
114    ///
115    /// Though using the `Indices` variant is not strictly unsafe in the usual
116    /// way (will not lead to memory bugs, etc.), it is marked unsafe as a
117    /// warning. Recommendations for a more idiomatic way to express this
118    /// potential footgun are welcome.
119    ///
120    /// Using `::wrapping_indices` is a more robust (but still potentially
121    /// non-portable) solution.
122    ///
123    pub unsafe fn indices(self, indices: Vec<usize>) -> DeviceSpecifier {
124        DeviceSpecifier::Indices(indices)
125    }
126
127    /// Returns a `DeviceSpecifier::WrappingIndices` variant, specifying a
128    /// list of devices by indices which are wrapped around (simply using the
129    /// modulo operator) so that every index is always valid.
130    ///
131    pub fn wrapping_indices(self, windices: Vec<usize>) -> DeviceSpecifier {
132        DeviceSpecifier::WrappingIndices(windices)
133    }
134
135    /// Returns a `DeviceSpecifier::TypeFlags` variant which specifies a list
136    /// of devices using a conventional bitfield.
137    ///
138    pub fn type_flags(self, flags: DeviceType) -> DeviceSpecifier {
139        DeviceSpecifier::TypeFlags(flags)
140    }
141
142    /// Returns the list of devices matching the parameters specified by this
143    /// `DeviceSpecifier`
144    ///
145    /// ### Panics
146    ///
147    /// Any device indices listed within the `Indices` variant must be within
148    /// the range of the number of devices for the platform specified by
149    /// `Platform`. If no `platform` has been specified, this behaviour is
150    /// undefined and could end up using any platform at all.
151    ///
152    pub fn to_device_list<P: Borrow<Platform>>(
153        &self,
154        platform: Option<P>,
155    ) -> OclResult<Vec<Device>> {
156        let platform = platform.map(|p| *p.borrow()).unwrap_or_default();
157
158        match *self {
159            DeviceSpecifier::All => Device::list_all(&platform).map_err(OclError::from),
160            DeviceSpecifier::First => Device::list_select(&platform, None, &[0]),
161            DeviceSpecifier::Single(ref device) => Ok(vec![*device]),
162            DeviceSpecifier::List(ref devices) => Ok(devices.clone()),
163            DeviceSpecifier::Indices(ref idx_list) => {
164                Device::list_select(&platform, None, idx_list)
165            }
166            DeviceSpecifier::WrappingIndices(ref idx_list) => {
167                Device::list_select_wrap(&platform, None, idx_list).map_err(OclError::from)
168            }
169            DeviceSpecifier::TypeFlags(flags) => {
170                Device::list(&platform, Some(flags)).map_err(OclError::from)
171            }
172        }
173    }
174}
175
176impl Default for DeviceSpecifier {
177    fn default() -> DeviceSpecifier {
178        DeviceSpecifier::All
179    }
180}
181
182impl From<usize> for DeviceSpecifier {
183    fn from(index: usize) -> DeviceSpecifier {
184        DeviceSpecifier::WrappingIndices(vec![index])
185    }
186}
187
188impl<'a> From<&'a [usize]> for DeviceSpecifier {
189    fn from(indices: &'a [usize]) -> DeviceSpecifier {
190        DeviceSpecifier::WrappingIndices(indices.into())
191    }
192}
193
194impl<'a> From<&'a Vec<usize>> for DeviceSpecifier {
195    fn from(indices: &'a Vec<usize>) -> DeviceSpecifier {
196        DeviceSpecifier::WrappingIndices(indices.clone())
197    }
198}
199
200impl<'a> From<&'a [Device]> for DeviceSpecifier {
201    fn from(devices: &'a [Device]) -> DeviceSpecifier {
202        DeviceSpecifier::List(devices.into())
203    }
204}
205
206impl<'a> From<&'a Vec<Device>> for DeviceSpecifier {
207    fn from(devices: &'a Vec<Device>) -> DeviceSpecifier {
208        DeviceSpecifier::List(devices.clone())
209    }
210}
211
212impl From<Device> for DeviceSpecifier {
213    fn from(device: Device) -> DeviceSpecifier {
214        DeviceSpecifier::Single(device)
215    }
216}
217
218impl<'a> From<&'a Device> for DeviceSpecifier {
219    fn from(device: &'a Device) -> DeviceSpecifier {
220        DeviceSpecifier::Single(*device)
221    }
222}
223
224impl From<DeviceIdCore> for DeviceSpecifier {
225    fn from(device: DeviceIdCore) -> DeviceSpecifier {
226        DeviceSpecifier::Single(device.into())
227    }
228}
229
230impl<'a> From<&'a DeviceIdCore> for DeviceSpecifier {
231    fn from(device: &'a DeviceIdCore) -> DeviceSpecifier {
232        DeviceSpecifier::Single(device.clone().into())
233    }
234}
235
236impl From<DeviceType> for DeviceSpecifier {
237    fn from(flags: DeviceType) -> DeviceSpecifier {
238        DeviceSpecifier::TypeFlags(flags)
239    }
240}
241
242/// An individual device identifier (an OpenCL device_id).
243///
244#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
245#[repr(C)]
246pub struct Device(DeviceIdCore);
247
248impl Device {
249    /// Returns the first available device on a platform.
250    pub fn first<P: Borrow<Platform>>(platform: P) -> OclResult<Device> {
251        let device_ids = core::get_device_ids(platform.borrow(), None, None)?;
252        if device_ids.is_empty() {
253            return Err(DeviceError::NoDevices.into());
254        }
255        Ok(Device(device_ids[0]))
256    }
257
258    /// Returns a single device specified by a wrapped index.
259    pub fn by_idx_wrap<P: Borrow<Platform>>(
260        platform: P,
261        device_idx_wrap: usize,
262    ) -> OclResult<Device> {
263        let device_ids = core::get_device_ids(platform.borrow(), None, None)?;
264        if device_ids.is_empty() {
265            return Err(DeviceError::NoDevices.into());
266        }
267        let wrapped_idx = device_idx_wrap % device_ids.len();
268        Ok(Device(device_ids[wrapped_idx]))
269    }
270
271    /// Returns a `DeviceSpecifier` useful for precisely specifying a set
272    /// of devices.
273    pub fn specifier() -> DeviceSpecifier {
274        DeviceSpecifier::default()
275    }
276
277    /// Resolves a list of indices into a list of valid devices.
278    ///
279    /// `devices` is the set of all indexable devices.
280    ///
281    ///
282    /// ### Errors
283    ///
284    /// All indices in `idxs` must be valid. Use `resolve_idxs_wrap` for index
285    /// lists which may contain out of bounds indices.
286    ///
287    pub fn resolve_idxs(idxs: &[usize], devices: &[Device]) -> OclResult<Vec<Device>> {
288        if devices.is_empty() {
289            return Err(DeviceError::ResolveIdxsEmptyDeviceList.into());
290        }
291        let mut result = Vec::with_capacity(idxs.len());
292        for &idx in idxs.iter() {
293            match devices.get(idx) {
294                Some(&device) => result.push(device),
295                // None => return Err(format!("Error resolving device index: '{}'. Index out of \
296                //     range. Devices avaliable: '{}'.", idx, devices.len()).into()),
297                None => {
298                    return Err(DeviceError::ResolveIdxsInvalidIndex {
299                        idx,
300                        max: devices.len(),
301                    }
302                    .into())
303                }
304            }
305        }
306        Ok(result)
307    }
308
309    /// Resolves a list of indices into a list of valid devices.
310    ///
311    /// `devices` is the set of all indexable devices.
312    ///
313    /// Wraps indices around using modulo (`%`) so that every index is valid.
314    ///
315    pub fn resolve_idxs_wrap(idxs: &[usize], devices: &[Device]) -> Vec<Device> {
316        let valid_idxs = util::wrap_vals(idxs, devices.len());
317        valid_idxs.iter().map(|&idx| devices[idx]).collect()
318    }
319
320    /// Returns a list of all devices avaliable for a given platform which
321    /// optionally match the flags set in the bitfield, `device_types`.
322    ///
323    /// Setting `device_types` to `None` will return a list of all avaliable
324    /// devices for `platform` regardless of type.
325    ///
326    ///
327    /// ### Errors
328    ///
329    /// Returns an `Err(ocl::core::Error::Status {...})` enum variant upon any
330    /// OpenCL error. Calling [`.status()`] on the returned error will return
331    /// an `Option(``[ocl::core::Status]``)` which can be unwrapped then
332    /// matched to determine the precise reason for failure.
333    ///
334    /// [`.status()`]: enum.Error.html#method.status
335    /// [`ocl::core::Status`]: enum.Status.html
336    ///
337    pub fn list<P: Borrow<Platform>>(
338        platform: P,
339        device_types: Option<DeviceType>,
340    ) -> OclResult<Vec<Device>> {
341        let list_core =
342            core::get_device_ids(platform.borrow(), device_types, None).unwrap_or(vec![]);
343        Ok(list_core.into_iter().map(Device).collect())
344    }
345
346    /// Returns a list of all devices avaliable for a given `platform`.
347    ///
348    /// Equivalent to `::list(platform, None)`.
349    ///
350    /// See [`::list`](struct.Device.html#method.list) for other
351    /// error information.
352    ///
353    pub fn list_all<P: Borrow<Platform>>(platform: P) -> OclResult<Vec<Device>> {
354        Self::list(platform, None)
355    }
356
357    /// Returns a list of devices filtered by type then selected using a
358    /// list of indices.
359    ///
360    ///
361    /// ### Errors
362    ///
363    /// All indices in `idxs` must be valid.
364    ///
365    /// See [`::list`](struct.Device.html#method.list) for other
366    /// error information.
367    ///
368    pub fn list_select<P: Borrow<Platform>>(
369        platform: P,
370        device_types: Option<DeviceType>,
371        idxs: &[usize],
372    ) -> OclResult<Vec<Device>> {
373        Self::resolve_idxs(idxs, &Self::list(platform, device_types)?)
374    }
375
376    /// Returns a list of devices filtered by type then selected using a
377    /// wrapping list of indices.
378    ///
379    /// Wraps indices around (`%`) so that every index is valid.
380    ///
381    ///
382    /// ### Errors
383    ///
384    /// See [`::list`](struct.Device.html#method.list)
385    ///
386    pub fn list_select_wrap<P: Borrow<Platform>>(
387        platform: P,
388        device_types: Option<DeviceType>,
389        idxs: &[usize],
390    ) -> OclResult<Vec<Device>> {
391        Ok(Self::resolve_idxs_wrap(
392            idxs,
393            &Self::list(platform, device_types)?,
394        ))
395    }
396
397    /// Returns a list of `Device`s from a list of `DeviceIdCore`s
398    pub fn list_from_core(mut devices: Vec<DeviceIdCore>) -> Vec<Device> {
399        use std::mem;
400        debug_assert!(mem::size_of::<DeviceIdCore>() == mem::size_of::<Device>());
401        unsafe {
402            let (ptr, len, cap) = (devices.as_mut_ptr(), devices.len(), devices.capacity());
403            mem::forget(devices);
404            Vec::from_raw_parts(ptr as *mut Device, len, cap)
405        }
406    }
407
408    /// Returns the device name.
409    pub fn name(&self) -> OclResult<String> {
410        core::get_device_info(&self.0, DeviceInfo::Name)
411            .map(|r| r.to_string())
412            .map_err(OclError::from)
413    }
414
415    /// Returns the device vendor as a string.
416    pub fn vendor(&self) -> OclResult<String> {
417        core::get_device_info(&self.0, DeviceInfo::Vendor)
418            .map(|r| r.to_string())
419            .map_err(OclError::from)
420    }
421
422    /// Returns the maximum workgroup size or an error.
423    pub fn max_wg_size(&self) -> OclResult<usize> {
424        match self.info(DeviceInfo::MaxWorkGroupSize) {
425            Ok(DeviceInfoResult::MaxWorkGroupSize(r)) => Ok(r),
426            Err(err) => Err(err),
427            _ => panic!("Device::max_wg_size: Unexpected 'DeviceInfoResult' variant."),
428        }
429    }
430
431    /// Returns the memory base address alignment offset or an error.
432    pub fn mem_base_addr_align(&self) -> OclResult<u32> {
433        match self.info(DeviceInfo::MemBaseAddrAlign) {
434            Ok(DeviceInfoResult::MemBaseAddrAlign(r)) => Ok(r),
435            Err(err) => Err(err),
436            _ => panic!("Device::mem_base_addr_align: Unexpected 'DeviceInfoResult' variant."),
437        }
438    }
439
440    /// Returns whether or not the device is available for use.
441    pub fn is_available(&self) -> OclResult<bool> {
442        match self.info(DeviceInfo::Available) {
443            Ok(DeviceInfoResult::Available(r)) => Ok(r),
444            Err(err) => Err(err),
445            _ => panic!("Device::is_available: Unexpected 'DeviceInfoResult' variant."),
446        }
447    }
448
449    /// Returns raw info about the device, as a vector of bytes. Intended for use with non-standard
450    /// OpenCL extensions.
451    pub fn info_raw(&self, info_kind: u32) -> OclResult<Vec<u8>> {
452        core::get_device_info_raw(&self.0, info_kind).map_err(OclError::from)
453    }
454
455    /// Returns info about the device.
456    pub fn info(&self, info_kind: DeviceInfo) -> OclResult<DeviceInfoResult> {
457        core::get_device_info(&self.0, info_kind).map_err(OclError::from)
458    }
459
460    /// Returns a string containing a formatted list of device properties.
461    pub fn to_string(&self) -> String {
462        self.clone().into()
463    }
464
465    /// Returns the underlying `DeviceIdCore`.
466    pub fn as_core(&self) -> &DeviceIdCore {
467        &self.0
468    }
469
470    fn fmt_info(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
471        f.debug_struct("Device")
472            .field("Type", &self.info(DeviceInfo::Type))
473            .field("VendorId", &self.info(DeviceInfo::VendorId))
474            .field("MaxComputeUnits", &self.info(DeviceInfo::MaxComputeUnits))
475            .field(
476                "MaxWorkItemDimensions",
477                &self.info(DeviceInfo::MaxWorkItemDimensions),
478            )
479            .field("MaxWorkGroupSize", &self.info(DeviceInfo::MaxWorkGroupSize))
480            .field("MaxWorkItemSizes", &self.info(DeviceInfo::MaxWorkItemSizes))
481            .field(
482                "PreferredVectorWidthChar",
483                &self.info(DeviceInfo::PreferredVectorWidthChar),
484            )
485            .field(
486                "PreferredVectorWidthShort",
487                &self.info(DeviceInfo::PreferredVectorWidthShort),
488            )
489            .field(
490                "PreferredVectorWidthInt",
491                &self.info(DeviceInfo::PreferredVectorWidthInt),
492            )
493            .field(
494                "PreferredVectorWidthLong",
495                &self.info(DeviceInfo::PreferredVectorWidthLong),
496            )
497            .field(
498                "PreferredVectorWidthFloat",
499                &self.info(DeviceInfo::PreferredVectorWidthFloat),
500            )
501            .field(
502                "PreferredVectorWidthDouble",
503                &self.info(DeviceInfo::PreferredVectorWidthDouble),
504            )
505            .field(
506                "MaxClockFrequency",
507                &self.info(DeviceInfo::MaxClockFrequency),
508            )
509            .field("AddressBits", &self.info(DeviceInfo::AddressBits))
510            .field("MaxReadImageArgs", &self.info(DeviceInfo::MaxReadImageArgs))
511            .field(
512                "MaxWriteImageArgs",
513                &self.info(DeviceInfo::MaxWriteImageArgs),
514            )
515            .field("MaxMemAllocSize", &self.info(DeviceInfo::MaxMemAllocSize))
516            .field("Image2dMaxWidth", &self.info(DeviceInfo::Image2dMaxWidth))
517            .field("Image2dMaxHeight", &self.info(DeviceInfo::Image2dMaxHeight))
518            .field("Image3dMaxWidth", &self.info(DeviceInfo::Image3dMaxWidth))
519            .field("Image3dMaxHeight", &self.info(DeviceInfo::Image3dMaxHeight))
520            .field("Image3dMaxDepth", &self.info(DeviceInfo::Image3dMaxDepth))
521            .field("ImageSupport", &self.info(DeviceInfo::ImageSupport))
522            .field("MaxParameterSize", &self.info(DeviceInfo::MaxParameterSize))
523            .field("MaxSamplers", &self.info(DeviceInfo::MaxSamplers))
524            .field("MemBaseAddrAlign", &self.info(DeviceInfo::MemBaseAddrAlign))
525            .field(
526                "MinDataTypeAlignSize",
527                &self.info(DeviceInfo::MinDataTypeAlignSize),
528            )
529            .field("SingleFpConfig", &self.info(DeviceInfo::SingleFpConfig))
530            .field(
531                "GlobalMemCacheType",
532                &self.info(DeviceInfo::GlobalMemCacheType),
533            )
534            .field(
535                "GlobalMemCachelineSize",
536                &self.info(DeviceInfo::GlobalMemCachelineSize),
537            )
538            .field(
539                "GlobalMemCacheSize",
540                &self.info(DeviceInfo::GlobalMemCacheSize),
541            )
542            .field("GlobalMemSize", &self.info(DeviceInfo::GlobalMemSize))
543            .field(
544                "MaxConstantBufferSize",
545                &self.info(DeviceInfo::MaxConstantBufferSize),
546            )
547            .field("MaxConstantArgs", &self.info(DeviceInfo::MaxConstantArgs))
548            .field("LocalMemType", &self.info(DeviceInfo::LocalMemType))
549            .field("LocalMemSize", &self.info(DeviceInfo::LocalMemSize))
550            .field(
551                "ErrorCorrectionSupport",
552                &self.info(DeviceInfo::ErrorCorrectionSupport),
553            )
554            .field(
555                "ProfilingTimerResolution",
556                &self.info(DeviceInfo::ProfilingTimerResolution),
557            )
558            .field("EndianLittle", &self.info(DeviceInfo::EndianLittle))
559            .field("Available", &self.info(DeviceInfo::Available))
560            .field(
561                "CompilerAvailable",
562                &self.info(DeviceInfo::CompilerAvailable),
563            )
564            .field(
565                "ExecutionCapabilities",
566                &self.info(DeviceInfo::ExecutionCapabilities),
567            )
568            .field("QueueProperties", &self.info(DeviceInfo::QueueProperties))
569            .field("Name", &self.info(DeviceInfo::Name))
570            .field("Vendor", &self.info(DeviceInfo::Vendor))
571            .field("DriverVersion", &self.info(DeviceInfo::DriverVersion))
572            .field("Profile", &self.info(DeviceInfo::Profile))
573            .field("Version", &self.info(DeviceInfo::Version))
574            .field("Extensions", &self.info(DeviceInfo::Extensions))
575            .field("Platform", &self.info(DeviceInfo::Platform))
576            .field("DoubleFpConfig", &self.info(DeviceInfo::DoubleFpConfig))
577            .field("HalfFpConfig", &self.info(DeviceInfo::HalfFpConfig))
578            .field(
579                "PreferredVectorWidthHalf",
580                &self.info(DeviceInfo::PreferredVectorWidthHalf),
581            )
582            .field(
583                "HostUnifiedMemory",
584                &self.info(DeviceInfo::HostUnifiedMemory),
585            )
586            .field(
587                "NativeVectorWidthChar",
588                &self.info(DeviceInfo::NativeVectorWidthChar),
589            )
590            .field(
591                "NativeVectorWidthShort",
592                &self.info(DeviceInfo::NativeVectorWidthShort),
593            )
594            .field(
595                "NativeVectorWidthInt",
596                &self.info(DeviceInfo::NativeVectorWidthInt),
597            )
598            .field(
599                "NativeVectorWidthLong",
600                &self.info(DeviceInfo::NativeVectorWidthLong),
601            )
602            .field(
603                "NativeVectorWidthFloat",
604                &self.info(DeviceInfo::NativeVectorWidthFloat),
605            )
606            .field(
607                "NativeVectorWidthDouble",
608                &self.info(DeviceInfo::NativeVectorWidthDouble),
609            )
610            .field(
611                "NativeVectorWidthHalf",
612                &self.info(DeviceInfo::NativeVectorWidthHalf),
613            )
614            .field("OpenclCVersion", &self.info(DeviceInfo::OpenclCVersion))
615            .field("LinkerAvailable", &self.info(DeviceInfo::LinkerAvailable))
616            .field("BuiltInKernels", &self.info(DeviceInfo::BuiltInKernels))
617            .field(
618                "ImageMaxBufferSize",
619                &self.info(DeviceInfo::ImageMaxBufferSize),
620            )
621            .field(
622                "ImageMaxArraySize",
623                &self.info(DeviceInfo::ImageMaxArraySize),
624            )
625            .field("ParentDevice", &self.info(DeviceInfo::ParentDevice))
626            .field(
627                "PartitionMaxSubDevices",
628                &self.info(DeviceInfo::PartitionMaxSubDevices),
629            )
630            .field(
631                "PartitionProperties",
632                &self.info(DeviceInfo::PartitionProperties),
633            )
634            .field(
635                "PartitionAffinityDomain",
636                &self.info(DeviceInfo::PartitionAffinityDomain),
637            )
638            .field("PartitionType", &self.info(DeviceInfo::PartitionType))
639            .field("ReferenceCount", &self.info(DeviceInfo::ReferenceCount))
640            .field(
641                "PreferredInteropUserSync",
642                &self.info(DeviceInfo::PreferredInteropUserSync),
643            )
644            .field("PrintfBufferSize", &self.info(DeviceInfo::PrintfBufferSize))
645            .field(
646                "ImagePitchAlignment",
647                &self.info(DeviceInfo::ImagePitchAlignment),
648            )
649            .field(
650                "ImageBaseAddressAlignment",
651                &self.info(DeviceInfo::ImageBaseAddressAlignment),
652            )
653            .finish()
654    }
655}
656
657unsafe impl ClDeviceIdPtr for Device {
658    fn as_ptr(&self) -> cl_device_id {
659        self.0.as_raw()
660    }
661}
662
663unsafe impl<'a> ClDeviceIdPtr for &'a Device {
664    fn as_ptr(&self) -> cl_device_id {
665        self.0.as_raw()
666    }
667}
668
669impl From<DeviceIdCore> for Device {
670    fn from(core: DeviceIdCore) -> Device {
671        Device(core)
672    }
673}
674
675impl From<Device> for String {
676    fn from(d: Device) -> String {
677        format!("{}", d)
678    }
679}
680
681impl From<Device> for DeviceIdCore {
682    fn from(d: Device) -> DeviceIdCore {
683        d.0
684    }
685}
686
687impl std::fmt::Display for Device {
688    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
689        self.fmt_info(f)
690    }
691}
692
693impl AsRef<Device> for Device {
694    fn as_ref(&self) -> &Device {
695        self
696    }
697}
698
699impl Deref for Device {
700    type Target = DeviceIdCore;
701
702    fn deref(&self) -> &DeviceIdCore {
703        &self.0
704    }
705}
706
707impl DerefMut for Device {
708    fn deref_mut(&mut self) -> &mut DeviceIdCore {
709        &mut self.0
710    }
711}