1use std::fmt;
2
3use crate::ffi::*;
4
5use crate::{
6 ClPlatformID, ClPointer, DeviceAffinityDomain, DeviceExecCapabilities, DeviceInfo,
7 DeviceLocalMemType, DeviceMemCacheType, DeviceType, Error, Output, PlatformPtr,
8 StatusCodeError, ObjectWrapper,
9};
10
11use crate::cl_helpers::{cl_get_info5, cl_get_object, cl_get_object_count};
12
13pub const UNUSABLE_DEVICE_ID: cl_device_id = 0xFFFF_FFFF as *mut usize as cl_device_id;
21
22pub const UNUSABLE_DEVICE_ERROR: Error = Error::DeviceError(DeviceError::UnusableDevice);
23
24pub const NO_PARENT_DEVICE_ERROR: Error = Error::DeviceError(DeviceError::NoParentDevice);
25
26pub fn device_usability_check(device_id: cl_device_id) -> Result<(), Error> {
27 if device_id == UNUSABLE_DEVICE_ID {
28 Err(UNUSABLE_DEVICE_ERROR)
29 } else {
30 Ok(())
31 }
32}
33
34pub fn cl_get_device_count(platform: cl_platform_id, device_type: cl_device_type) -> Output<u32> {
36 unsafe {
37 cl_get_object_count::<cl_platform_id, cl_device_type, cl_device_id>(
38 platform,
39 device_type,
40 clGetDeviceIDs,
41 )
42 }
43}
44
45pub fn list_devices_by_type(
46 platform: &ClPlatformID,
47 device_type: DeviceType,
48) -> Output<Vec<ClDeviceID>> {
49 unsafe {
50 match cl_get_object(platform.platform_ptr(), device_type.into(), clGetDeviceIDs) {
51 Ok(cl_ptr) => {
52 let devices: Vec<ClDeviceID> = cl_ptr
53 .into_vec()
54 .into_iter()
55 .map(|d| ClDeviceID::new(d))
56 .filter_map(Result::ok)
57 .collect();
58 Ok(devices)
59 }
60 Err(Error::StatusCodeError(StatusCodeError { status_code: -1 })) => Ok(vec![]),
61 Err(Error::StatusCodeError(StatusCodeError { status_code: -30 })) => Ok(vec![]),
62 Err(e) => Err(e),
63 }
64 }
65}
66
67pub unsafe fn cl_get_device_info<T>(device: cl_device_id, flag: DeviceInfo) -> Output<ClPointer<T>>
68where
69 T: Copy,
70{
71 device_usability_check(device)?;
72 cl_get_info5(device.device_ptr(), flag.into(), clGetDeviceInfo)
73}
74
75#[derive(Debug, Fail, PartialEq, Eq, Clone)]
77pub enum DeviceError {
78 #[fail(display = "Device is not in a usable state")]
79 UnusableDevice,
80
81 #[fail(display = "The given platform had no default device")]
82 NoDefaultDevice,
83
84 #[fail(display = "The given device had no parent device")]
85 NoParentDevice,
86}
87
88pub type ClDeviceID = ObjectWrapper<cl_device_id>;
89
90impl DevicePtr for ClDeviceID {
91 unsafe fn device_ptr(&self) -> cl_device_id {
92 self.cl_object()
93 }
94}
95
96impl DevicePtr for &ClDeviceID {
97 unsafe fn device_ptr(&self) -> cl_device_id {
98 self.cl_object()
99 }
100}
101
102impl DevicePtr for cl_device_id {
103 unsafe fn device_ptr(&self) -> cl_device_id {
104 *self
105 }
106}
107
108macro_rules! info_fn {
109 ($name:ident, $flag:ident, String) => {
110 fn $name(&self) -> Output<String> {
111 unsafe{
112 cl_get_device_info(self.device_ptr(), DeviceInfo::$flag)
113 .map(|ret| ret.into_string() )
114 }
115 }
116 };
117
118 ($name:ident, $flag:ident, bool) => {
119 fn $name(&self) -> Output<bool> {
120 use crate::ffi::cl_bool;
121 unsafe {
122 cl_get_device_info::<cl_bool>(self.device_ptr(), DeviceInfo::$flag).map(From::from)
123 }
124 }
125 };
126
127 ($name:ident, $flag:ident, $cl_type:ty, Vec<$output_t:ty>) => {
128 fn $name(&self) -> Output<Vec<$output_t>> {
129 unsafe {
130 cl_get_device_info(self.device_ptr(), DeviceInfo::$flag).map(|ret| ret.into_vec())
131 }
132 }
133 };
134
135 ($name:ident, $flag:ident, $output_t:ty) => {
136 fn $name(&self) -> Output<$output_t> {
137 unsafe {
138 cl_get_device_info(self.device_ptr(), DeviceInfo::$flag).map(|ret| ret.into_one())
139 }
140 }
141 };
142
143 ($name:ident, $flag:ident, $cl_type:ty, $output_t:ty) => {
144 fn $name(&self) -> Output<$output_t> {
145 unsafe {
146 cl_get_device_info(self.device_ptr(), DeviceInfo::$flag)
147 .map(|ret| ret.into_one())
148 }
149 }
150 };
151}
152
153pub trait DevicePtr
154where
155 Self: fmt::Debug + Sized,
156{
157 unsafe fn device_ptr(&self) -> cl_device_id;
158
159 fn is_usable(&self) -> bool {
160 unsafe { self.device_ptr() != UNUSABLE_DEVICE_ID }
161 }
162
163 fn usability_check(&self) -> Output<()> {
164 if self.is_usable() {
165 Ok(())
166 } else {
167 Err(DeviceError::UnusableDevice.into())
168 }
169 }
170
171 info_fn!(
172 global_mem_cacheline_size,
173 GlobalMemCachelineSize,
174 cl_uint,
175 u32
176 );
177 info_fn!(
178 native_vector_width_double,
179 NativeVectorWidthDouble,
180 cl_uint,
181 u32
182 );
183 info_fn!(
184 native_vector_width_half,
185 NativeVectorWidthHalf,
186 cl_uint,
187 u32
188 );
189 info_fn!(address_bits, AddressBits, cl_uint, u32);
190 info_fn!(max_clock_frequency, MaxClockFrequency, cl_uint, u32);
191 info_fn!(max_compute_units, MaxComputeUnits, cl_uint, u32);
192 info_fn!(max_constant_args, MaxConstantArgs, cl_uint, u32);
193 info_fn!(max_read_image_args, MaxReadImageArgs, cl_uint, u32);
194 info_fn!(max_samplers, MaxSamplers, cl_uint, u32);
195 info_fn!(
196 max_work_item_dimensions,
197 MaxWorkItemDimensions,
198 cl_uint,
199 u32
200 );
201 info_fn!(max_write_image_args, MaxWriteImageArgs, cl_uint, u32);
202 info_fn!(mem_base_addr_align, MemBaseAddrAlign, cl_uint, u32);
203 info_fn!(min_data_type_align_size, MinDataTypeAlignSize, cl_uint, u32);
204 info_fn!(
205 native_vector_width_char,
206 NativeVectorWidthChar,
207 cl_uint,
208 u32
209 );
210 info_fn!(
211 native_vector_width_short,
212 NativeVectorWidthShort,
213 cl_uint,
214 u32
215 );
216 info_fn!(native_vector_width_int, NativeVectorWidthInt, cl_uint, u32);
217 info_fn!(
218 native_vector_width_long,
219 NativeVectorWidthLong,
220 cl_uint,
221 u32
222 );
223 info_fn!(
224 native_vector_width_float,
225 NativeVectorWidthFloat,
226 cl_uint,
227 u32
228 );
229 info_fn!(
230 partition_max_sub_devices,
231 PartitionMaxSubDevices,
232 cl_uint,
233 u32
234 );
235 info_fn!(
236 preferred_vector_width_char,
237 PreferredVectorWidthChar,
238 cl_uint,
239 u32
240 );
241 info_fn!(
242 preferred_vector_width_short,
243 PreferredVectorWidthShort,
244 cl_uint,
245 u32
246 );
247 info_fn!(
248 preferred_vector_width_int,
249 PreferredVectorWidthInt,
250 cl_uint,
251 u32
252 );
253 info_fn!(
254 preferred_vector_width_long,
255 PreferredVectorWidthLong,
256 cl_uint,
257 u32
258 );
259 info_fn!(
260 preferred_vector_width_float,
261 PreferredVectorWidthFloat,
262 cl_uint,
263 u32
264 );
265 info_fn!(
266 preferred_vector_width_double,
267 PreferredVectorWidthDouble,
268 cl_uint,
269 u32
270 );
271 info_fn!(
272 preferred_vector_width_half,
273 PreferredVectorWidthHalf,
274 cl_uint,
275 u32
276 );
277 info_fn!(vendor_id, VendorId, cl_uint, u32);
278
279 info_fn!(available, Available, bool);
281 info_fn!(compiler_available, CompilerAvailable, bool);
282 info_fn!(endian_little, EndianLittle, bool);
283 info_fn!(error_correction_support, ErrorCorrectionSupport, bool);
284 info_fn!(host_unified_memory, HostUnifiedMemory, bool);
285 info_fn!(image_support, ImageSupport, bool);
286 info_fn!(linker_available, LinkerAvailable, bool);
287 info_fn!(preferred_interop_user_sync, PreferredInteropUserSync, bool);
288
289 info_fn!(name, Name, String);
291 info_fn!(opencl_c_version, OpenclCVersion, String);
292 info_fn!(profile, Profile, String);
293 info_fn!(vendor, Vendor, String);
294 info_fn!(version, Version, String);
295 info_fn!(driver_version, DriverVersion, String);
296
297 info_fn!(global_mem_cache_size, GlobalMemCacheSize, cl_ulong, u64);
299 info_fn!(global_mem_size, GlobalMemSize, cl_ulong, u64);
300 info_fn!(local_mem_size, LocalMemSize, cl_ulong, u64);
301 info_fn!(
302 max_constant_buffer_size,
303 MaxConstantBufferSize,
304 cl_ulong,
305 u64
306 );
307 info_fn!(max_mem_alloc_size, MaxMemAllocSize, cl_ulong, u64);
308
309 info_fn!(image2d_max_width, Image2DMaxWidth, size_t, usize);
311 info_fn!(image2d_max_height, Image2DMaxHeight, size_t, usize);
312 info_fn!(image3d_max_width, Image3DMaxWidth, size_t, usize);
313 info_fn!(image3d_max_height, Image3DMaxHeight, size_t, usize);
314 info_fn!(image3d_max_depth, Image3DMaxDepth, size_t, usize);
315 info_fn!(image_max_buffer_size, ImageMaxBufferSize, size_t, usize);
316 info_fn!(image_max_array_size, ImageMaxArraySize, size_t, usize);
317 info_fn!(max_parameter_size, MaxParameterSize, size_t, usize);
318 info_fn!(max_work_group_size, MaxWorkGroupSize, size_t, usize);
319 info_fn!(printf_buffer_size, PrintfBufferSize, size_t, usize);
320 info_fn!(
321 profiling_timer_resolution,
322 ProfilingTimerResolution,
323 size_t,
324 usize
325 );
326
327 info_fn!(max_work_item_sizes, MaxWorkItemSizes, size_t, Vec<usize>);
329
330 info_fn!(
332 local_mem_type,
333 LocalMemType,
334 cl_device_local_mem_type,
335 DeviceLocalMemType
336 );
337
338 info_fn!(
340 execution_capabilities,
341 ExecutionCapabilities,
342 cl_device_exec_capabilities,
343 DeviceExecCapabilities
344 );
345
346 info_fn!(
348 global_mem_cache_type,
349 GlobalMemCacheType,
350 cl_device_mem_cache_type,
351 DeviceMemCacheType
352 );
353
354 info_fn!(
356 partition_affinity_domain,
357 PartitionAffinityDomain,
358 cl_device_affinity_domain,
359 DeviceAffinityDomain
360 );
361
362 info_fn!(device_type, Type, cl_device_type, DeviceType);
364}
365
366unsafe impl Send for ClDeviceID {}
367unsafe impl Sync for ClDeviceID {}
368
369#[cfg(test)]
370mod tests {
371 use crate::ffi::*;
372 use crate::*;
373
374 #[test]
375 fn unusable_device_id_results_in_an_unusable_device_error() {
376 let unusable_device_id = 0xFFFF_FFFF as cl_device_id;
377 let error = unsafe { ClDeviceID::new(unusable_device_id) };
378 assert_eq!(error, Err(UNUSABLE_DEVICE_ERROR));
379 }
380
381 #[test]
382 fn lists_all_devices() {
383 let platform = ClPlatformID::default();
384 let devices =
385 list_devices_by_type(&platform, DeviceType::ALL).expect("Failed to list all devices");
386 assert!(devices.len() > 0);
387 }
388
389 #[test]
390 fn devices_of_many_types_can_be_listed_for_a_platform() {
391 let platform = ClPlatformID::default();
392 let _ = list_devices_by_type(&platform, DeviceType::DEFAULT)
393 .expect("Failed to list DEFAULT devices");
394 let _ =
395 list_devices_by_type(&platform, DeviceType::CPU).expect("Failed to list CPU devices");
396 let _ =
397 list_devices_by_type(&platform, DeviceType::GPU).expect("Failed to list GPU devices");
398 let _ = list_devices_by_type(&platform, DeviceType::ACCELERATOR)
399 .expect("Failed to list ACCELERATOR devices");
400 let _ = list_devices_by_type(&platform, DeviceType::CUSTOM)
401 .expect("Failed to list CUSTOM devices");
402 let _ =
403 list_devices_by_type(&platform, DeviceType::ALL).expect("Failed to list ALL devices");
404 }
405
406 #[test]
407 fn device_fmt_debug_works() {
408 ll_testing::with_each_device(|device| {
409 let formatted = format!("{:?}", device);
410 expect_method!(formatted, contains, device.address());
411 expect_method!(formatted, contains, "cl_device_id");
412 })
413 }
414}
415#[cfg(test)]
416mod device_ptr_tests {
417 use crate::*;
418
419 #[test]
420 fn device_name_works() {
421 ll_testing::with_each_device(|device| {
422 let name: String = device.name().unwrap();
423 assert!(name.len() > 0);
424 })
425 }
426
427 macro_rules! test_method {
428 ($method:ident) => {
429 paste::item! {
430 #[test]
431 fn [<$method _works>]() {
432 ll_testing::with_each_device(|device| {
433 let _result = device.$method().unwrap();
434 })
435 }
436 }
437 };
438 }
439
440 test_method!(global_mem_cacheline_size);
442 test_method!(native_vector_width_double);
443 test_method!(native_vector_width_half);
444 test_method!(address_bits);
445 test_method!(max_clock_frequency);
446 test_method!(max_compute_units);
447 test_method!(max_constant_args);
448 test_method!(max_read_image_args);
449 test_method!(max_samplers);
450 test_method!(max_work_item_dimensions);
451 test_method!(max_write_image_args);
452 test_method!(mem_base_addr_align);
453 test_method!(min_data_type_align_size);
454 test_method!(native_vector_width_char);
455 test_method!(native_vector_width_short);
456 test_method!(native_vector_width_int);
457 test_method!(native_vector_width_long);
458 test_method!(native_vector_width_float);
459 test_method!(partition_max_sub_devices);
460 test_method!(preferred_vector_width_char);
461 test_method!(preferred_vector_width_short);
462 test_method!(preferred_vector_width_int);
463 test_method!(preferred_vector_width_long);
464 test_method!(preferred_vector_width_float);
465 test_method!(preferred_vector_width_double);
466 test_method!(preferred_vector_width_half);
467 test_method!(vendor_id);
468
469 test_method!(available);
471 test_method!(compiler_available);
472 test_method!(endian_little);
473 test_method!(error_correction_support);
474 test_method!(host_unified_memory);
475 test_method!(image_support);
476 test_method!(linker_available);
477 test_method!(preferred_interop_user_sync);
478
479 test_method!(name);
481 test_method!(opencl_c_version);
482 test_method!(profile);
483 test_method!(vendor);
484 test_method!(version);
485 test_method!(driver_version);
486
487 test_method!(global_mem_cache_size);
489 test_method!(global_mem_size);
490 test_method!(local_mem_size);
491 test_method!(max_constant_buffer_size);
492 test_method!(max_mem_alloc_size);
493
494 test_method!(image2d_max_width);
496 test_method!(image2d_max_height);
497 test_method!(image3d_max_width);
498 test_method!(image3d_max_height);
499 test_method!(image3d_max_depth);
500 test_method!(image_max_buffer_size);
501 test_method!(image_max_array_size);
502 test_method!(max_parameter_size);
503 test_method!(max_work_group_size);
504 test_method!(printf_buffer_size);
505 test_method!(profiling_timer_resolution);
506
507 test_method!(max_work_item_sizes);
509
510 test_method!(local_mem_type);
512
513 test_method!(execution_capabilities);
515 test_method!(global_mem_cache_type);
517
518 test_method!(partition_affinity_domain);
520
521 test_method!(device_type);
523}