1use crate::objects::bitfields::DeviceType;
19use crate::objects::enums::{ParamValue, Size};
20use crate::objects::functions::{bytes_into_string, status_update};
21use crate::objects::structs::DeviceInfo;
22use crate::objects::traits::GetSetGo;
23use crate::objects::types::{APIResult, DeviceList, DevicePtr, PlatformPtr, Properties};
24use crate::{gen_object_list, gen_param_value, get_count, size_getter};
25use libc::c_void;
26use opencl_heads::ffi;
27use opencl_heads::ffi::{clCreateSubDevices, clGetDeviceIDs, clGetDeviceInfo};
28use opencl_heads::types::*;
29use std::ptr;
30
31pub fn get_device_ids(platform: &PlatformPtr, device_type: DeviceType) -> APIResult<DeviceList> {
32 let device_type = device_type.get();
33 let platform = platform.unwrap();
34 let device_count = get_count!(clGetDeviceIDs, platform, device_type);
35
36 if device_count == 0 {
37 Ok(Vec::default())
38 } else {
39 gen_object_list!(
40 clGetDeviceIDs,
41 DeviceList,
42 device_count,
43 platform,
44 device_type
45 )
46 }
47}
48
49pub fn get_device_info(device: &DevicePtr, param_name: cl_device_info) -> APIResult<ParamValue> {
50 type D = DeviceInfo;
51 let fn_name = "clGetDeviceInfo";
52 let device = device.unwrap();
53 size_getter!(get_device_info_size, clGetDeviceInfo);
54 match param_name {
55 D::NAME
56 | D::VENDOR
57 | D::VERSION
58 | D::PROFILE
59 | D::DRIVER_VERSION
60 | D::EXTENSIONS
61 | D::OPENCL_C_VERSION
62 | D::BUILT_IN_KERNELS
63 | D::IL_VERSION
64 | D::LATEST_CONFORMANCE_VERSION_PASSED => {
65 let size = get_device_info_size(device, param_name)?;
66 let param_value = gen_param_value!(clGetDeviceInfo, u8, device, param_name, size);
67 Ok(ParamValue::String(bytes_into_string(param_value)?))
68 }
69 D::VENDOR_ID
70 | D::MAX_COMPUTE_UNITS
71 | D::MAX_WORK_ITEM_DIMENSIONS
72 | D::PREFERRED_VECTOR_WIDTH_CHAR
73 | D::PREFERRED_VECTOR_WIDTH_SHORT
74 | D::PREFERRED_VECTOR_WIDTH_INT
75 | D::PREFERRED_VECTOR_WIDTH_LONG
76 | D::PREFERRED_VECTOR_WIDTH_FLOAT
77 | D::PREFERRED_VECTOR_WIDTH_DOUBLE
78 | D::PREFERRED_VECTOR_WIDTH_HALF
79 | D::NATIVE_VECTOR_WIDTH_CHAR
80 | D::NATIVE_VECTOR_WIDTH_SHORT
81 | D::NATIVE_VECTOR_WIDTH_INT
82 | D::NATIVE_VECTOR_WIDTH_LONG
83 | D::NATIVE_VECTOR_WIDTH_FLOAT
84 | D::NATIVE_VECTOR_WIDTH_DOUBLE
85 | D::NATIVE_VECTOR_WIDTH_HALF
86 | D::MAX_CLOCK_FREQUENCY
87 | D::ADDRESS_BITS
88 | D::MAX_READ_IMAGE_ARGS
89 | D::MAX_WRITE_IMAGE_ARGS
90 | D::MAX_READ_WRITE_IMAGE_ARGS
91 | D::MAX_SAMPLERS
92 | D::IMAGE_PITCH_ALIGNMENT
93 | D::IMAGE_BASE_ADDRESS_ALIGNMENT
94 | D::MAX_PIPE_ARGS
95 | D::PIPE_MAX_ACTIVE_RESERVATIONS
96 | D::PIPE_MAX_PACKET_SIZE
97 | D::MEM_BASE_ADDR_ALIGN
98 | D::MIN_DATA_TYPE_ALIGN_SIZE
99 | D::GLOBAL_MEM_CACHELINE_SIZE
100 | D::MAX_CONSTANT_ARGS
101 | D::QUEUE_ON_DEVICE_PREFERRED_SIZE
102 | D::QUEUE_ON_DEVICE_MAX_SIZE
103 | D::MAX_ON_DEVICE_QUEUES
104 | D::MAX_ON_DEVICE_EVENTS
105 | D::PARTITION_MAX_SUB_DEVICES
106 | D::REFERENCE_COUNT
107 | D::PREFERRED_PLATFORM_ATOMIC_ALIGNMENT
108 | D::PREFERRED_GLOBAL_ATOMIC_ALIGNMENT
109 | D::PREFERRED_LOCAL_ATOMIC_ALIGNMENT
110 | D::MAX_NUM_SUB_GROUPS
111 | D::IMAGE_SUPPORT
112 | D::ERROR_CORRECTION_SUPPORT
113 | D::HOST_UNIFIED_MEMORY
114 | D::ENDIAN_LITTLE
115 | D::AVAILABLE
116 | D::COMPILER_AVAILABLE
117 | D::LINKER_AVAILABLE
118 | D::PREFERRED_INTEROP_USER_SYNC
119 | D::SUB_GROUP_INDEPENDENT_FORWARD_PROGRESS
120 | D::NON_UNIFORM_WORK_GROUP_SUPPORT
121 | D::WORK_GROUP_COLLECTIVE_FUNCTIONS_SUPPORT
122 | D::GENERIC_ADDRESS_SPACE_SUPPORT
123 | D::PIPE_SUPPORT
124 | D::NUMERIC_VERSION
125 | D::GLOBAL_MEM_CACHE_TYPE
126 | D::LOCAL_MEM_TYPE => {
127 let param_value = gen_param_value!(clGetDeviceInfo, u32, device, param_name);
128 Ok(ParamValue::UInt(param_value))
129 }
130 D::MAX_MEM_ALLOC_SIZE
131 | D::GLOBAL_MEM_CACHE_SIZE
132 | D::GLOBAL_MEM_SIZE
133 | D::MAX_CONSTANT_BUFFER_SIZE
134 | D::LOCAL_MEM_SIZE
135 | D::TYPE
136 | D::SINGLE_FP_CONFIG
137 | D::DOUBLE_FP_CONFIG
138 | D::EXECUTION_CAPABILITIES
139 | D::QUEUE_ON_HOST_PROPERTIES
140 | D::QUEUE_ON_DEVICE_PROPERTIES
141 | D::PARTITION_AFFINITY_DOMAIN
142 | D::SVM_CAPABILITIES
143 | D::ATOMIC_MEMORY_CAPABILITIES
144 | D::ATOMIC_FENCE_CAPABILITIES
145 | D::DEVICE_ENQUEUE_CAPABILITIES => {
146 let param_value = gen_param_value!(clGetDeviceInfo, u64, device, param_name);
147 Ok(ParamValue::ULong(param_value))
148 }
149 D::ILS_WITH_VERSION
150 | D::BUILT_IN_KERNELS_WITH_VERSION
151 | D::OPENCL_C_ALL_VERSIONS
152 | D::OPENCL_C_FEATURES
153 | D::EXTENSIONS_WITH_VERSION => {
154 let size = get_device_info_size(device, param_name)?;
155 let param_value =
156 gen_param_value!(clGetDeviceInfo, cl_name_version, device, param_name, size);
157 Ok(ParamValue::NameVersion(param_value))
158 }
159 D::MAX_WORK_GROUP_SIZE
160 | D::IMAGE2D_MAX_WIDTH
161 | D::IMAGE2D_MAX_HEIGHT
162 | D::IMAGE3D_MAX_WIDTH
163 | D::IMAGE3D_MAX_HEIGHT
164 | D::IMAGE3D_MAX_DEPTH
165 | D::IMAGE_MAX_BUFFER_SIZE
166 | D::IMAGE_MAX_ARRAY_SIZE
167 | D::MAX_PARAMETER_SIZE
168 | D::MAX_GLOBAL_VARIABLE_SIZE
169 | D::GLOBAL_VARIABLE_PREFERRED_TOTAL_SIZE
170 | D::PROFILING_TIMER_RESOLUTION
171 | D::PRINTF_BUFFER_SIZE
172 | D::PREFERRED_WORK_GROUP_SIZE_MULTIPLE => {
173 let param_value = gen_param_value!(clGetDeviceInfo, usize, device, param_name);
174 Ok(ParamValue::CSize(param_value))
175 }
176 D::PLATFORM | D::PARENT_DEVICE => {
177 let param_value = gen_param_value!(clGetDeviceInfo, isize, device, param_name);
178 Ok(ParamValue::CPtr(param_value))
179 }
180 D::PARTITION_PROPERTIES | D::PARTITION_TYPE => {
181 let size = get_device_info_size(device, param_name)?;
182 let param_value = gen_param_value!(clGetDeviceInfo, isize, device, param_name, size);
183 Ok(ParamValue::ArrCPtr(param_value))
184 }
185 D::MAX_WORK_ITEM_SIZES => {
186 let size = get_device_info_size(device, param_name)?;
187 let param_value = gen_param_value!(clGetDeviceInfo, usize, device, param_name, size);
188 Ok(ParamValue::ArrCSize(param_value))
189 }
190 _ => status_update(40404, fn_name, ParamValue::default()),
191 }
192}
193
194pub fn get_device_and_host_timer(device: &DevicePtr) -> APIResult<(cl_ulong, cl_ulong)> {
195 let fn_name = "clGetDeviceAndHostTimer";
196 let mut device_timestamp = cl_ulong::default();
197 let mut host_timestamp = cl_ulong::default();
198 let status_code = unsafe {
199 ffi::clGetDeviceAndHostTimer(device.unwrap(), &mut device_timestamp, &mut host_timestamp)
200 };
201 status_update(status_code, fn_name, (device_timestamp, host_timestamp))
202}
203pub fn get_host_timer(device: &DevicePtr) -> APIResult<cl_ulong> {
224 let fn_name = "clGetHostTimer";
225 let mut host_timestamp = cl_ulong::default();
226 let status_code = unsafe { ffi::clGetHostTimer(device.unwrap(), &mut host_timestamp) };
227 status_update(status_code, fn_name, host_timestamp)
228}
229
230pub fn create_sub_devices(in_device: &DevicePtr, properties: &Properties) -> APIResult<DeviceList> {
232 let in_device = in_device.unwrap();
233 let properties = match properties {
234 Some(x) => x.as_ptr(),
235 None => ptr::null(),
236 };
237 let device_partition_count = get_count!(clCreateSubDevices, in_device, properties);
238 let device_partition_count = device_partition_count * 8;
239 gen_object_list!(
240 clCreateSubDevices,
241 DeviceList,
242 device_partition_count,
243 in_device,
244 properties
245 )
246}
247
248pub fn retain_device(device: &DevicePtr) -> APIResult<()> {
249 let fn_name = "clRetainDevice";
250 let status_code = unsafe { ffi::clRetainDevice(device.unwrap()) };
251 status_update(status_code, fn_name, ())
252}
253
254pub fn release_device(device: DevicePtr) -> APIResult<()> {
255 let fn_name = "clReleaseDevice";
256 let status_code = unsafe { ffi::clReleaseDevice(device.unwrap()) };
257 status_update(status_code, fn_name, ())
258}
259
260#[cfg(test)]
270mod tests {
271 use super::*;
272 use crate::api::platform;
273 use crate::objects::structs::{DevicePartitionProperty, PlatformInfo};
274 use crate::objects::types::PlatformPtr;
275 #[test]
276 fn test_get_device_info() {
277 let all_platforms = platform::get_platform_ids().unwrap();
278 assert_ne!(all_platforms.len(), 0);
279 let id = PlatformPtr::from_ptr(all_platforms[0], "main_fn").unwrap();
281
282 let name = platform::get_platform_info(&id, PlatformInfo::NAME).unwrap();
283 let platform_name = name.unwrap_string().unwrap();
284 assert_ne!(platform_name, "");
285 println!("CL_PLATFORM_NAME: {}", platform_name);
286
287 let device =
288 DeviceType::new(DeviceType::CPU + DeviceType::GPU + DeviceType::DEFAULT).unwrap();
289
290 let device_ids = get_device_ids(&id, device).unwrap();
292 assert!(0 < device_ids.len());
293 let device_id = DevicePtr::from_ptr(device_ids[0], "test_fn").unwrap();
295 let vendor_name = get_device_info(&device_id, DeviceInfo::VENDOR).unwrap();
296 let vendor_name = vendor_name.unwrap_string().unwrap();
297 println!("CL_DEVICE_VENDOR_NAME: {}", vendor_name);
298 assert_ne!(vendor_name, "");
299 let vendor_id = get_device_info(&device_id, DeviceInfo::VENDOR_ID).unwrap();
300 let vendor_id = vendor_id.unwrap_uint().unwrap();
301 println!("CL_DEVICE_VENDOR_ID: {:X}", vendor_id);
302 assert_ne!(vendor_id, 0);
303 }
304
305 #[test]
306 #[ignore]
307 fn test_create_sub_device() {
308 let all_platforms = platform::get_platform_ids().unwrap();
309 assert_ne!(all_platforms.len(), 0);
310 let id = PlatformPtr::from_ptr(all_platforms[0], "main_fn").unwrap();
311
312 let name = platform::get_platform_info(&id, PlatformInfo::NAME).unwrap();
313 let platform_name = name.unwrap_string().unwrap();
314 assert_ne!(platform_name, "");
315 println!("CL_PLATFORM_NAME: {}", platform_name);
316
317 let device =
318 DeviceType::new(DeviceType::CPU + DeviceType::GPU + DeviceType::DEFAULT).unwrap();
319
320 let device_ids = get_device_ids(&id, device).unwrap();
321 assert!(0 < device_ids.len());
322 let device_id = DevicePtr::from_ptr(device_ids[0], "test_fn").unwrap();
325 let vendor_name =
326 get_device_info(&device_id, DeviceInfo::PARTITION_MAX_SUB_DEVICES).unwrap();
327 let max_sub_devices = vendor_name.unwrap_uint().unwrap();
328 println!("CL_DEVICE_COMPUTE_UNITS: {}", max_sub_devices);
329
330 if max_sub_devices > 1 {
331 let sub_cu_count = max_sub_devices / 4;
332 let properties = DevicePartitionProperty.equally(sub_cu_count);
333
334 let sub_device_list = match create_sub_devices(&device_id, &properties) {
335 Ok(x) => x,
336 Err(x) => {
337 eprintln!("{}", x);
338 Vec::new()
339 }
340 };
341 println!("CL_DEVICE_LIST: {:?}", sub_device_list);
342 assert!(0 < sub_device_list.len());
343 }
344 }
345}