opencl_core/
program.rs

1use std::fmt;
2use std::mem::ManuallyDrop;
3
4use crate::ffi::cl_program;
5
6use crate::ll::{ClContext, ClProgram, ContextPtr, ProgramPtr};
7use crate::{Context, Device, Output};
8
9pub struct UnbuiltProgram {
10    context: ManuallyDrop<ClContext>,
11    inner: ManuallyDrop<ClProgram>,
12    _unconstructable: (),
13}
14
15impl UnbuiltProgram {
16    pub unsafe fn new(program: ClProgram, context: ClContext) -> UnbuiltProgram {
17        UnbuiltProgram {
18            context: ManuallyDrop::new(context),
19            inner: ManuallyDrop::new(program),
20            _unconstructable: (),
21        }
22    }
23}
24
25unsafe impl Send for UnbuiltProgram {}
26
27impl Drop for UnbuiltProgram {
28    fn drop(&mut self) {
29        unsafe {
30            ManuallyDrop::drop(&mut self.inner);
31            ManuallyDrop::drop(&mut self.context);
32        }
33    }
34}
35
36impl Clone for UnbuiltProgram {
37    fn clone(&self) -> UnbuiltProgram {
38        UnbuiltProgram {
39            context: self.context.clone(),
40            inner: ManuallyDrop::new((*self.inner).clone()),
41            _unconstructable: (),
42        }
43    }
44}
45
46impl fmt::Debug for UnbuiltProgram {
47    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
48        write!(f, "UnbuiltProgram{{{:?}}}", self.inner)
49    }
50}
51
52impl UnbuiltProgram {
53    pub fn create_with_source(context: &Context, src: &str) -> Output<UnbuiltProgram> {
54        unsafe {
55            let ll_prog = ClProgram::create_with_source(context.low_level_context(), src)?;
56            Ok(UnbuiltProgram::new(
57                ll_prog,
58                context.low_level_context().clone(),
59            ))
60        }
61    }
62
63    pub fn create_with_binary(
64        context: &Context,
65        device: &Device,
66        binary: &[u8],
67    ) -> Output<UnbuiltProgram> {
68        unsafe {
69            let ll_prog = ClProgram::create_with_binary(
70                context.low_level_context(),
71                device.low_level_device(),
72                binary,
73            )?;
74            Ok(UnbuiltProgram::new(
75                ll_prog,
76                context.low_level_context().clone(),
77            ))
78        }
79    }
80
81    pub fn build(mut self, devices: &[Device]) -> Output<Program> {
82        let built_prog: Program = unsafe {
83            self.inner.build(devices)?;
84            let (program_ptr, context_ptr, context_devices) = (
85                self.inner.program_ptr(),
86                self.context.context_ptr(),
87                self.context.devices()?,
88            );
89
90            let context_devices2: Vec<Device> = context_devices
91                .into_iter()
92                .map(|d| Device::new(d))
93                .collect();
94
95            let ll_program = ClProgram::new(program_ptr)?;
96            let ll_context = ClContext::new(context_ptr)?;
97            let hl_context = Context::build(ll_context, context_devices2);
98            Program::new(ll_program, hl_context, devices.to_vec())
99        };
100        std::mem::forget(self);
101        Ok(built_prog)
102    }
103}
104
105pub struct Program {
106    _context: ManuallyDrop<Context>,
107    _devices: ManuallyDrop<Vec<Device>>,
108    inner: ManuallyDrop<ClProgram>,
109    _unconstructable: (),
110}
111
112impl Program {
113    pub fn create_with_source(context: &Context, src: &str) -> Output<UnbuiltProgram> {
114        UnbuiltProgram::create_with_source(context, src)
115    }
116
117    pub fn create_with_binary(
118        context: &Context,
119        device: &Device,
120        binary: &[u8],
121    ) -> Output<UnbuiltProgram> {
122        UnbuiltProgram::create_with_binary(context, device, binary)
123    }
124
125    pub unsafe fn new(object: ClProgram, context: Context, devices: Vec<Device>) -> Program {
126        Program {
127            inner: ManuallyDrop::new(object),
128            _context: ManuallyDrop::new(context),
129            _devices: ManuallyDrop::new(devices),
130            _unconstructable: (),
131        }
132    }
133
134    pub unsafe fn from_low_level_program(program: &ClProgram) -> Output<Program> {
135        let ll_devices = program.devices()?;
136        let ll_context = program.context()?;
137        let hl_devices = ll_devices.into_iter().map(|d| Device::new(d)).collect();
138        let hl_context = Context::from_low_level_context(&ll_context)?;
139        Ok(Program::new(program.clone(), hl_context, hl_devices))
140    }
141
142    pub fn devices(&self) -> &[Device] {
143        &self._devices[..]
144    }
145
146    pub fn context(&self) -> &Context {
147        &self._context
148    }
149
150    pub fn low_level_program(&self) -> &ClProgram {
151        &self.inner
152    }
153}
154
155impl Drop for Program {
156    fn drop(&mut self) {
157        unsafe {
158            ManuallyDrop::drop(&mut self.inner);
159            ManuallyDrop::drop(&mut self._context);
160            ManuallyDrop::drop(&mut self._devices);
161        }
162    }
163}
164
165impl Clone for Program {
166    fn clone(&self) -> Program {
167        Program {
168            _devices: ManuallyDrop::new((*self._devices).clone()),
169            _context: self._context.clone(),
170            inner: ManuallyDrop::new((*self.inner).clone()),
171            _unconstructable: (),
172        }
173    }
174}
175
176impl fmt::Debug for Program {
177    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
178        write!(f, "Program{{{:?}}}", unsafe { self.program_ptr() })
179    }
180}
181
182unsafe impl Sync for Program {}
183unsafe impl Send for Program {}
184
185unsafe impl ProgramPtr for Program {
186    unsafe fn program_ptr(&self) -> cl_program {
187        (*self.inner).program_ptr()
188    }
189}
190
191unsafe impl ProgramPtr for &Program {
192    unsafe fn program_ptr(&self) -> cl_program {
193        (*self.inner).program_ptr()
194    }
195}
196
197unsafe impl ProgramPtr for &mut Program {
198    unsafe fn program_ptr(&self) -> cl_program {
199        (*self.inner).program_ptr()
200    }
201}
202
203impl PartialEq for Program {
204    fn eq(&self, other: &Self) -> bool {
205        unsafe { std::ptr::eq(self.program_ptr(), other.program_ptr()) }
206    }
207}
208
209impl Eq for Program {}
210
211#[cfg(test)]
212mod tests {
213    use crate::ll::*;
214    use crate::*;
215
216    const SRC: &str = "
217    __kernel void test(__global int *i) {        
218        *i += 1;
219    }
220    ";
221
222    #[test]
223    fn program_method_reference_count_works() {
224        let program: Program = testing::get_program(SRC);
225        let output: u32 = program
226            .reference_count()
227            .expect("Failed to call program.reference_count()");
228        assert_eq!(output, 1);
229    }
230
231    #[test]
232    fn program_method_context_works() {
233        let program: Program = testing::get_program(SRC);
234        let _output: &Context = program.context();
235    }
236
237    #[test]
238    fn program_method_num_devices_works() {
239        let program: Program = testing::get_program(SRC);
240        let output = program
241            .num_devices()
242            .expect("Failed to call program.num_devices()");
243        assert_eq!(output, program.devices().len());
244    }
245
246    #[test]
247    fn program_method_devices_works() {
248        let program: Program = testing::get_program(SRC);
249        let devices: &[Device] = program.devices();
250        assert!(devices.len() > 0);
251    }
252
253    #[test]
254    fn program_method_source_works() {
255        let program: Program = testing::get_program(SRC);
256        let output: String = program.source().expect("Failed to call program.source()");
257        assert_eq!(output, SRC.to_string());
258    }
259
260    #[test]
261    fn program_method_binary_sizes_works() {
262        let program: Program = testing::get_program(SRC);
263        let output: Vec<usize> = program
264            .binary_sizes()
265            .expect("Failed to call program.binary_sizes()");
266        assert_eq!(output.len(), program.devices().len());
267    }
268
269    #[test]
270    fn program_method_binaries_works() {
271        let program: Program = testing::get_program(SRC);
272        let output: Vec<u8> = program
273            .binaries()
274            .expect("Failed to call program.binaries()");
275        let n_devices = program.devices().len();
276        let n_bytes = n_devices * 8;
277        assert_eq!(output.len(), n_bytes);
278        for byte in output.into_iter() {
279            assert_eq!(byte, 0u8);
280        }
281    }
282
283    #[test]
284    fn program_method_num_kernels_works() {
285        let program: Program = testing::get_program(SRC);
286        let output: usize = program
287            .num_kernels()
288            .expect("Failed to call program.num_kernels()");
289        assert_eq!(output, 1);
290    }
291
292    #[test]
293    fn program_method_kernel_names_works() {
294        let program: Program = testing::get_program(SRC);
295        let output: Vec<String> = program
296            .kernel_names()
297            .expect("Failed to call program.kernel_names()");
298        let expected = vec!["test".to_string()];
299        assert_eq!(output, expected);
300    }
301}