opencl_api/api/
queue.rs

1/*
2 * queue.rs - Command Queue APIs (Part of OpenCL Runtime Layer).
3 *
4 * Copyright 2020-2021 Naman Bishnoi
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 *     http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17*/
18//! Considering OpenCL 1.x as base.
19
20// use crate::enums::Status;
21use crate::objects::bitfields::CommandQueueProperties;
22use crate::objects::enums::{ParamValue, Size};
23use crate::objects::functions::status_update;
24use crate::objects::structs::{CommandQueueInfo, StatusCode};
25use crate::objects::traits::GetSetGo;
26use crate::objects::types::{APIResult, ContextPtr, DevicePtr, LongProperties, QueuePtr};
27use crate::{gen_param_value, size_getter};
28use libc::c_void;
29use opencl_heads::ffi;
30use opencl_heads::ffi::clGetCommandQueueInfo;
31use opencl_heads::types::*;
32use std::ptr;
33
34// #[cfg(feature = "depr_2_0")]
35pub fn create_command_queue(
36    context: &ContextPtr,
37    device: &DevicePtr,
38    properties: &CommandQueueProperties,
39) -> APIResult<QueuePtr> {
40    let fn_name = "clCreateCommandQueue";
41    let mut status_code: cl_int = StatusCode::INVALID_COMMAND_QUEUE;
42    let queue_ptr = unsafe {
43        ffi::clCreateCommandQueue(
44            context.unwrap(),
45            device.unwrap(),
46            properties.get(),
47            &mut status_code,
48        )
49    };
50    status_update(
51        status_code,
52        fn_name,
53        QueuePtr::from_ptr(queue_ptr, fn_name)?,
54    )
55}
56
57pub fn create_command_queue_with_properties(
58    context: &ContextPtr,
59    device: &DevicePtr,
60    properties: &LongProperties,
61) -> APIResult<QueuePtr> {
62    let fn_name = "clCreateCommandQueueWithProperties";
63    let mut status_code: cl_int = StatusCode::INVALID_COMMAND_QUEUE;
64    let properties = match properties {
65        Some(x) => x.as_ptr(),
66        None => ptr::null(),
67    };
68    let queue_ptr = unsafe {
69        ffi::clCreateCommandQueueWithProperties(
70            context.unwrap(),
71            device.unwrap(),
72            properties,
73            &mut status_code,
74        )
75    };
76    status_update(
77        status_code,
78        fn_name,
79        QueuePtr::from_ptr(queue_ptr, fn_name)?,
80    )
81}
82
83pub fn set_default_device_command_queue(
84    context: &ContextPtr,
85    device: &DevicePtr,
86    command_queue: &QueuePtr,
87) -> APIResult<()> {
88    let status_code = unsafe {
89        ffi::clSetDefaultDeviceCommandQueue(
90            context.unwrap(),
91            device.unwrap(),
92            command_queue.unwrap(),
93        )
94    };
95    status_update(status_code, "clSetDefaultDeviceCommandQueue", ())
96}
97
98pub fn retain_command_queue(command_queue: &QueuePtr) -> APIResult<()> {
99    let status_code = unsafe { ffi::clRetainCommandQueue(command_queue.unwrap()) };
100    status_update(status_code, "clRetainCommandQueue", ())
101}
102
103pub fn release_command_queue(command_queue: QueuePtr) -> APIResult<()> {
104    let status_code = unsafe { ffi::clReleaseCommandQueue(command_queue.unwrap()) };
105    status_update(status_code, "clReleaseCommandQueue", ())
106}
107
108pub fn get_command_queue_info(
109    command_queue: &QueuePtr,
110    param_name: cl_command_queue_info,
111) -> APIResult<ParamValue> {
112    let command_queue = command_queue.unwrap();
113    size_getter!(get_command_queue_info_size, clGetCommandQueueInfo);
114    match param_name {
115        CommandQueueInfo::CONTEXT | CommandQueueInfo::DEVICE | CommandQueueInfo::DEVICE_DEFAULT => {
116            let param_value =
117                gen_param_value!(clGetCommandQueueInfo, isize, command_queue, param_name);
118            Ok(ParamValue::CPtr(param_value))
119        }
120        CommandQueueInfo::REFERENCE_COUNT | CommandQueueInfo::SIZE => {
121            let param_value =
122                gen_param_value!(clGetCommandQueueInfo, u32, command_queue, param_name);
123            Ok(ParamValue::UInt(param_value))
124        }
125        CommandQueueInfo::PROPERTIES => {
126            let param_value =
127                gen_param_value!(clGetCommandQueueInfo, u64, command_queue, param_name);
128            Ok(ParamValue::ULong(param_value))
129        }
130        // #[cfg(feature = "cl_3_0")]
131        CommandQueueInfo::PROPERTIES_ARRAY => {
132            let size = get_command_queue_info_size(command_queue, param_name)?;
133            let param_value =
134                gen_param_value!(clGetCommandQueueInfo, u64, command_queue, param_name, size);
135            Ok(ParamValue::ArrULong(param_value))
136        }
137        _ => status_update(40404, "clGetContextInfo", ParamValue::default()),
138    }
139}
140
141#[cfg(feature = "depr_1_0")]
142pub fn set_command_queue_property(
143    command_queue: &QueuePtr,
144    properties: &CommandQueueProperties,
145    enable: cl_bool,
146) -> APIResult<()> {
147    let status_code = unsafe {
148        ffi::clSetCommandQueueProperty(command_queue.unwrap(), properties, enable, ptr::null_mut())
149    };
150    status_update(status_code, "clSetCommandQueueProperty", ())
151}
152
153pub fn flush(command_queue: &QueuePtr) -> APIResult<()> {
154    let status_code = unsafe { ffi::clFlush(command_queue.unwrap()) };
155    status_update(status_code, "clFlush", ())
156}
157
158pub fn finish(command_queue: &QueuePtr) -> APIResult<()> {
159    let status_code = unsafe { ffi::clFinish(command_queue.unwrap()) };
160    status_update(status_code, "clFinish", ())
161}
162
163/************************/
164/* /\ /\ /\ /\ /\ /\ /\ */
165/*|__|__|__|__|__|__|__|*/
166/*|  |  |  |  |  |  |  |*/
167/*|  |  Unit Tests  |  |*/
168/*|__|__|__|__|__|__|__|*/
169/*|__|__|__|__|__|__|__|*/
170/************************/
171
172#[cfg(test)]
173mod tests {
174    use super::*;
175    use crate::api::context::{create_context, release_context};
176    use crate::api::device::get_device_ids;
177    use crate::api::platform::get_platform_ids;
178    use crate::objects::bitfields::{CommandQueueProperties, DeviceType};
179    use crate::objects::property::{ContextProperties, QueueProperties};
180    use crate::objects::structs::{CommandQueueInfo};
181    use crate::objects::traits::GetSetGo;
182    use crate::objects::types::{DevicePtr, PlatformPtr, WrapMutPtr};
183
184    #[test]
185    fn test_command_queue() {
186        let platform_ids = get_platform_ids().unwrap();
187
188        // Choose the first platform
189        // let platform_id = platform_ids[0];
190        //TODO: Add auto-detection of platforms
191        let platform_id = PlatformPtr::from_ptr(platform_ids[0], "test_fn").unwrap();
192
193        let device_ids = get_device_ids(
194            &platform_id,
195            DeviceType::new(DeviceType::DEFAULT + DeviceType::CPU + DeviceType::GPU).unwrap(),
196        )
197        .unwrap();
198        assert!(0 < device_ids.len());
199
200        // let device_id = device_ids[0];
201        //TODO: Add auto-detection of devices
202        let device_id = DevicePtr::from_ptr(device_ids[0], "test_fn").unwrap();
203
204        let properties = ContextProperties.gen(Some(&platform_id), None);
205        // let properties = ContextProperties.platform(&platform_id);
206
207        let context = create_context(&properties, device_ids, None, WrapMutPtr::null());
208        let context = context.unwrap();
209
210        // Queue v1
211        let properties =
212            CommandQueueProperties::new(CommandQueueProperties::PROFILING_ENABLE).unwrap();
213        let queue = create_command_queue(&context, &device_id, &properties).unwrap();
214
215        release_command_queue(queue).unwrap();
216
217        // Queue v2
218        // let properties = CommandQueueInfo.properties(
219        //     CommandQueueProperties::new(CommandQueueProperties::PROFILING_ENABLE).unwrap(),
220        // );
221        let properties = QueueProperties.gen(
222            Some(CommandQueueProperties::new(CommandQueueProperties::PROFILING_ENABLE).unwrap()),
223            None,
224        );
225        eprintln!("{:?}", properties);
226        let queue = create_command_queue_with_properties(&context, &device_id, &None).unwrap();
227
228        release_command_queue(queue).unwrap();
229
230        release_context(context).unwrap();
231    }
232
233    #[test]
234    fn test_get_command_queue_info() {
235        let platform_ids = get_platform_ids().unwrap();
236
237        // Choose the first platform
238        // let platform_id = platform_ids[0];
239        //TODO: Add auto-detection of platforms
240        let platform_id = PlatformPtr::from_ptr(platform_ids[0], "test_fn").unwrap();
241
242        let device_ids =
243            get_device_ids(&platform_id, DeviceType::new(DeviceType::DEFAULT).unwrap()).unwrap();
244        assert!(0 < device_ids.len());
245
246        // let device_id = device_ids[0];
247        let device_id = DevicePtr::from_ptr(device_ids[0], "test_fn").unwrap();
248
249        let properties = ContextProperties.gen(Some(&platform_id), Some(false));
250        // println!("{:?}", properties);
251        // assert!(false);
252        // let properties = ContextProperties.platform(&platform_id);
253
254        let context = create_context(&properties, device_ids, None, WrapMutPtr::null());
255        let context = context.unwrap();
256
257        // Queue v1
258        let properties =
259            CommandQueueProperties::new(CommandQueueProperties::PROFILING_ENABLE).unwrap();
260        let queue = create_command_queue(&context, &device_id, &properties).unwrap();
261        // Get command queue info v1
262        let command_info = get_command_queue_info(&queue, CommandQueueInfo::PROPERTIES).unwrap();
263        assert_eq!(properties.get(), command_info.unwrap_ulong().unwrap());
264
265        release_command_queue(queue).unwrap();
266
267        // Queue v2
268        // let properties = CommandQueueInfo.properties(
269        //     CommandQueueProperties::new(CommandQueueProperties::PROFILING_ENABLE).unwrap(),
270        // );
271        let properties = QueueProperties.gen(
272            Some(
273                CommandQueueProperties::new(
274                    CommandQueueProperties::PROFILING_ENABLE
275                        // + CommandQueueProperties::ON_DEVICE_DEFAULT,
276                )
277                .unwrap(),
278            ),
279            None,
280            // Some(DeviceInfo::QUEUE_ON_DEVICE_PREFERRED_SIZE),
281        );
282        eprintln!("{:?}", properties);
283        let queue =
284            create_command_queue_with_properties(&context, &device_id, &properties).unwrap();
285
286        let command_info = get_command_queue_info(&queue, CommandQueueInfo::PROPERTIES).unwrap();
287        assert_eq!(properties.unwrap()[1], command_info.unwrap_ulong().unwrap());
288
289        release_command_queue(queue).unwrap();
290
291        release_context(context).unwrap();
292    }
293}