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            crate::image_intrinsic::set_image_intrinsic_size(handle, w, h);
121            let mut q = self.q.lock().unwrap();
122            q.removals.remove(&handle);
123            q.updates.insert(
124                handle,
125                RenderCommand::SetImageRgba8 {
126                    handle,
127                    w,
128                    h,
129                    rgba,
130                    srgb,
131                },
132            );
133            request_present();
134        }
135
136        pub fn set_image_nv12(
137            &self,
138            handle: ImageHandle,
139            w: u32,
140            h: u32,
141            y: Arc<[u8]>,
142            uv: Arc<[u8]>,
143            color_info: ColorInfo,
144        ) {
145            self.set_image_planes(handle, w, h, PixelFormat::Nv12, vec![y, uv], color_info);
146        }
147
148        pub fn set_image_planes(
149            &self,
150            handle: ImageHandle,
151            w: u32,
152            h: u32,
153            pixel_format: PixelFormat,
154            planes: Vec<Arc<[u8]>>,
155            color_info: ColorInfo,
156        ) {
157            crate::image_intrinsic::set_image_intrinsic_size(handle, w, h);
158            let mut q = self.q.lock().unwrap();
159            q.removals.remove(&handle);
160            q.updates.insert(
161                handle,
162                RenderCommand::SetImagePlanes {
163                    handle,
164                    w,
165                    h,
166                    pixel_format,
167                    planes,
168                    color_info,
169                },
170            );
171            request_present();
172        }
173
174        pub fn remove_image(&self, handle: ImageHandle) {
175            crate::image_intrinsic::clear_image_intrinsic_size(handle);
176            let mut q = self.q.lock().unwrap();
177            q.removals.insert(handle);
178            q.updates.remove(&handle);
179            request_present();
180        }
181
182        #[cfg(target_os = "linux")]
183        pub fn set_image_dmabuf(
184            &self,
185            handle: ImageHandle,
186            w: u32,
187            h: u32,
188            fds: Vec<std::os::unix::io::OwnedFd>,
189            fourcc: u32,
190            modifier: u64,
191            strides: Vec<u32>,
192            offsets: Vec<u64>,
193            color_info: ColorInfo,
194        ) {
195            crate::image_intrinsic::set_image_intrinsic_size(handle, w, h);
196            let mut q = self.q.lock().unwrap();
197            q.removals.remove(&handle);
198            q.updates.insert(
199                handle,
200                RenderCommand::SetImageDmaBuf {
201                    handle,
202                    w,
203                    h,
204                    fds,
205                    fourcc,
206                    modifier,
207                    strides,
208                    offsets,
209                    color_info,
210                },
211            );
212            request_present();
213        }
214
215        pub fn drain(&self) -> Vec<RenderCommand> {
216            let mut q = self.q.lock().unwrap();
217            let mut result = Vec::with_capacity(q.removals.len() + q.updates.len());
218
219            for handle in q.removals.drain() {
220                result.push(RenderCommand::RemoveImage { handle });
221            }
222
223            for (_, cmd) in q.updates.drain() {
224                result.push(cmd);
225            }
226
227            result
228        }
229    }
230
231    impl Default for RenderContext {
232        fn default() -> Self {
233            Self::new()
234        }
235    }
236}
237
238#[cfg(target_arch = "wasm32")]
239mod imp {
240    use super::*;
241    use std::cell::RefCell;
242    use std::collections::{HashMap, HashSet};
243    use std::rc::Rc;
244    use std::sync::Arc;
245
246    struct Queue {
247        updates: HashMap<ImageHandle, RenderCommand>,
248        removals: HashSet<ImageHandle>,
249    }
250
251    struct Inner {
252        next: ImageHandle,
253        q: Queue,
254    }
255
256    #[derive(Clone)]
257    pub struct RenderContext {
258        inner: Rc<RefCell<Inner>>,
259    }
260
261    impl RenderContext {
262        pub fn new() -> Self {
263            Self {
264                inner: Rc::new(RefCell::new(Inner {
265                    next: 1,
266                    q: Queue {
267                        updates: HashMap::new(),
268                        removals: HashSet::new(),
269                    },
270                })),
271            }
272        }
273
274        pub fn alloc_image_handle(&self) -> ImageHandle {
275            let mut s = self.inner.borrow_mut();
276            let id = s.next;
277            s.next += 1;
278            id
279        }
280
281        pub fn set_image_encoded(&self, handle: ImageHandle, bytes: Vec<u8>, srgb: bool) {
282            let mut s = self.inner.borrow_mut();
283            s.q.removals.remove(&handle);
284            s.q.updates.insert(
285                handle,
286                RenderCommand::SetImageEncoded {
287                    handle,
288                    bytes,
289                    srgb,
290                },
291            );
292            request_present();
293        }
294
295        pub fn image_from_encoded(&self, bytes: impl Into<Vec<u8>>, srgb: bool) -> ImageHandle {
296            let handle = self.alloc_image_handle();
297            self.set_image_encoded(handle, bytes.into(), srgb);
298            handle
299        }
300
301        pub fn set_image_rgba8(
302            &self,
303            handle: ImageHandle,
304            w: u32,
305            h: u32,
306            rgba: Vec<u8>,
307            srgb: bool,
308        ) {
309            crate::image_intrinsic::set_image_intrinsic_size(handle, w, h);
310            let mut s = self.inner.borrow_mut();
311            s.q.removals.remove(&handle);
312            s.q.updates.insert(
313                handle,
314                RenderCommand::SetImageRgba8 {
315                    handle,
316                    w,
317                    h,
318                    rgba,
319                    srgb,
320                },
321            );
322            request_present();
323        }
324
325        pub fn set_image_nv12(
326            &self,
327            handle: ImageHandle,
328            w: u32,
329            h: u32,
330            y: Arc<[u8]>,
331            uv: Arc<[u8]>,
332            color_info: ColorInfo,
333        ) {
334            self.set_image_planes(handle, w, h, PixelFormat::Nv12, vec![y, uv], color_info);
335        }
336
337        pub fn set_image_planes(
338            &self,
339            handle: ImageHandle,
340            w: u32,
341            h: u32,
342            pixel_format: PixelFormat,
343            planes: Vec<Arc<[u8]>>,
344            color_info: ColorInfo,
345        ) {
346            crate::image_intrinsic::set_image_intrinsic_size(handle, w, h);
347            let mut s = self.inner.borrow_mut();
348            s.q.removals.remove(&handle);
349            s.q.updates.insert(
350                handle,
351                RenderCommand::SetImagePlanes {
352                    handle,
353                    w,
354                    h,
355                    pixel_format,
356                    planes,
357                    color_info,
358                },
359            );
360            request_present();
361        }
362
363        pub fn remove_image(&self, handle: ImageHandle) {
364            crate::image_intrinsic::clear_image_intrinsic_size(handle);
365            let mut s = self.inner.borrow_mut();
366            s.q.updates.remove(&handle);
367            s.q.removals.insert(handle);
368            request_present();
369        }
370
371        #[cfg(target_os = "linux")]
372        pub fn set_image_dmabuf(
373            &self,
374            _handle: ImageHandle,
375            _w: u32,
376            _h: u32,
377            _fds: Vec<std::os::unix::io::OwnedFd>,
378            _fourcc: u32,
379            _modifier: u64,
380            _strides: Vec<u32>,
381            _offsets: Vec<u64>,
382            _color_info: ColorInfo,
383        ) {
384            // DMA-BUF not supported on WASM
385        }
386
387        pub fn drain(&self) -> Vec<RenderCommand> {
388            let mut s = self.inner.borrow_mut();
389            let mut result = Vec::with_capacity(s.q.removals.len() + s.q.updates.len());
390
391            for handle in s.q.removals.drain() {
392                result.push(RenderCommand::RemoveImage { handle });
393            }
394
395            for (_, cmd) in s.q.updates.drain() {
396                result.push(cmd);
397            }
398
399            result
400        }
401    }
402
403    impl Default for RenderContext {
404        fn default() -> Self {
405            Self::new()
406        }
407    }
408}
409
410pub use imp::RenderContext;
411
412/// RAII guard that removes the image when dropped
413pub struct ImageHandleGuard {
414    pub handle: ImageHandle,
415    rc: RenderContext,
416}
417
418impl ImageHandleGuard {
419    pub fn new(rc: &RenderContext) -> Self {
420        Self {
421            handle: rc.alloc_image_handle(),
422            rc: rc.clone(),
423        }
424    }
425}
426
427impl Drop for ImageHandleGuard {
428    fn drop(&mut self) {
429        self.rc.remove_image(self.handle);
430    }
431}
432
433impl std::ops::Deref for ImageHandleGuard {
434    type Target = ImageHandle;
435    fn deref(&self) -> &Self::Target {
436        &self.handle
437    }
438}