opencl_core/
context.rs

1use std::fmt;
2use std::iter::Iterator;
3use std::mem::ManuallyDrop;
4
5use crate::ffi::cl_device_id;
6use crate::ll::{ClContext, ClDeviceID, ContextProperties, ContextPtr, DevicePtr, VecOrSlice};
7
8use crate::{Device, Output};
9
10pub struct Context {
11    inner: ManuallyDrop<ClContext>,
12    _devices: ManuallyDrop<Vec<ClDeviceID>>,
13    _unconstructable: (),
14}
15
16impl Context {
17    // Context::build is safe because all objects should be reference counted
18    // and their wrapping structs should be droppable. If there is a memory
19    // error from opencl it will not be caused by Context::build.
20    pub fn build<'a, D>(obj: ClContext, devices: D) -> Context
21    where
22        D: Into<VecOrSlice<'a, Device>>,
23    {
24        let devices = devices.into();
25        let ll_devices = devices
26            .as_slice()
27            .iter()
28            .map(|d| d.low_level_device().clone())
29            .collect();
30        Context {
31            inner: ManuallyDrop::new(obj),
32            _devices: ManuallyDrop::new(ll_devices),
33            _unconstructable: (),
34        }
35    }
36
37    pub fn low_level_context(&self) -> &ClContext {
38        &*self.inner
39    }
40
41    pub fn from_low_level_context(ll_context: &ClContext) -> Output<Context> {
42        let ll_devices = unsafe { ll_context.devices() }?;
43        let devices: Vec<Device> = ll_devices.into_iter().map(|d| Device::new(d)).collect();
44        Ok(Context::build(ll_context.clone(), devices))
45    }
46
47    pub fn create<'a, D: Into<VecOrSlice<'a, Device>>>(devices: D) -> Output<Context> {
48        let devices = devices.into();
49        let device_ptrs: Vec<cl_device_id> =
50            devices.iter().map(|d| unsafe { d.device_ptr() }).collect();
51
52        let ll_context: ClContext = unsafe { ClContext::create(&device_ptrs[..]) }?;
53        Ok(Context::build(ll_context, devices))
54    }
55
56    pub fn devices(&self) -> &[ClDeviceID] {
57        &self._devices[..]
58    }
59
60    pub fn reference_count(&self) -> Output<u32> {
61        unsafe { self.inner.reference_count() }
62    }
63
64    pub fn properties(&self) -> Output<Vec<ContextProperties>> {
65        unsafe { self.inner.properties() }
66    }
67
68    pub fn num_devices(&self) -> usize {
69        self._devices.len()
70    }
71}
72
73impl Clone for Context {
74    fn clone(&self) -> Context {
75        let cloned_devices = self._devices.iter().map(Clone::clone).collect();
76        Context {
77            inner: ManuallyDrop::new((*self.inner).clone()),
78            _devices: ManuallyDrop::new(cloned_devices),
79            _unconstructable: (),
80        }
81    }
82}
83
84impl Drop for Context {
85    fn drop(&mut self) {
86        unsafe { ManuallyDrop::drop(&mut self.inner) }
87    }
88}
89
90/// Context is thread-safe. The only mutable actions for a cl_context are its
91/// retain and release functions which are (according to OpenCL documentation),
92/// thread-safe, atomic reference counting operations. Therefore, Context
93/// is safe for Sync + Send.
94unsafe impl Send for Context {}
95unsafe impl Sync for Context {}
96
97impl PartialEq for Context {
98    fn eq(&self, other: &Self) -> bool {
99        *self.inner == *other.inner
100    }
101}
102
103impl Eq for Context {}
104
105impl fmt::Debug for Context {
106    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
107        write!(f, "Context{{{:?}}}", unsafe { self.inner.context_ptr() })
108    }
109}
110
111#[cfg(test)]
112mod tests {
113    use super::Context;
114    use crate::device::Device;
115    use crate::testing;
116
117    #[test]
118    fn context_can_be_created_via_a_device() {
119        let device: Device = testing::get_device();
120        let devices = vec![device];
121        let _context: Context =
122            Context::create(&devices[..]).expect("Failed to create context from a device");
123    }
124
125    #[test]
126    fn context_ptr_is_implemented() {
127        let ctx = testing::get_context();
128        ctx.reference_count().unwrap();
129        ctx.num_devices();
130        ctx.properties().unwrap();
131    }
132}