Skip to main content

repose_platform/
render.rs

1//! Render context for image upload commands
2use repose_core::color::{ColorInfo, PixelFormat};
3use repose_core::{ImageHandle, request_frame};
4
5#[derive(Debug)]
6pub enum RenderCommand {
7    SetImageEncoded {
8        handle: ImageHandle,
9        bytes: Vec<u8>,
10        srgb: bool,
11    },
12    SetImageRgba8 {
13        handle: ImageHandle,
14        w: u32,
15        h: u32,
16        rgba: Vec<u8>,
17        srgb: bool,
18    },
19    SetImageNv12 {
20        handle: ImageHandle,
21        w: u32,
22        h: u32,
23        y: Vec<u8>,
24        uv: Vec<u8>,
25        color_info: ColorInfo,
26    },
27    SetImagePlanes {
28        handle: ImageHandle,
29        w: u32,
30        h: u32,
31        pixel_format: PixelFormat,
32        planes: Vec<Vec<u8>>,
33        color_info: ColorInfo,
34    },
35    RemoveImage {
36        handle: ImageHandle,
37    },
38}
39
40#[cfg(not(target_arch = "wasm32"))]
41mod imp {
42    use super::*;
43    use std::collections::{HashMap, HashSet};
44    use std::sync::atomic::{AtomicU64, Ordering};
45    use std::sync::{Arc, Mutex};
46
47    struct Queue {
48        updates: HashMap<ImageHandle, RenderCommand>,
49        removals: HashSet<ImageHandle>,
50    }
51
52    impl Queue {
53        fn new() -> Self {
54            Self {
55                updates: HashMap::new(),
56                removals: HashSet::new(),
57            }
58        }
59    }
60
61    #[derive(Clone)]
62    pub struct RenderContext {
63        next: Arc<AtomicU64>,
64        q: Arc<Mutex<Queue>>,
65    }
66
67    impl RenderContext {
68        pub fn new() -> Self {
69            Self {
70                next: Arc::new(AtomicU64::new(1)),
71                q: Arc::new(Mutex::new(Queue::new())),
72            }
73        }
74
75        pub fn alloc_image_handle(&self) -> ImageHandle {
76            self.next.fetch_add(1, Ordering::Relaxed)
77        }
78
79        pub fn set_image_encoded(&self, handle: ImageHandle, bytes: Vec<u8>, srgb: bool) {
80            let mut q = self.q.lock().unwrap();
81            q.removals.remove(&handle);
82            q.updates.insert(
83                handle,
84                RenderCommand::SetImageEncoded {
85                    handle,
86                    bytes,
87                    srgb,
88                },
89            );
90            request_frame();
91        }
92
93        pub fn set_image_rgba8(
94            &self,
95            handle: ImageHandle,
96            w: u32,
97            h: u32,
98            rgba: Vec<u8>,
99            srgb: bool,
100        ) {
101            let mut q = self.q.lock().unwrap();
102            q.removals.remove(&handle);
103            q.updates.insert(
104                handle,
105                RenderCommand::SetImageRgba8 {
106                    handle,
107                    w,
108                    h,
109                    rgba,
110                    srgb,
111                },
112            );
113            request_frame();
114        }
115
116        pub fn set_image_nv12(
117            &self,
118            handle: ImageHandle,
119            w: u32,
120            h: u32,
121            y: Vec<u8>,
122            uv: Vec<u8>,
123            color_info: ColorInfo,
124        ) {
125            self.set_image_planes(handle, w, h, PixelFormat::Nv12, vec![y, uv], color_info);
126        }
127
128        pub fn set_image_planes(
129            &self,
130            handle: ImageHandle,
131            w: u32,
132            h: u32,
133            pixel_format: PixelFormat,
134            planes: Vec<Vec<u8>>,
135            color_info: ColorInfo,
136        ) {
137            let mut q = self.q.lock().unwrap();
138            q.removals.remove(&handle);
139            q.updates.insert(
140                handle,
141                RenderCommand::SetImagePlanes {
142                    handle,
143                    w,
144                    h,
145                    pixel_format,
146                    planes,
147                    color_info,
148                },
149            );
150            request_frame();
151        }
152
153        pub fn remove_image(&self, handle: ImageHandle) {
154            let mut q = self.q.lock().unwrap();
155            q.removals.remove(&handle);
156            q.updates.remove(&handle);
157            request_frame();
158        }
159
160        pub(crate) fn drain(&self) -> Vec<RenderCommand> {
161            let mut q = self.q.lock().unwrap();
162            let mut result = Vec::with_capacity(q.removals.len() + q.updates.len());
163
164            for handle in q.removals.drain() {
165                result.push(RenderCommand::RemoveImage { handle });
166            }
167
168            for (_, cmd) in q.updates.drain() {
169                result.push(cmd);
170            }
171
172            result
173        }
174    }
175
176    impl Default for RenderContext {
177        fn default() -> Self {
178            Self::new()
179        }
180    }
181}
182
183#[cfg(target_arch = "wasm32")]
184mod imp {
185    use super::*;
186    use std::cell::RefCell;
187    use std::collections::{HashMap, HashSet};
188    use std::rc::Rc;
189
190    struct Queue {
191        updates: HashMap<ImageHandle, RenderCommand>,
192        removals: HashSet<ImageHandle>,
193    }
194
195    struct Inner {
196        next: ImageHandle,
197        q: Queue,
198    }
199
200    #[derive(Clone)]
201    pub struct RenderContext {
202        inner: Rc<RefCell<Inner>>,
203    }
204
205    impl RenderContext {
206        pub fn new() -> Self {
207            Self {
208                inner: Rc::new(RefCell::new(Inner {
209                    next: 1,
210                    q: Queue {
211                        updates: HashMap::new(),
212                        removals: HashSet::new(),
213                    },
214                })),
215            }
216        }
217
218        pub fn alloc_image_handle(&self) -> ImageHandle {
219            let mut s = self.inner.borrow_mut();
220            let id = s.next;
221            s.next += 1;
222            id
223        }
224
225        pub fn set_image_encoded(&self, handle: ImageHandle, bytes: Vec<u8>, srgb: bool) {
226            let mut s = self.inner.borrow_mut();
227            s.q.removals.remove(&handle);
228            s.q.updates.insert(
229                handle,
230                RenderCommand::SetImageEncoded {
231                    handle,
232                    bytes,
233                    srgb,
234                },
235            );
236            request_frame();
237        }
238
239        pub fn set_image_rgba8(
240            &self,
241            handle: ImageHandle,
242            w: u32,
243            h: u32,
244            rgba: Vec<u8>,
245            srgb: bool,
246        ) {
247            let mut s = self.inner.borrow_mut();
248            s.q.removals.remove(&handle);
249            s.q.updates.insert(
250                handle,
251                RenderCommand::SetImageRgba8 {
252                    handle,
253                    w,
254                    h,
255                    rgba,
256                    srgb,
257                },
258            );
259            request_frame();
260        }
261
262        pub fn set_image_nv12(
263            &self,
264            handle: ImageHandle,
265            w: u32,
266            h: u32,
267            y: Vec<u8>,
268            uv: Vec<u8>,
269            color_info: ColorInfo,
270        ) {
271            self.set_image_planes(handle, w, h, PixelFormat::Nv12, vec![y, uv], color_info);
272        }
273
274        pub fn set_image_planes(
275            &self,
276            handle: ImageHandle,
277            w: u32,
278            h: u32,
279            pixel_format: PixelFormat,
280            planes: Vec<Vec<u8>>,
281            color_info: ColorInfo,
282        ) {
283            let mut s = self.inner.borrow_mut();
284            s.q.removals.remove(&handle);
285            s.q.updates.insert(
286                handle,
287                RenderCommand::SetImagePlanes {
288                    handle,
289                    w,
290                    h,
291                    pixel_format,
292                    planes,
293                    color_info,
294                },
295            );
296            request_frame();
297        }
298
299        pub fn remove_image(&self, handle: ImageHandle) {
300            let mut s = self.inner.borrow_mut();
301            s.q.updates.remove(&handle);
302            s.q.removals.insert(handle);
303            request_frame();
304        }
305
306        pub(crate) fn drain(&self) -> Vec<RenderCommand> {
307            let mut s = self.inner.borrow_mut();
308            let mut result = Vec::with_capacity(s.q.removals.len() + s.q.updates.len());
309
310            for handle in s.q.removals.drain() {
311                result.push(RenderCommand::RemoveImage { handle });
312            }
313
314            for (_, cmd) in s.q.updates.drain() {
315                result.push(cmd);
316            }
317
318            result
319        }
320    }
321
322    impl Default for RenderContext {
323        fn default() -> Self {
324            Self::new()
325        }
326    }
327}
328
329pub use imp::RenderContext;
330
331/// RAII guard that removes the image when dropped
332pub struct ImageHandleGuard {
333    pub handle: ImageHandle,
334    rc: RenderContext,
335}
336
337impl ImageHandleGuard {
338    pub fn new(rc: &RenderContext) -> Self {
339        Self {
340            handle: rc.alloc_image_handle(),
341            rc: rc.clone(),
342        }
343    }
344}
345
346impl Drop for ImageHandleGuard {
347    fn drop(&mut self) {
348        self.rc.remove_image(self.handle);
349    }
350}
351
352impl std::ops::Deref for ImageHandleGuard {
353    type Target = ImageHandle;
354    fn deref(&self) -> &Self::Target {
355        &self.handle
356    }
357}