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}