1use std::any::TypeId;
35use std::collections::HashMap;
36use std::ops::{Deref, DerefMut};
37use std::sync::Arc;
38
39use repose_core::{PaintCallbackInfo, PaintCallbackPayload, Rect};
40
41#[cfg(not(all(
43 target_arch = "wasm32",
44 any(
45 not(feature = "fragile-send-sync-non-atomic-wasm"),
46 target_feature = "atomics"
47 )
48)))]
49type AnyBox = Box<dyn std::any::Any + Send + Sync>;
50#[cfg(all(
51 target_arch = "wasm32",
52 any(
53 not(feature = "fragile-send-sync-non-atomic-wasm"),
54 target_feature = "atomics"
55 )
56))]
57type AnyBox = Box<dyn std::any::Any>;
58
59#[cfg(not(all(
60 target_arch = "wasm32",
61 any(
62 not(feature = "fragile-send-sync-non-atomic-wasm"),
63 target_feature = "atomics"
64 )
65)))]
66pub trait MaybeSendSync: Send + Sync + 'static {}
67#[cfg(not(all(
68 target_arch = "wasm32",
69 any(
70 not(feature = "fragile-send-sync-non-atomic-wasm"),
71 target_feature = "atomics"
72 )
73)))]
74impl<T: Send + Sync + 'static> MaybeSendSync for T {}
75
76#[cfg(all(
77 target_arch = "wasm32",
78 any(
79 not(feature = "fragile-send-sync-non-atomic-wasm"),
80 target_feature = "atomics"
81 )
82))]
83pub trait MaybeSendSync: 'static {}
84#[cfg(all(
85 target_arch = "wasm32",
86 any(
87 not(feature = "fragile-send-sync-non-atomic-wasm"),
88 target_feature = "atomics"
89 )
90))]
91impl<T: 'static> MaybeSendSync for T {}
92
93#[derive(Default)]
94pub struct CallbackResources {
95 map: HashMap<TypeId, AnyBox>,
96}
97
98impl CallbackResources {
99 pub fn insert<T: MaybeSendSync>(&mut self, value: T) {
100 self.map.insert(TypeId::of::<T>(), Box::new(value));
101 }
102
103 pub fn get<T: MaybeSendSync>(&self) -> Option<&T> {
104 self.map
105 .get(&TypeId::of::<T>())
106 .and_then(|b| b.downcast_ref::<T>())
107 }
108
109 pub fn get_mut<T: MaybeSendSync>(&mut self) -> Option<&mut T> {
110 self.map
111 .get_mut(&TypeId::of::<T>())
112 .and_then(|b| b.downcast_mut::<T>())
113 }
114
115 pub fn get_or_insert_with<T: MaybeSendSync + Default>(&mut self) -> &mut T {
116 let id = TypeId::of::<T>();
117 self.map.entry(id).or_insert_with(|| Box::new(T::default()));
118 self.map.get_mut(&id).unwrap().downcast_mut::<T>().unwrap()
119 }
120
121 pub fn remove<T: 'static>(&mut self) -> Option<T> {
122 self.map
123 .remove(&TypeId::of::<T>())
124 .and_then(|b| b.downcast::<T>().ok())
125 .map(|b| *b)
126 }
127
128 pub fn contains<T: 'static>(&self) -> bool {
129 self.map.contains_key(&TypeId::of::<T>())
130 }
131
132 pub fn len(&self) -> usize {
133 self.map.len()
134 }
135
136 pub fn is_empty(&self) -> bool {
137 self.map.is_empty()
138 }
139
140 pub fn clear(&mut self) {
141 self.map.clear();
142 }
143}
144
145#[derive(Clone, Copy, Debug)]
146pub struct ScreenDescriptor {
147 pub size_in_pixels: [u32; 2],
148 pub pixels_per_point: f32,
149 pub target_format: wgpu::TextureFormat,
151 pub sample_count: u32,
153}
154
155pub struct CallbackRenderPass<'pass, 'encoder> {
156 pass: &'pass mut wgpu::RenderPass<'encoder>,
157 target_format: wgpu::TextureFormat,
158 sample_count: u32,
159}
160
161impl<'pass, 'encoder> CallbackRenderPass<'pass, 'encoder> {
162 pub(crate) fn new(
163 pass: &'pass mut wgpu::RenderPass<'encoder>,
164 target_format: wgpu::TextureFormat,
165 sample_count: u32,
166 ) -> Self {
167 Self {
168 pass,
169 target_format,
170 sample_count,
171 }
172 }
173
174 pub fn target_format(&self) -> wgpu::TextureFormat {
175 self.target_format
176 }
177
178 pub fn sample_count(&self) -> u32 {
179 self.sample_count
180 }
181
182 pub fn set_pipeline(&mut self, pipeline: &wgpu::RenderPipeline) {
183 self.pass.set_pipeline(pipeline);
184 }
185
186 pub fn set_bind_group(&mut self, index: u32, bind_group: &wgpu::BindGroup, offsets: &[u32]) {
187 self.pass.set_bind_group(index, bind_group, offsets);
188 }
189
190 pub fn set_vertex_buffer(&mut self, slot: u32, buffer: wgpu::BufferSlice<'_>) {
191 self.pass.set_vertex_buffer(slot, buffer);
192 }
193
194 pub fn set_index_buffer(&mut self, buffer: wgpu::BufferSlice<'_>, format: wgpu::IndexFormat) {
195 self.pass.set_index_buffer(buffer, format);
196 }
197
198 pub fn set_viewport(
199 &mut self,
200 x: f32,
201 y: f32,
202 width: f32,
203 height: f32,
204 min_depth: f32,
205 max_depth: f32,
206 ) {
207 self.pass
208 .set_viewport(x, y, width, height, min_depth, max_depth);
209 }
210
211 pub fn set_scissor_rect(&mut self, x: u32, y: u32, width: u32, height: u32) {
212 self.pass.set_scissor_rect(x, y, width, height);
213 }
214
215 pub fn set_stencil_reference(&mut self, reference: u32) {
216 self.pass.set_stencil_reference(reference);
217 }
218
219 pub fn draw(&mut self, vertices: std::ops::Range<u32>, instances: std::ops::Range<u32>) {
220 self.pass.draw(vertices, instances);
221 }
222
223 pub fn draw_indexed(
224 &mut self,
225 indices: std::ops::Range<u32>,
226 base_vertex: i32,
227 instances: std::ops::Range<u32>,
228 ) {
229 self.pass.draw_indexed(indices, base_vertex, instances);
230 }
231}
232
233impl<'pass, 'encoder> Deref for CallbackRenderPass<'pass, 'encoder> {
234 type Target = wgpu::RenderPass<'encoder>;
235
236 fn deref(&self) -> &Self::Target {
237 self.pass
238 }
239}
240
241impl<'pass, 'encoder> DerefMut for CallbackRenderPass<'pass, 'encoder> {
242 fn deref_mut(&mut self) -> &mut Self::Target {
243 self.pass
244 }
245}
246
247pub trait WgpuCallback: Send + Sync + 'static {
249 fn resource_key(&self) -> Option<&str> {
250 None
251 }
252
253 fn resource_type_id(&self) -> TypeId {
254 TypeId::of::<Self>()
255 }
256
257 fn prepare(
260 &self,
261 _device: &wgpu::Device,
262 _queue: &wgpu::Queue,
263 _encoder: &mut wgpu::CommandEncoder,
264 _screen_descriptor: &ScreenDescriptor,
265 _resources: &mut CallbackResources,
266 ) -> Vec<wgpu::CommandBuffer> {
267 Vec::new()
268 }
269
270 fn finish_prepare(
272 &self,
273 _device: &wgpu::Device,
274 _queue: &wgpu::Queue,
275 _encoder: &mut wgpu::CommandEncoder,
276 _screen_descriptor: &ScreenDescriptor,
277 _resources: &mut CallbackResources,
278 ) -> Vec<wgpu::CommandBuffer> {
279 Vec::new()
280 }
281
282 fn paint(
283 &self,
284 info: PaintCallbackInfo,
285 render_pass: &mut CallbackRenderPass<'_, '_>,
286 resources: &CallbackResources,
287 );
288}
289
290pub struct Callback(pub Box<dyn WgpuCallback>);
291
292impl Callback {
293 #[deprecated(note = "rect is ignored; use Callback::new(callback) - layout supplies rect")]
294 pub fn new_paint_callback(
295 _rect: Rect,
296 callback: impl WgpuCallback + 'static,
297 ) -> PaintCallbackPayload {
298 Arc::new(Self(Box::new(callback)))
299 }
300
301 #[allow(clippy::new_ret_no_self)]
304 pub fn new(callback: impl WgpuCallback + 'static) -> PaintCallbackPayload {
305 Arc::new(Self(Box::new(callback)))
306 }
307
308 pub fn embedded_view(
311 modifier: repose_core::Modifier,
312 callback: impl WgpuCallback + 'static,
313 ) -> repose_core::View {
314 let payload = Self::new(callback);
315 let mut m = modifier.paint_callback(payload);
316 let has_size = m.size.is_some()
317 || m.width.is_some()
318 || m.height.is_some()
319 || m.fill_max.is_some()
320 || m.fill_max_w.is_some()
321 || m.fill_max_h.is_some();
322 if !has_size {
323 m = m.size(repose_core::Dp(100.0), repose_core::Dp(100.0));
324 }
325 repose_core::View::new(0, repose_core::ViewKind::Box).modifier(m)
326 }
327}