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