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