Skip to main content

repose_platform/
render.rs

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