cl3/
platform.rs

1// Copyright (c) 2020-2025 Via Technology Ltd.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//    http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! `OpenCL` Platform API.
16
17#![allow(unused_unsafe)]
18#![allow(non_camel_case_types)]
19#![allow(clippy::wildcard_in_or_patterns)]
20
21pub use opencl_sys::{
22    CL_PLATFORM_EXTENSIONS, CL_PLATFORM_EXTENSIONS_WITH_VERSION,
23    CL_PLATFORM_EXTERNAL_MEMORY_IMPORT_HANDLE_TYPES_KHR, CL_PLATFORM_HOST_TIMER_RESOLUTION,
24    CL_PLATFORM_NAME, CL_PLATFORM_NUMERIC_VERSION, CL_PLATFORM_PROFILE,
25    CL_PLATFORM_SEMAPHORE_EXPORT_HANDLE_TYPES_KHR, CL_PLATFORM_SEMAPHORE_IMPORT_HANDLE_TYPES_KHR,
26    CL_PLATFORM_SEMAPHORE_TYPES_KHR, CL_PLATFORM_VENDOR, CL_PLATFORM_VERSION, CL_SUCCESS, cl_int,
27    cl_name_version, cl_platform_id, cl_platform_info, cl_uint, cl_ulong, cl_version,
28};
29
30#[allow(unused_imports)]
31use super::error_codes::DLOPEN_FUNCTION_NOT_AVAILABLE;
32use super::info_type::InfoType;
33use super::{api_info_size, api_info_value, api_info_vector};
34
35use libc::{c_void, size_t};
36use std::mem;
37use std::ptr;
38
39/// Get the available platforms.
40/// Calls clGetPlatformIDs to get the available platform ids.
41///  # Examples
42/// ```
43/// use cl3::platform::get_platform_ids;
44///
45/// let platform_ids = get_platform_ids().unwrap();
46/// println!("Number of `OpenCL` platforms: {}", platform_ids.len());
47/// assert!(0 < platform_ids.len());
48/// ```
49/// returns a Result containing a vector of available platform ids
50/// or the error code from the `OpenCL` C API function.
51#[allow(unused_unsafe)]
52pub fn get_platform_ids() -> Result<Vec<cl_platform_id>, cl_int> {
53    // Get the number of platforms
54    let mut count: cl_uint = 0;
55    let mut status = unsafe { cl_call!(clGetPlatformIDs(0, ptr::null_mut(), &raw mut count)) };
56
57    if CL_SUCCESS != status {
58        Err(status)
59    } else if 0 < count {
60        // Get the platform ids.
61        let len = count as usize;
62        let mut ids: Vec<cl_platform_id> = Vec::with_capacity(len);
63        unsafe {
64            status = cl_call!(clGetPlatformIDs(count, ids.as_mut_ptr(), ptr::null_mut()));
65            ids.set_len(len);
66        };
67
68        if CL_SUCCESS == status {
69            Ok(ids)
70        } else {
71            Err(status)
72        }
73    } else {
74        Ok(Vec::default())
75    }
76}
77
78/// Get data about an `OpenCL` platform.
79/// Calls clGetPlatformInfo to get the desired data about the platform.
80pub fn get_platform_data(
81    platform: cl_platform_id,
82    param_name: cl_platform_info,
83) -> Result<Vec<u8>, cl_int> {
84    api_info_size!(get_size, clGetPlatformInfo);
85    let size = get_size(platform, param_name)?;
86    api_info_vector!(get_vector, u8, clGetPlatformInfo);
87    get_vector(platform, param_name, size)
88}
89
90/// Get specific information about an `OpenCL` platform.
91/// Calls `clGetPlatformInfo` to get the desired information about the platform.
92///
93///  # Examples
94/// ```
95/// use cl3::platform::{get_platform_ids, get_platform_info, CL_PLATFORM_NAME, CL_PLATFORM_VERSION};
96///
97/// let platform_ids = get_platform_ids().unwrap();
98/// assert!(0 < platform_ids.len());
99///
100/// // Choose a the first platform
101/// let platform_id = platform_ids[0];
102///
103/// let value = get_platform_info(platform_id, CL_PLATFORM_NAME).unwrap();
104/// let value: String = value.into();
105/// println!("CL_PLATFORM_NAME: {}", value);
106/// assert!(!value.is_empty());
107///
108/// let value = get_platform_info(platform_id, CL_PLATFORM_VERSION).unwrap();
109/// let value = String::from(value);
110/// println!("CL_PLATFORM_VERSION: {}", value);
111/// assert!(!value.is_empty());
112/// ```
113/// * `platform` - the `cl_platform_id` of the `OpenCL` platform.
114/// * `param_name` - the type of platform information being queried, see
115///   [Platform Queries](https://www.khronos.org/registry/OpenCL/specs/3.0-unified/html/OpenCL_API.html#platform-queries-table).
116///
117/// returns a Result containing the desired information in an `InfoType` enum
118/// or the error code from the `OpenCL` C API function.
119pub fn get_platform_info(
120    platform: cl_platform_id,
121    param_name: cl_platform_info,
122) -> Result<InfoType, cl_int> {
123    match param_name {
124        // CL_VERSION_3_0
125        CL_PLATFORM_NUMERIC_VERSION => {
126            api_info_value!(get_value, cl_uint, clGetPlatformInfo);
127            Ok(InfoType::Uint(get_value(platform, param_name)?))
128        }
129
130        // CL_VERSION_2_1
131        CL_PLATFORM_HOST_TIMER_RESOLUTION => {
132            api_info_value!(get_value, cl_ulong, clGetPlatformInfo);
133            Ok(InfoType::Ulong(get_value(platform, param_name)?))
134        }
135
136        // CL_VERSION_3_0
137        CL_PLATFORM_EXTENSIONS_WITH_VERSION => {
138            api_info_size!(get_size, clGetPlatformInfo);
139            let size = get_size(platform, param_name)?;
140            api_info_vector!(get_vec, cl_name_version, clGetPlatformInfo);
141            Ok(InfoType::VecNameVersion(get_vec(
142                platform, param_name, size,
143            )?))
144        }
145
146        CL_PLATFORM_EXTERNAL_MEMORY_IMPORT_HANDLE_TYPES_KHR // cl_khr_external_memory
147        | CL_PLATFORM_SEMAPHORE_IMPORT_HANDLE_TYPES_KHR // cl_khr_external_semaphore
148        | CL_PLATFORM_SEMAPHORE_EXPORT_HANDLE_TYPES_KHR // cl_khr_external_semaphore
149        | CL_PLATFORM_SEMAPHORE_TYPES_KHR // cl_khr_semaphore
150        => {
151            api_info_size!(get_size, clGetPlatformInfo);
152            api_info_vector!(get_vec, cl_uint, clGetPlatformInfo);
153            let size = get_size(platform, param_name)?;
154            Ok(InfoType::VecUshort(get_vec(platform, param_name, size)?))
155        }
156
157        CL_PLATFORM_PROFILE
158        | CL_PLATFORM_VERSION
159        | CL_PLATFORM_NAME
160        | CL_PLATFORM_VENDOR
161        | CL_PLATFORM_EXTENSIONS
162        | _ => Ok(InfoType::VecUchar(get_platform_data(platform, param_name)?)),
163    }
164}
165
166#[cfg(test)]
167mod tests {
168    use super::*;
169    use crate::error_codes::error_text;
170
171    #[test]
172    fn test_get_platform_info() {
173        let platform_ids = get_platform_ids().unwrap();
174        println!("Number of platforms: {}", platform_ids.len());
175        assert!(0 < platform_ids.len());
176
177        // Choose the first platform
178        let platform_id = platform_ids[0];
179
180        let value = get_platform_info(platform_id, CL_PLATFORM_PROFILE).unwrap();
181        let value: String = value.into();
182        println!("CL_PLATFORM_PROFILE: {}", value);
183        assert!(!value.is_empty());
184
185        let value = get_platform_info(platform_id, CL_PLATFORM_VERSION).unwrap();
186        let value: String = value.into();
187        println!("CL_PLATFORM_VERSION: {}", value);
188        assert!(!value.is_empty());
189
190        let value = get_platform_info(platform_id, CL_PLATFORM_NAME).unwrap();
191        let value: String = value.into();
192        println!("CL_PLATFORM_NAME: {}", value);
193        assert!(!value.is_empty());
194
195        let value = get_platform_info(platform_id, CL_PLATFORM_VENDOR).unwrap();
196        let value: String = value.into();
197        println!("CL_PLATFORM_VENDOR: {}", value);
198        assert!(!value.is_empty());
199
200        let value = get_platform_info(platform_id, CL_PLATFORM_EXTENSIONS).unwrap();
201        let value: String = value.into();
202        println!("CL_PLATFORM_EXTENSIONS: {}", value);
203        assert!(!value.is_empty());
204
205        // CL_VERSION_2_1 value, may not be supported
206        match get_platform_info(platform_id, CL_PLATFORM_HOST_TIMER_RESOLUTION) {
207            Ok(value) => {
208                let value = cl_ulong::from(value);
209                println!("CL_PLATFORM_HOST_TIMER_RESOLUTION: {}", value)
210            }
211            Err(e) => println!(
212                "OpenCL error, CL_PLATFORM_HOST_TIMER_RESOLUTION: {}",
213                error_text(e)
214            ),
215        };
216    }
217
218    #[test]
219    fn test_get_platform_info_3_0() {
220        let platform_ids = get_platform_ids().unwrap();
221
222        // Choose the first platform with an OpenCL 3 version
223        let opencl_3: &str = "OpenCL 3";
224        let mut platform_3: Option<cl_platform_id> = None;
225        for id in platform_ids {
226            let value = get_platform_info(id, CL_PLATFORM_VERSION).unwrap();
227            let value: String = value.into();
228            if value.contains(opencl_3) {
229                platform_3 = Some(id);
230                break;
231            }
232        }
233
234        if let Some(platform_id) = platform_3 {
235            let value = get_platform_info(platform_id, CL_PLATFORM_NUMERIC_VERSION).unwrap();
236            let value = cl_uint::from(value);
237            println!("CL_PLATFORM_NUMERIC_VERSION: {}", value);
238            assert!(0 < value);
239
240            let value =
241                get_platform_info(platform_id, CL_PLATFORM_EXTENSIONS_WITH_VERSION).unwrap();
242            println!("CL_PLATFORM_EXTENSIONS_WITH_VERSION: {}", value);
243
244            let value = Vec::<cl_name_version>::from(value);
245            println!("CL_PLATFORM_EXTENSIONS_WITH_VERSION count: {}", value.len());
246            assert!(0 < value.len());
247        }
248    }
249}