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