1use std::{
2 path::Path,
3 collections::HashSet,
4 marker::PhantomData,
5 time::{Instant, Duration},
6};
7use ocl::{self, prm, builders::KernelBuilder};
8use ocl_include::{Hook, MemHook, ListHook};
9use crate::{
10 prelude::*,
11 scene::Scene,
12 view::View,
13
14 Context,
15 process::Program,
16 buffer::RenderBuffer,
17};
18
19pub fn create_renderer<S: Scene, V: View>() -> RendererBuilder<S, V> {
21 RendererBuilder {
22 list_hook:
23 ListHook::builder()
24 .add_hook(crate::source())
25 .build(),
26 phantom: PhantomData,
27 }
28}
29
30pub struct RendererBuilder<S: Scene, V: View> {
32 list_hook: ListHook,
33 phantom: PhantomData<(S, V)>,
34}
35
36pub struct Renderer<S: Scene, V: View> {
40 program: Program,
41 dims: (usize, usize),
42 pub scene: S,
43 pub view: V,
44}
45
46pub struct RenderData<S: Scene, V: View> {
48 screen: RenderBuffer,
49 scene_data: S::Data,
50 view_data: V::Data,
51}
52
53impl<S: Scene, V: View> Renderer<S, V> {
54 pub fn new<H: Hook + 'static>(
55 dims: (usize, usize),
56 scene: S, view: V,
57 hook: H,
58 ) -> crate::Result<Self> {
59 let mut inst_cache = HashSet::<u64>::new();
60 let list_hook = ListHook::builder()
61 .add_hook(hook)
62 .add_hook(
63 MemHook::builder()
64 .add_file(&Path::new("__gen/scene.h"), S::source(&mut inst_cache))?
65 .add_file(&Path::new("__gen/view.h"), V::source(&mut inst_cache))?
66 .build()
67 )
68 .build();
69 let program = Program::new(&list_hook, &Path::new("clay_core/render.c"))?;
70
71 Ok(Self { program, dims, scene, view })
72 }
73
74 pub fn program(&self) -> &Program {
75 &self.program
76 }
77
78 pub fn create_worker(&self, context: &Context) -> crate::Result<(RenderWorker<S, V>, String)> {
79 RenderWorker::new(
80 context,
81 self.program(),
82 self.create_data(context)?,
83 )
84 }
85}
86
87impl<S: Scene, V: View> RendererBuilder<S, V> {
88 pub fn add_hook<H: Hook + 'static>(&mut self, hook: H) {
89 self.list_hook.add_hook(hook);
90 }
91
92 pub fn build(
93 self, dims: (usize, usize),
94 scene: S, view: V,
95 ) -> crate::Result<Renderer<S, V>> {
96 Renderer::<S, V>::new(
97 dims, scene, view,
98 self.list_hook,
99 )
100 }
101}
102
103impl<S: Scene, V: View> Store for Renderer<S, V> {
104 type Data = RenderData<S, V>;
105
106 fn create_data(&self, context: &Context) -> crate::Result<Self::Data> {
107 Ok(Self::Data {
108 screen: RenderBuffer::new(context, self.dims)?,
109 scene_data: self.scene.create_data(context)?,
110 view_data: self.view.create_data(context)?,
111 })
112 }
113
114 fn update_data(&self, context: &Context, data: &mut Self::Data) -> crate::Result<()> {
115 self.scene.update_data(context, &mut data.scene_data)?;
116 self.view.update_data(context, &mut data.view_data)?;
117 Ok(())
118 }
119}
120
121impl<S: Scene, V: View> RenderData<S, V> {
122 pub fn buffer(&self) -> &RenderBuffer {
123 &self.screen
124 }
125 pub fn buffer_mut(&mut self) -> &mut RenderBuffer {
126 &mut self.screen
127 }
128 pub fn scene(&self) -> &S::Data {
129 &self.scene_data
130 }
131 pub fn scene_mut(&mut self) -> &mut S::Data {
132 &mut self.scene_data
133 }
134 pub fn view(&self) -> &V::Data {
135 &self.view_data
136 }
137 pub fn view_mut(&mut self) -> &mut V::Data {
138 &mut self.view_data
139 }
140}
141
142impl<S: Scene, V: View> Push for RenderData<S, V> {
143 fn args_count() -> usize {
144 3 + S::Data::args_count() + V::Data::args_count()
145 }
146 fn args_def(kb: &mut KernelBuilder) {
147 kb.arg(prm::Int2::zero()); kb.arg(None::<&ocl::Buffer<f32>>); kb.arg(None::<&ocl::Buffer<u32>>); S::Data::args_def(kb);
151 V::Data::args_def(kb);
152 }
153 fn args_set(&mut self, i: usize, k: &mut ocl::Kernel) -> crate::Result<()> {
154 let mut j = i;
155
156 let dims = self.screen.dims();
157 let dims_prm = prm::Int2::new(dims.0 as i32, dims.1 as i32);
158 k.set_arg(i + 0, &dims_prm)?;
159 k.set_arg(i + 1, self.screen.color_mut())?;
160 k.set_arg(i + 2, self.screen.random_mut())?;
161 j += 3;
162
163 self.scene_data.args_set(j, k)?;
164 j += S::Data::args_count();
165
166 self.view_data.args_set(j, k)?;
167 Ok(())
170 }
171}
172
173pub struct RenderWorker<S: Scene, V: View> {
177 data: RenderData<S, V>,
178 kernel: ocl::Kernel,
179 context: Context,
180}
181
182impl<S: Scene, V: View> RenderWorker<S, V> {
183 pub fn new(
184 context: &Context,
185 program: &Program,
186 data: RenderData<S, V>,
187 ) -> crate::Result<(Self, String)> {
188 let queue = context.queue().clone();
189
190 let (ocl_prog, message) = program.build(context)?;
191
192 let mut kb = ocl::Kernel::builder();
193 kb.program(&ocl_prog)
194 .name("render")
195 .queue(queue.clone());
196 RenderData::<S, V>::args_def(&mut kb);
197
198 let kernel = kb.build()?;
199
200 Ok((RenderWorker {
201 data, kernel,
202 context: context.clone(),
203 }, message))
204 }
205
206 pub fn data(&self) -> &RenderData<S, V> {
207 &self.data
208 }
209 pub fn data_mut(&mut self) -> &mut RenderData<S, V> {
210 &mut self.data
211 }
212
213 pub fn run(&mut self) -> crate::Result<()> {
216 self.data.args_set(0, &mut self.kernel)?;
217 unsafe {
218 self.kernel.cmd()
219 .global_work_size(self.data.screen.dims())
220 .enq()?;
221 }
222 self.context.queue().finish()?;
223 self.data_mut().screen.pass();
224
225 Ok(())
226 }
227
228 pub fn run_for(&mut self, time: Duration) -> crate::Result<usize> {
230 let inst = Instant::now();
231 let mut passes = 1;
232 self.run()?;
233 while inst.elapsed() < time {
234 self.run()?;
235 passes += 1;
236 }
237 Ok(passes)
238 }
239}