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 }
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
393pub 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}