1use 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#[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#[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 pub fn all(self) -> DeviceSpecifier {
81 DeviceSpecifier::All
82 }
83
84 pub fn first(self) -> DeviceSpecifier {
88 DeviceSpecifier::First
89 }
90
91 pub fn single(self, device: Device) -> DeviceSpecifier {
95 DeviceSpecifier::Single(device)
96 }
97
98 pub fn list(self, list: Vec<Device>) -> DeviceSpecifier {
102 DeviceSpecifier::List(list)
103 }
104
105 pub unsafe fn indices(self, indices: Vec<usize>) -> DeviceSpecifier {
124 DeviceSpecifier::Indices(indices)
125 }
126
127 pub fn wrapping_indices(self, windices: Vec<usize>) -> DeviceSpecifier {
132 DeviceSpecifier::WrappingIndices(windices)
133 }
134
135 pub fn type_flags(self, flags: DeviceType) -> DeviceSpecifier {
139 DeviceSpecifier::TypeFlags(flags)
140 }
141
142 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#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
245#[repr(C)]
246pub struct Device(DeviceIdCore);
247
248impl Device {
249 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 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 pub fn specifier() -> DeviceSpecifier {
274 DeviceSpecifier::default()
275 }
276
277 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 => {
298 return Err(DeviceError::ResolveIdxsInvalidIndex {
299 idx,
300 max: devices.len(),
301 }
302 .into())
303 }
304 }
305 }
306 Ok(result)
307 }
308
309 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 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 pub fn list_all<P: Borrow<Platform>>(platform: P) -> OclResult<Vec<Device>> {
354 Self::list(platform, None)
355 }
356
357 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 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 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 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 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 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 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 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 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 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 pub fn to_string(&self) -> String {
462 self.clone().into()
463 }
464
465 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}