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