use std;
use std::ops::{Deref, DerefMut};
use std::convert::Into;
use std::error::Error;
use error::{Error as OclError, Result as OclResult};
use standard::Platform;
use core::{self, DeviceId as DeviceIdCore, DeviceType, DeviceInfo, DeviceInfoResult, ClDeviceIdPtr};
use util;
const DEBUG_PRINT: bool = false;
#[derive(Debug, Clone)]
pub enum DeviceSpecifier {
All,
First,
Single(Device),
List(Vec<Device>),
Indices(Vec<usize>),
WrappingIndices(Vec<usize>),
TypeFlags(DeviceType),
}
impl DeviceSpecifier {
pub fn all(self) -> DeviceSpecifier {
DeviceSpecifier::All
}
pub fn first(self) -> DeviceSpecifier {
DeviceSpecifier::First
}
pub fn single(self, device: Device) -> DeviceSpecifier {
DeviceSpecifier::Single(device)
}
pub fn list(self, list: Vec<Device>) -> DeviceSpecifier {
DeviceSpecifier::List(list)
}
pub fn indices(self, indices: Vec<usize>) -> DeviceSpecifier {
DeviceSpecifier::Indices(indices)
}
pub fn wrapping_indices(self, windices: Vec<usize>) -> DeviceSpecifier {
DeviceSpecifier::WrappingIndices(windices)
}
pub fn type_flags(self, flags: DeviceType) -> DeviceSpecifier {
DeviceSpecifier::TypeFlags(flags)
}
pub fn to_device_list(&self, platform: Option<Platform>) -> OclResult<Vec<Device>> {
let platform = match platform {
Some(p) => p.clone(),
None => Platform::default(),
};
Ok(match self {
&DeviceSpecifier::All => {
Device::list_all(&platform)
},
&DeviceSpecifier::First => {
try!(Device::list_select(&platform, None, &vec![0]))
},
&DeviceSpecifier::Single(ref device) => {
vec![device.clone()]
},
&DeviceSpecifier::List(ref devices) => {
devices.clone()
},
&DeviceSpecifier::Indices(ref idx_list) => {
try!(Device::list_select(&platform, None, idx_list))
},
&DeviceSpecifier::WrappingIndices(ref idx_list) => {
Device::list_select_wrap(&platform, None, idx_list)
},
&DeviceSpecifier::TypeFlags(flags) => {
Device::list(&platform, Some(flags))
},
})
}
}
impl Default for DeviceSpecifier {
fn default() -> DeviceSpecifier {
DeviceSpecifier::All
}
}
impl From<usize> for DeviceSpecifier {
fn from(index: usize) -> DeviceSpecifier {
DeviceSpecifier::WrappingIndices(vec![index])
}
}
impl<'a> From<&'a [usize]> for DeviceSpecifier {
fn from(indices: &'a [usize]) -> DeviceSpecifier {
DeviceSpecifier::WrappingIndices(indices.into())
}
}
impl<'a> From<&'a Vec<usize>> for DeviceSpecifier {
fn from(indices: &'a Vec<usize>) -> DeviceSpecifier {
DeviceSpecifier::WrappingIndices(indices.clone())
}
}
impl<'a> From<&'a [Device]> for DeviceSpecifier {
fn from(devices: &'a [Device]) -> DeviceSpecifier {
DeviceSpecifier::List(devices.into())
}
}
impl<'a> From<&'a Vec<Device>> for DeviceSpecifier {
fn from(devices: &'a Vec<Device>) -> DeviceSpecifier {
DeviceSpecifier::List(devices.clone())
}
}
impl From<Device> for DeviceSpecifier {
fn from(device: Device) -> DeviceSpecifier {
DeviceSpecifier::Single(device)
}
}
impl<'a> From<&'a Device> for DeviceSpecifier {
fn from(device: &'a Device) -> DeviceSpecifier {
DeviceSpecifier::Single(device.clone())
}
}
impl From<DeviceType> for DeviceSpecifier {
fn from(flags: DeviceType) -> DeviceSpecifier {
DeviceSpecifier::TypeFlags(flags)
}
}
#[derive(Clone, Copy, Debug)]
pub struct Device(DeviceIdCore);
impl Device {
pub fn first(platform: Platform) -> Device {
let first_core = core::get_device_ids(&platform, None, None)
.expect("ocl::Device::first: Error retrieving device list");
Device(first_core[0])
}
pub fn specifier() -> DeviceSpecifier {
DeviceSpecifier::default()
}
pub fn resolve_idxs(idxs: &[usize], devices: &[Device]) -> OclResult<Vec<Device>> {
let mut result = Vec::with_capacity(idxs.len());
for &idx in idxs.iter() {
match devices.get(idx) {
Some(&device) => result.push(device),
None => return OclError::err(format!("Error resolving device index: '{}'. Index out of \
range. Devices avaliable: '{}'.", idx, devices.len())),
}
}
Ok(result)
}
pub fn resolve_idxs_wrap(idxs: &[usize], devices: &[Device]) -> Vec<Device> {
let valid_idxs = util::wrap_vals(idxs, devices.len());
valid_idxs.iter().map(|&idx| devices[idx]).collect()
}
pub fn list(platform: &Platform, device_types: Option<DeviceType>) -> Vec<Device> {
let list_core = core::get_device_ids(platform.as_core(), device_types, None)
.expect("Device::list: Error retrieving device list");
let list = list_core.into_iter().map(|pr| Device(pr) ).collect();
if DEBUG_PRINT { println!("Devices::list(): device_types: {:?} -> list: {:?}",
device_types, list); }
list
}
pub fn list_all(platform: &Platform) -> Vec<Device> {
Self::list(platform, None)
}
pub fn list_select(platform: &Platform, device_types: Option<DeviceType>,
idxs: &[usize]) -> OclResult<Vec<Device>>
{
Self::resolve_idxs(idxs, &Self::list(platform, device_types))
}
pub fn list_select_wrap(platform: &Platform, device_types: Option<DeviceType>,
idxs: &[usize]) -> Vec<Device>
{
let list = Self::resolve_idxs_wrap(idxs, &Self::list(platform, device_types));
if DEBUG_PRINT { println!("Devices::list_select_wrap(): device_types: {:?} \
-> list: {:?}", device_types, list); }
list
}
pub fn list_from_core(devices: Vec<DeviceIdCore>) -> Vec<Device> {
devices.into_iter().map(|p| Device(p)).collect()
}
pub fn name(&self) -> String {
core::get_device_info(&self.0, DeviceInfo::Name).into()
}
pub fn vendor(&self) -> String {
core::get_device_info(&self.0, DeviceInfo::Vendor).into()
}
pub fn max_wg_size(&self) -> usize {
match self.info(DeviceInfo::MaxWorkGroupSize) {
DeviceInfoResult::MaxWorkGroupSize(s) => s,
DeviceInfoResult::Error(err) => panic!("ocl::Device::max_wg_size: {}", err.description()),
_ => panic!("ocl::Device::max_wg_size: Unexpected 'DeviceInfoResult' variant."),
}
}
pub fn info(&self, info_kind: DeviceInfo) -> DeviceInfoResult {
core::get_device_info(&self.0, info_kind)
}
pub fn to_string(&self) -> String {
self.clone().into()
}
pub fn as_core(&self) -> &DeviceIdCore {
&self.0
}
fn fmt_info(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
f.debug_struct("Device")
.field("Type", &self.info(DeviceInfo::Type))
.field("VendorId", &self.info(DeviceInfo::VendorId))
.field("MaxComputeUnits", &self.info(DeviceInfo::MaxComputeUnits))
.field("MaxWorkItemDimensions", &self.info(DeviceInfo::MaxWorkItemDimensions))
.field("MaxWorkGroupSize", &self.info(DeviceInfo::MaxWorkGroupSize))
.field("MaxWorkItemSizes", &self.info(DeviceInfo::MaxWorkItemSizes))
.field("PreferredVectorWidthChar", &self.info(DeviceInfo::PreferredVectorWidthChar))
.field("PreferredVectorWidthShort", &self.info(DeviceInfo::PreferredVectorWidthShort))
.field("PreferredVectorWidthInt", &self.info(DeviceInfo::PreferredVectorWidthInt))
.field("PreferredVectorWidthLong", &self.info(DeviceInfo::PreferredVectorWidthLong))
.field("PreferredVectorWidthFloat", &self.info(DeviceInfo::PreferredVectorWidthFloat))
.field("PreferredVectorWidthDouble", &self.info(DeviceInfo::PreferredVectorWidthDouble))
.field("MaxClockFrequency", &self.info(DeviceInfo::MaxClockFrequency))
.field("AddressBits", &self.info(DeviceInfo::AddressBits))
.field("MaxReadImageArgs", &self.info(DeviceInfo::MaxReadImageArgs))
.field("MaxWriteImageArgs", &self.info(DeviceInfo::MaxWriteImageArgs))
.field("MaxMemAllocSize", &self.info(DeviceInfo::MaxMemAllocSize))
.field("Image2dMaxWidth", &self.info(DeviceInfo::Image2dMaxWidth))
.field("Image2dMaxHeight", &self.info(DeviceInfo::Image2dMaxHeight))
.field("Image3dMaxWidth", &self.info(DeviceInfo::Image3dMaxWidth))
.field("Image3dMaxHeight", &self.info(DeviceInfo::Image3dMaxHeight))
.field("Image3dMaxDepth", &self.info(DeviceInfo::Image3dMaxDepth))
.field("ImageSupport", &self.info(DeviceInfo::ImageSupport))
.field("MaxParameterSize", &self.info(DeviceInfo::MaxParameterSize))
.field("MaxSamplers", &self.info(DeviceInfo::MaxSamplers))
.field("MemBaseAddrAlign", &self.info(DeviceInfo::MemBaseAddrAlign))
.field("MinDataTypeAlignSize", &self.info(DeviceInfo::MinDataTypeAlignSize))
.field("SingleFpConfig", &self.info(DeviceInfo::SingleFpConfig))
.field("GlobalMemCacheType", &self.info(DeviceInfo::GlobalMemCacheType))
.field("GlobalMemCachelineSize", &self.info(DeviceInfo::GlobalMemCachelineSize))
.field("GlobalMemCacheSize", &self.info(DeviceInfo::GlobalMemCacheSize))
.field("GlobalMemSize", &self.info(DeviceInfo::GlobalMemSize))
.field("MaxConstantBufferSize", &self.info(DeviceInfo::MaxConstantBufferSize))
.field("MaxConstantArgs", &self.info(DeviceInfo::MaxConstantArgs))
.field("LocalMemType", &self.info(DeviceInfo::LocalMemType))
.field("LocalMemSize", &self.info(DeviceInfo::LocalMemSize))
.field("ErrorCorrectionSupport", &self.info(DeviceInfo::ErrorCorrectionSupport))
.field("ProfilingTimerResolution", &self.info(DeviceInfo::ProfilingTimerResolution))
.field("EndianLittle", &self.info(DeviceInfo::EndianLittle))
.field("Available", &self.info(DeviceInfo::Available))
.field("CompilerAvailable", &self.info(DeviceInfo::CompilerAvailable))
.field("ExecutionCapabilities", &self.info(DeviceInfo::ExecutionCapabilities))
.field("QueueProperties", &self.info(DeviceInfo::QueueProperties))
.field("Name", &self.info(DeviceInfo::Name))
.field("Vendor", &self.info(DeviceInfo::Vendor))
.field("DriverVersion", &self.info(DeviceInfo::DriverVersion))
.field("Profile", &self.info(DeviceInfo::Profile))
.field("Version", &self.info(DeviceInfo::Version))
.field("Extensions", &self.info(DeviceInfo::Extensions))
.field("Platform", &self.info(DeviceInfo::Platform))
.field("DoubleFpConfig", &self.info(DeviceInfo::DoubleFpConfig))
.field("HalfFpConfig", &self.info(DeviceInfo::HalfFpConfig))
.field("PreferredVectorWidthHalf", &self.info(DeviceInfo::PreferredVectorWidthHalf))
.field("HostUnifiedMemory", &self.info(DeviceInfo::HostUnifiedMemory))
.field("NativeVectorWidthChar", &self.info(DeviceInfo::NativeVectorWidthChar))
.field("NativeVectorWidthShort", &self.info(DeviceInfo::NativeVectorWidthShort))
.field("NativeVectorWidthInt", &self.info(DeviceInfo::NativeVectorWidthInt))
.field("NativeVectorWidthLong", &self.info(DeviceInfo::NativeVectorWidthLong))
.field("NativeVectorWidthFloat", &self.info(DeviceInfo::NativeVectorWidthFloat))
.field("NativeVectorWidthDouble", &self.info(DeviceInfo::NativeVectorWidthDouble))
.field("NativeVectorWidthHalf", &self.info(DeviceInfo::NativeVectorWidthHalf))
.field("OpenclCVersion", &self.info(DeviceInfo::OpenclCVersion))
.field("LinkerAvailable", &self.info(DeviceInfo::LinkerAvailable))
.field("BuiltInKernels", &self.info(DeviceInfo::BuiltInKernels))
.field("ImageMaxBufferSize", &self.info(DeviceInfo::ImageMaxBufferSize))
.field("ImageMaxArraySize", &self.info(DeviceInfo::ImageMaxArraySize))
.field("ParentDevice", &self.info(DeviceInfo::ParentDevice))
.field("PartitionMaxSubDevices", &self.info(DeviceInfo::PartitionMaxSubDevices))
.field("PartitionProperties", &self.info(DeviceInfo::PartitionProperties))
.field("PartitionAffinityDomain", &self.info(DeviceInfo::PartitionAffinityDomain))
.field("PartitionType", &self.info(DeviceInfo::PartitionType))
.field("ReferenceCount", &self.info(DeviceInfo::ReferenceCount))
.field("PreferredInteropUserSync", &self.info(DeviceInfo::PreferredInteropUserSync))
.field("PrintfBufferSize", &self.info(DeviceInfo::PrintfBufferSize))
.field("ImagePitchAlignment", &self.info(DeviceInfo::ImagePitchAlignment))
.field("ImageBaseAddressAlignment", &self.info(DeviceInfo::ImageBaseAddressAlignment))
.finish()
}
}
unsafe impl ClDeviceIdPtr for Device {}
impl Into<String> for Device {
fn into(self) -> String {
format!("{}", self)
}
}
impl Into<DeviceIdCore> for Device {
fn into(self) -> DeviceIdCore {
self.0
}
}
impl std::fmt::Display for Device {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
self.fmt_info(f)
}
}
impl AsRef<Device> for Device {
fn as_ref(&self) -> &Device {
self
}
}
impl Deref for Device {
type Target = DeviceIdCore;
fn deref(&self) -> &DeviceIdCore {
&self.0
}
}
impl DerefMut for Device {
fn deref_mut(&mut self) -> &mut DeviceIdCore {
&mut self.0
}
}