1use std::{
2 mem::swap,
3 ops::Deref,
4 path::Path,
5 collections::HashSet,
6 marker::PhantomData,
7};
8use ocl::{self, prm};
9use ocl_include::{Hook, MemHook, ListHook};
10use crate::{
11 filter::Filter,
12 Context,
13 process::Program,
14 buffer::{RenderBuffer, Image},
15};
16
17pub struct PostprocCollector<F: Filter> {
19 list_hook: ListHook,
20 phantom: PhantomData<F>,
21}
22
23pub struct PostprocBuilder<F: Filter> {
25 program: Program,
26 phantom: PhantomData<F>,
27}
28
29pub struct Postproc<F: Filter> {
34 context: Context,
35 k_mean: ocl::Kernel,
36 k_filt: ocl::Kernel,
37 k_pack: ocl::Kernel,
38 host_buffer: Vec<f32>,
39 buffers: (ocl::Buffer<f32>, ocl::Buffer<f32>),
40 image: Image,
41 dims: (usize, usize),
42 pub filter: F,
43}
44
45impl<F: Filter> PostprocBuilder<F> {
46 pub fn program(&self) -> &Program {
47 &self.program
48 }
49}
50
51pub fn create_postproc<F: Filter>() -> PostprocCollector<F> {
53 PostprocCollector {
54 list_hook:
55 ListHook::builder()
56 .add_hook(crate::source())
57 .build(),
58 phantom: PhantomData,
59 }
60}
61
62impl<F: Filter> PostprocCollector<F> {
63 pub fn add_hook<H: Hook + 'static>(&mut self, hook: H) {
64 self.list_hook.add_hook(hook);
65 }
66
67 fn source(cache: &mut HashSet<u64>) -> String {
68 let cpref = F::inst_name().to_uppercase();
69 [
70 format!("#define __FILTER_ARGS_DEF {}_ARGS_DEF", cpref),
71 format!("#define __FILTER_ARGS {}_ARGS", cpref),
72 format!("#define __filter_apply {}_apply", F::inst_name()),
73 F::source(cache)
74 ].join("\n")
75 }
76
77 pub fn collect(mut self) -> crate::Result<PostprocBuilder<F>> {
78 let mut cache = HashSet::<u64>::new();
79 self.list_hook.add_hook(
80 MemHook::builder()
81 .add_file(
82 &Path::new("__gen/filter.h"),
83 Self::source(&mut cache),
84 )?
85 .build()
86 );
87 let program = Program::new(
88 &self.list_hook,
89 &Path::new("clay_core/filter.c"),
90 )?;
91
92 Ok(PostprocBuilder { program, phantom: PhantomData })
93 }
94}
95
96impl<F: Filter> PostprocBuilder<F> {
97 pub fn build(
98 self,
99 context: &Context,
100 dims: (usize, usize),
101 filter: F,
102 ) -> crate::Result<(Postproc<F>, String)> {
103 Postproc::new(context, dims, filter, self.program)
104 }
105}
106
107impl<F: Filter + Default> PostprocBuilder<F> {
108 pub fn build_default(
109 self,
110 context: &Context,
111 dims: (usize, usize),
112 ) -> crate::Result<(Postproc<F>, String)> {
113 self.build(context, dims, F::default())
114 }
115}
116
117impl<F: Filter> Postproc<F> {
118 fn build_mean(context: &Context) -> crate::Result<(ocl::Kernel, String)> {
119 let queue = context.queue().clone();
120
121 let program = Program::new(
122 &crate::source(),
123 &Path::new("clay_core/mean.c"),
124 )?;
125
126 let (ocl_prog, message) = program.build(context)?;
127
128 let kernel = ocl::Kernel::builder()
129 .program(&ocl_prog)
130 .name("mean")
131 .queue(queue.clone())
132 .arg(prm::Int2::zero()) .arg(0i32) .arg(0i32) .arg(None::<&ocl::Buffer<f32>>) .arg(None::<&ocl::Buffer<f32>>) .build()?;
138
139 Ok((kernel, message))
140 }
141
142 fn build_pack(context: &Context) -> crate::Result<(ocl::Kernel, String)> {
143 let queue = context.queue().clone();
144
145 let program = Program::new(
146 &crate::source(),
147 &Path::new("clay_core/pack.c"),
148 )?;
149
150 let (ocl_prog, message) = program.build(context)?;
151
152 let kernel = ocl::Kernel::builder()
153 .program(&ocl_prog)
154 .name("pack")
155 .queue(queue.clone())
156 .arg(prm::Int2::zero()) .arg(None::<&ocl::Buffer<u8>>) .arg(None::<&ocl::Buffer<f32>>) .build()?;
160
161 Ok((kernel, message))
162 }
163
164 fn create_buffer(context: &Context, dims: (usize, usize)) -> crate::Result<ocl::Buffer<f32>> {
165 ocl::Buffer::<f32>::builder()
166 .queue(context.queue().clone())
167 .flags(ocl::flags::MEM_READ_WRITE)
168 .len(3*dims.0*dims.1)
169 .fill_val(0 as f32)
170 .build()
171 .map_err(|e| e.into())
172 }
173
174 pub fn new(
175 context: &Context, dims: (usize, usize),
176 filter: F, program: Program,
177 ) -> crate::Result<(Self, String)> {
178 let queue = context.queue().clone();
179
180 let (ocl_prog, message) = program.build(context)?;
181
182 let mut kb = ocl::Kernel::builder();
183 kb.program(&ocl_prog)
184 .name("filter")
185 .queue(queue.clone())
186 .arg(prm::Int2::zero()) .arg(None::<&ocl::Buffer<f32>>) .arg(None::<&ocl::Buffer<f32>>); F::args_def(&mut kb);
190
191 let k_filt = kb.build()?;
192
193 let (k_mean, _msg_mean) = Self::build_mean(context)?;
194 let (k_pack, _msg_pack) = Self::build_pack(context)?;
196 Ok((Postproc {
199 context: context.clone(),
200 k_mean, k_filt, k_pack,
201 host_buffer: Vec::new(),
202 buffers: (
203 Self::create_buffer(context, dims)?,
204 Self::create_buffer(context, dims)?,
205 ),
206 image: Image::new(context, dims)?,
207 dims: dims,
208 filter,
209 }, message))
210 }
211
212 pub fn resize(&mut self, dims: (usize, usize)) -> crate::Result<()> {
213 self.buffers = (
214 Self::create_buffer(&self.context, dims)?,
215 Self::create_buffer(&self.context, dims)?,
216 );
217 self.image = Image::new(&self.context, dims)?;
218 self.dims = dims;
219 Ok(())
220 }
221
222 fn dims_prm(&self) -> prm::Int2 {
223 let dims = self.dims;
224 prm::Int2::new(dims.0 as i32, dims.1 as i32)
225 }
226
227 fn apply_collect(&mut self, n_passes: usize, screen: &RenderBuffer) -> crate::Result<()> {
228 if *screen.context() != self.context {
229 let len = 3*self.dims.0*self.dims.1;
230 if self.host_buffer.len() != len {
231 self.host_buffer.resize(len, 0f32);
232 }
233
234 screen.color().cmd()
235 .offset(0)
236 .read(&mut self.host_buffer)
237 .enq()?;
238
239 self.buffers.1.cmd()
240 .offset(0)
241 .write(&self.host_buffer)
242 .enq()?;
243
244 self.context.queue().finish()?;
245 };
246
247 let d = self.dims_prm();
248 let k = &mut self.k_mean;
249 k.set_arg(0, &d)?;
250 k.set_arg(1, &(n_passes as i32))?;
251 k.set_arg(2, &(screen.n_passes() as i32))?;
252 k.set_arg(3, &mut self.buffers.0)?;
253 if *screen.context() != self.context {
254 k.set_arg(4, &self.buffers.1)?;
255 } else {
256 k.set_arg(4, screen.color())?;
257 }
258
259 unsafe {
260 k.cmd()
261 .global_work_size(self.dims)
262 .enq()?;
263 }
264
265 Ok(())
266 }
267
268 fn apply_filter(&mut self) -> crate::Result<()> {
269 let d = self.dims_prm();
270 let k = &mut self.k_filt;
271 k.set_arg(0, &d)?;
272 k.set_arg(1, &mut self.buffers.1)?;
273 k.set_arg(2, &self.buffers.0)?;
274 self.filter.args_set(3, k)?;
275
276 unsafe {
277 k.cmd()
278 .global_work_size(self.dims)
279 .enq()?;
280 }
281
282 swap(&mut self.buffers.1, &mut self.buffers.0);
283 Ok(())
284 }
285
286 pub fn process<'a, I: Iterator<Item=&'a RenderBuffer>>(
287 &mut self, screens: I,
288 ) -> crate::Result<()> {
289 let mut n_passes = 0;
290 for screen in screens {
291 self.apply_collect(n_passes, screen.deref())?;
292 n_passes += screen.n_passes();
293 }
294
295 self.apply_filter()?;
296
297 self.context.queue().finish()?;
298 Ok(())
299 }
300
301 pub fn process_one(&mut self, screen: &RenderBuffer) -> crate::Result<()> {
302 self.process([screen].into_iter().map(|s| *s))
303 }
304
305 pub fn make_image(&mut self) -> crate::Result<()> {
306 let d = self.dims_prm();
307 let k = &mut self.k_pack;
308 k.set_arg(0, &d)?;
309 k.set_arg(1, self.image.bytes_mut())?;
310 k.set_arg(2, &self.buffers.0)?;
311
312 unsafe {
313 k.cmd()
314 .global_work_size(self.dims)
315 .enq()?;
316 }
317
318 swap(&mut self.buffers.1, &mut self.buffers.0);
319 Ok(())
320 }
321
322 pub fn buffer(&self) -> &ocl::Buffer<f32> {
323 &self.buffers.0
324 }
325 pub fn image(&self) -> &Image {
326 &self.image
327 }
328 pub fn dims(&self) -> (usize, usize) {
329 self.dims
330 }
331}