1use crate::color::{ColorInfo, PixelFormat};
2use crate::{ImageHandle, request_frame};
3
4#[derive(Debug)]
5pub enum RenderCommand {
6 SetImageEncoded {
7 handle: ImageHandle,
8 bytes: Vec<u8>,
9 srgb: bool,
10 },
11 SetImageRgba8 {
12 handle: ImageHandle,
13 w: u32,
14 h: u32,
15 rgba: Vec<u8>,
16 srgb: bool,
17 },
18 SetImageNv12 {
19 handle: ImageHandle,
20 w: u32,
21 h: u32,
22 y: Vec<u8>,
23 uv: Vec<u8>,
24 color_info: ColorInfo,
25 },
26 SetImagePlanes {
27 handle: ImageHandle,
28 w: u32,
29 h: u32,
30 pixel_format: PixelFormat,
31 planes: Vec<Vec<u8>>,
32 color_info: ColorInfo,
33 },
34 RemoveImage {
35 handle: ImageHandle,
36 },
37}
38
39#[cfg(not(target_arch = "wasm32"))]
40mod imp {
41 use super::*;
42 use std::collections::{HashMap, HashSet};
43 use std::sync::atomic::{AtomicU64, Ordering};
44 use std::sync::{Arc, Mutex};
45
46 struct Queue {
47 updates: HashMap<ImageHandle, RenderCommand>,
48 removals: HashSet<ImageHandle>,
49 }
50
51 impl Queue {
52 fn new() -> Self {
53 Self {
54 updates: HashMap::new(),
55 removals: HashSet::new(),
56 }
57 }
58 }
59
60 #[derive(Clone)]
61 pub struct RenderContext {
62 next: Arc<AtomicU64>,
63 q: Arc<Mutex<Queue>>,
64 }
65
66 impl RenderContext {
67 pub fn new() -> Self {
68 Self {
69 next: Arc::new(AtomicU64::new(1)),
70 q: Arc::new(Mutex::new(Queue::new())),
71 }
72 }
73
74 pub fn alloc_image_handle(&self) -> ImageHandle {
75 self.next.fetch_add(1, Ordering::Relaxed)
76 }
77
78 pub fn set_image_encoded(&self, handle: ImageHandle, bytes: Vec<u8>, srgb: bool) {
79 let mut q = self.q.lock().unwrap();
80 q.removals.remove(&handle);
81 q.updates.insert(
82 handle,
83 RenderCommand::SetImageEncoded {
84 handle,
85 bytes,
86 srgb,
87 },
88 );
89 request_frame();
90 }
91
92 pub fn set_image_rgba8(
93 &self,
94 handle: ImageHandle,
95 w: u32,
96 h: u32,
97 rgba: Vec<u8>,
98 srgb: bool,
99 ) {
100 let mut q = self.q.lock().unwrap();
101 q.removals.remove(&handle);
102 q.updates.insert(
103 handle,
104 RenderCommand::SetImageRgba8 {
105 handle,
106 w,
107 h,
108 rgba,
109 srgb,
110 },
111 );
112 request_frame();
113 }
114
115 pub fn set_image_nv12(
116 &self,
117 handle: ImageHandle,
118 w: u32,
119 h: u32,
120 y: Vec<u8>,
121 uv: Vec<u8>,
122 color_info: ColorInfo,
123 ) {
124 self.set_image_planes(handle, w, h, PixelFormat::Nv12, vec![y, uv], color_info);
125 }
126
127 pub fn set_image_planes(
128 &self,
129 handle: ImageHandle,
130 w: u32,
131 h: u32,
132 pixel_format: PixelFormat,
133 planes: Vec<Vec<u8>>,
134 color_info: ColorInfo,
135 ) {
136 let mut q = self.q.lock().unwrap();
137 q.removals.remove(&handle);
138 q.updates.insert(
139 handle,
140 RenderCommand::SetImagePlanes {
141 handle,
142 w,
143 h,
144 pixel_format,
145 planes,
146 color_info,
147 },
148 );
149 request_frame();
150 }
151
152 pub fn remove_image(&self, handle: ImageHandle) {
153 let mut q = self.q.lock().unwrap();
154 q.removals.remove(&handle);
155 q.updates.remove(&handle);
156 request_frame();
157 }
158
159 pub fn drain(&self) -> Vec<RenderCommand> {
160 let mut q = self.q.lock().unwrap();
161 let mut result = Vec::with_capacity(q.removals.len() + q.updates.len());
162
163 for handle in q.removals.drain() {
164 result.push(RenderCommand::RemoveImage { handle });
165 }
166
167 for (_, cmd) in q.updates.drain() {
168 result.push(cmd);
169 }
170
171 result
172 }
173 }
174
175 impl Default for RenderContext {
176 fn default() -> Self {
177 Self::new()
178 }
179 }
180}
181
182#[cfg(target_arch = "wasm32")]
183mod imp {
184 use super::*;
185 use std::cell::RefCell;
186 use std::collections::{HashMap, HashSet};
187 use std::rc::Rc;
188
189 struct Queue {
190 updates: HashMap<ImageHandle, RenderCommand>,
191 removals: HashSet<ImageHandle>,
192 }
193
194 struct Inner {
195 next: ImageHandle,
196 q: Queue,
197 }
198
199 #[derive(Clone)]
200 pub struct RenderContext {
201 inner: Rc<RefCell<Inner>>,
202 }
203
204 impl RenderContext {
205 pub fn new() -> Self {
206 Self {
207 inner: Rc::new(RefCell::new(Inner {
208 next: 1,
209 q: Queue {
210 updates: HashMap::new(),
211 removals: HashSet::new(),
212 },
213 })),
214 }
215 }
216
217 pub fn alloc_image_handle(&self) -> ImageHandle {
218 let mut s = self.inner.borrow_mut();
219 let id = s.next;
220 s.next += 1;
221 id
222 }
223
224 pub fn set_image_encoded(&self, handle: ImageHandle, bytes: Vec<u8>, srgb: bool) {
225 let mut s = self.inner.borrow_mut();
226 s.q.removals.remove(&handle);
227 s.q.updates.insert(
228 handle,
229 RenderCommand::SetImageEncoded {
230 handle,
231 bytes,
232 srgb,
233 },
234 );
235 request_frame();
236 }
237
238 pub fn set_image_rgba8(
239 &self,
240 handle: ImageHandle,
241 w: u32,
242 h: u32,
243 rgba: Vec<u8>,
244 srgb: bool,
245 ) {
246 let mut s = self.inner.borrow_mut();
247 s.q.removals.remove(&handle);
248 s.q.updates.insert(
249 handle,
250 RenderCommand::SetImageRgba8 {
251 handle,
252 w,
253 h,
254 rgba,
255 srgb,
256 },
257 );
258 request_frame();
259 }
260
261 pub fn set_image_nv12(
262 &self,
263 handle: ImageHandle,
264 w: u32,
265 h: u32,
266 y: Vec<u8>,
267 uv: Vec<u8>,
268 color_info: ColorInfo,
269 ) {
270 self.set_image_planes(handle, w, h, PixelFormat::Nv12, vec![y, uv], color_info);
271 }
272
273 pub fn set_image_planes(
274 &self,
275 handle: ImageHandle,
276 w: u32,
277 h: u32,
278 pixel_format: PixelFormat,
279 planes: Vec<Vec<u8>>,
280 color_info: ColorInfo,
281 ) {
282 let mut s = self.inner.borrow_mut();
283 s.q.removals.remove(&handle);
284 s.q.updates.insert(
285 handle,
286 RenderCommand::SetImagePlanes {
287 handle,
288 w,
289 h,
290 pixel_format,
291 planes,
292 color_info,
293 },
294 );
295 request_frame();
296 }
297
298 pub fn remove_image(&self, handle: ImageHandle) {
299 let mut s = self.inner.borrow_mut();
300 s.q.updates.remove(&handle);
301 s.q.removals.insert(handle);
302 request_frame();
303 }
304
305 pub fn drain(&self) -> Vec<RenderCommand> {
306 let mut s = self.inner.borrow_mut();
307 let mut result = Vec::with_capacity(s.q.removals.len() + s.q.updates.len());
308
309 for handle in s.q.removals.drain() {
310 result.push(RenderCommand::RemoveImage { handle });
311 }
312
313 for (_, cmd) in s.q.updates.drain() {
314 result.push(cmd);
315 }
316
317 result
318 }
319 }
320
321 impl Default for RenderContext {
322 fn default() -> Self {
323 Self::new()
324 }
325 }
326}
327
328pub use imp::RenderContext;
329
330pub struct ImageHandleGuard {
332 pub handle: ImageHandle,
333 rc: RenderContext,
334}
335
336impl ImageHandleGuard {
337 pub fn new(rc: &RenderContext) -> Self {
338 Self {
339 handle: rc.alloc_image_handle(),
340 rc: rc.clone(),
341 }
342 }
343}
344
345impl Drop for ImageHandleGuard {
346 fn drop(&mut self) {
347 self.rc.remove_image(self.handle);
348 }
349}
350
351impl std::ops::Deref for ImageHandleGuard {
352 type Target = ImageHandle;
353 fn deref(&self) -> &Self::Target {
354 &self.handle
355 }
356}