Skip to main content

repose_core/
render_context.rs

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