1use std::{fmt::Debug, marker::PhantomData, ops::Deref};
2
3use tracing::{info, warn};
4use wgpu::util::DeviceExt;
5
6pub mod collections {
7 use slotmap::{Key, SecondaryMap, SlotMap};
8 use std::{
9 any::{Any, TypeId},
10 collections::HashMap,
11 };
12
13 pub struct Graph<K: Key, N> {
14 nodes: SlotMap<K, N>,
15 nexts: SecondaryMap<K, Vec<K>>,
16 prevs: SecondaryMap<K, Vec<K>>,
17 }
18
19 impl<K: Key, N> Default for Graph<K, N> {
20 fn default() -> Self {
21 Self {
22 nodes: SlotMap::default(),
23 nexts: SecondaryMap::default(),
24 prevs: SecondaryMap::default(),
25 }
26 }
27 }
28
29 impl<K: Key, N> Graph<K, N> {
30 pub fn new() -> Self {
31 Self::default()
32 }
33 pub fn insert_node(&mut self, node: N) -> K {
34 let key = self.nodes.insert(node);
35 self.nexts.insert(key, Vec::new());
36 self.prevs.insert(key, Vec::new());
37 key
38 }
39 pub fn insert_edge(&mut self, from: K, to: K) {
40 self.nexts.get_mut(from).unwrap().push(to);
41 self.prevs.get_mut(to).unwrap().push(from);
42 }
43 pub fn iter(&self) -> GraphTopoIter<'_, K, N> {
44 GraphTopoIter::new(self)
45 }
46 }
47
48 pub struct GraphTopoIter<'a, K: Key, N> {
49 graph: &'a Graph<K, N>,
50 in_degrees: SecondaryMap<K, usize>,
51 ready_stack: Vec<K>,
52 }
53
54 impl<'a, K: Key, N> GraphTopoIter<'a, K, N> {
55 fn new(graph: &'a Graph<K, N>) -> Self {
56 let mut in_degrees = SecondaryMap::new();
57 let mut ready_stack = Vec::new();
58
59 for (key, _) in graph.nodes.iter() {
60 let degree = graph.prevs[key].len();
61 in_degrees.insert(key, degree);
62
63 if degree == 0 {
64 ready_stack.push(key);
65 }
66 }
67
68 Self {
69 graph,
70 in_degrees,
71 ready_stack,
72 }
73 }
74 }
75
76 impl<'a, K: Key, N> Iterator for GraphTopoIter<'a, K, N> {
77 type Item = &'a N;
78
79 fn next(&mut self) -> Option<Self::Item> {
80 let current_key = self.ready_stack.pop()?;
81
82 let next_nodes = self.graph.nexts.get(current_key).unwrap();
83 for &next_key in next_nodes {
84 let degree = self.in_degrees.get_mut(next_key).unwrap();
85 *degree -= 1;
86 if *degree == 0 {
87 self.ready_stack.push(next_key);
88 }
89 }
90
91 self.graph.nodes.get(current_key)
92 }
93 }
94
95 pub trait AnyClear: Any + Send + Sync {
97 fn clear(&mut self);
98 }
99
100 impl<T: Any + Send + Sync> AnyClear for Vec<T> {
101 fn clear(&mut self) {
102 self.clear();
103 }
104 }
105
106 #[derive(Default)]
110 pub struct TypeBinnedVec {
111 inner: HashMap<TypeId, Box<dyn AnyClear>>,
112 }
113
114 impl TypeBinnedVec {
115 fn init_row<T: Send + Sync + 'static>(&mut self) -> &mut Vec<T> {
116 #[allow(clippy::unwrap_or_default)]
117 let entry = self
118 .inner
119 .entry(TypeId::of::<T>())
120 .or_insert(Box::<Vec<T>>::default());
121 (entry.as_mut() as &mut dyn Any)
122 .downcast_mut::<Vec<T>>()
123 .unwrap()
124 }
125 pub fn get_row<T: Send + Sync + 'static>(&self) -> &[T] {
126 self.inner
127 .get(&TypeId::of::<T>())
128 .and_then(|v| (v.as_ref() as &dyn Any).downcast_ref::<Vec<T>>())
129 .map(|v| v.as_ref())
130 .unwrap_or(&[])
131 }
132 pub fn extend<T: Send + Sync + 'static>(&mut self, packets: impl IntoIterator<Item = T>) {
133 self.init_row::<T>().extend(packets);
134 }
135 pub fn push<T: Send + Sync + 'static>(&mut self, packet: T) {
136 self.init_row::<T>().push(packet);
137 }
138 pub fn clear(&mut self) {
139 self.inner.iter_mut().for_each(|(_, v)| {
140 v.clear();
141 });
142 }
143 }
144}
145
146pub struct WgpuContext {
148 pub instance: wgpu::Instance,
150 pub adapter: wgpu::Adapter,
152 pub device: wgpu::Device,
154 pub queue: wgpu::Queue,
156}
157
158impl WgpuContext {
159 pub async fn new() -> Self {
161 let instance = wgpu::Instance::default();
162 let adapter = instance
163 .request_adapter(&wgpu::RequestAdapterOptions {
164 power_preference: wgpu::PowerPreference::HighPerformance,
165 ..Default::default()
166 })
167 .await
168 .unwrap();
169 info!("wgpu adapter info: {:?}", adapter.get_info());
170
171 #[cfg(feature = "profiling")]
172 let (device, queue) = adapter
173 .request_device(&wgpu::DeviceDescriptor {
174 label: None,
175 required_features: adapter.features()
176 & wgpu_profiler::GpuProfiler::ALL_WGPU_TIMER_FEATURES,
177 required_limits: wgpu::Limits::default(),
178 memory_hints: wgpu::MemoryHints::default(),
179 trace: wgpu::Trace::Off,
180 experimental_features: wgpu::ExperimentalFeatures::disabled(),
181 })
182 .await
183 .unwrap();
184 #[cfg(not(feature = "profiling"))]
185 let (device, queue) = adapter
186 .request_device(&wgpu::DeviceDescriptor::default())
187 .await
188 .unwrap();
189
190 Self {
191 instance,
192 adapter,
193 device,
194 queue,
195 }
196 }
197}
198
199#[allow(unused)]
200pub(crate) struct WgpuBuffer<T: bytemuck::Pod + bytemuck::Zeroable + Debug> {
201 label: Option<&'static str>,
202 buffer: wgpu::Buffer,
203 usage: wgpu::BufferUsages,
204 inner: T,
205}
206
207impl<T: bytemuck::Pod + bytemuck::Zeroable + Debug> AsRef<wgpu::Buffer> for WgpuBuffer<T> {
208 fn as_ref(&self) -> &wgpu::Buffer {
209 &self.buffer
210 }
211}
212
213#[allow(unused)]
214impl<T: bytemuck::Pod + bytemuck::Zeroable + Debug> WgpuBuffer<T> {
215 pub(crate) fn new_init(
216 ctx: &WgpuContext,
217 label: Option<&'static str>,
218 usage: wgpu::BufferUsages,
219 data: T,
220 ) -> Self {
221 assert!(
222 usage.contains(wgpu::BufferUsages::COPY_DST),
223 "Buffer {label:?} does not contains COPY_DST"
224 );
225 Self {
227 label,
228 buffer: ctx
229 .device
230 .create_buffer_init(&wgpu::util::BufferInitDescriptor {
231 label,
232 contents: bytemuck::bytes_of(&data),
233 usage,
234 }),
235 usage,
236 inner: data,
237 }
238 }
239
240 pub(crate) fn get(&self) -> &T {
241 &self.inner
242 }
243
244 pub(crate) fn set(&mut self, ctx: &WgpuContext, data: T) {
245 {
246 let mut view = ctx
247 .queue
248 .write_buffer_with(
249 &self.buffer,
250 0,
251 wgpu::BufferSize::new(std::mem::size_of_val(&data) as u64).unwrap(),
252 )
253 .unwrap();
254 view.copy_from_slice(bytemuck::bytes_of(&data));
255 }
256 self.inner = data;
258 }
259
260 #[allow(unused)]
261 pub(crate) fn read_buffer(&self, ctx: &WgpuContext) -> Vec<u8> {
262 let size = std::mem::size_of::<T>();
263 let staging_buffer = ctx.device.create_buffer(&wgpu::BufferDescriptor {
264 label: Some("Debug Staging Buffer"),
265 size: size as u64,
266 usage: wgpu::BufferUsages::MAP_READ | wgpu::BufferUsages::COPY_DST,
267 mapped_at_creation: false,
268 });
269
270 let mut encoder = ctx
271 .device
272 .create_command_encoder(&wgpu::CommandEncoderDescriptor {
273 label: Some("Debug Read Encoder"),
274 });
275
276 encoder.copy_buffer_to_buffer(&self.buffer, 0, &staging_buffer, 0, size as u64);
277 ctx.queue.submit(Some(encoder.finish()));
278
279 let buffer_slice = staging_buffer.slice(..);
280 let (tx, rx) = async_channel::bounded(1);
281 buffer_slice.map_async(wgpu::MapMode::Read, move |result| {
282 pollster::block_on(tx.send(result)).unwrap()
283 });
284 ctx.device
285 .poll(wgpu::PollType::wait_indefinitely())
286 .unwrap();
287 pollster::block_on(rx.recv()).unwrap().unwrap();
288
289 buffer_slice.get_mapped_range().to_vec()
290 }
291}
292
293pub(crate) struct WgpuVecBuffer<T: Default + bytemuck::Pod + bytemuck::Zeroable + Debug> {
294 label: Option<&'static str>,
295 pub(crate) buffer: wgpu::Buffer,
296 usage: wgpu::BufferUsages,
297 len: usize,
299 _phantom: PhantomData<T>,
300 }
302
303impl<T: Default + bytemuck::Pod + bytemuck::Zeroable + Debug> WgpuVecBuffer<T> {
304 pub(crate) fn new(
305 ctx: &WgpuContext,
306 label: Option<&'static str>,
307 usage: wgpu::BufferUsages,
308 len: usize,
309 ) -> Self {
310 assert!(
311 usage.contains(wgpu::BufferUsages::COPY_DST),
312 "Buffer {label:?} does not contains COPY_DST"
313 );
314 let size = (std::mem::size_of::<T>() * len) as u64;
315 Self {
316 label,
317 buffer: ctx.device.create_buffer(&wgpu::BufferDescriptor {
318 label,
319 size,
320 usage,
321 mapped_at_creation: false,
322 }),
323 usage,
324 len: 0,
325 _phantom: PhantomData,
326 }
328 }
329
330 #[allow(unused)]
331 pub(crate) fn new_init(
332 ctx: &WgpuContext,
333 label: Option<&'static str>,
334 usage: wgpu::BufferUsages,
335 data: &[T],
336 ) -> Self {
337 let mut buffer = Self::new(ctx, label, usage, data.len());
338 buffer.set(ctx, data);
339 buffer
340 }
341
342 #[allow(unused)]
343 pub(crate) fn len(&self) -> usize {
344 self.len
345 }
346 #[allow(unused)]
351 pub(crate) fn resize(&mut self, ctx: &WgpuContext, len: usize) -> bool {
352 let size = (std::mem::size_of::<T>() * len) as u64;
353 let realloc = self.buffer.size() != size;
354 if realloc {
355 self.len = len;
356 self.buffer = ctx.device.create_buffer(&wgpu::BufferDescriptor {
358 label: self.label,
359 size,
360 usage: self.usage,
361 mapped_at_creation: false,
362 })
363 }
364 realloc
365 }
366
367 pub(crate) fn set(&mut self, ctx: &WgpuContext, data: &[T]) -> bool {
368 self.len = data.len();
372 let realloc = self.buffer.size() != std::mem::size_of_val(data) as u64;
373
374 if realloc {
375 let buffer = ctx.device.create_buffer(&wgpu::BufferDescriptor {
378 label: self.label,
379 size: (std::mem::size_of_val(data)) as u64,
380 usage: self.usage,
381 mapped_at_creation: false,
382 });
383 ctx.queue
384 .write_buffer(&buffer, 0, bytemuck::cast_slice(data));
385 self.buffer = buffer;
387 } else {
388 {
390 let mut view = ctx
391 .queue
392 .write_buffer_with(
393 &self.buffer,
394 0,
395 wgpu::BufferSize::new((std::mem::size_of_val(data)) as u64).unwrap(),
396 )
397 .unwrap();
398 view.copy_from_slice(bytemuck::cast_slice(data));
399 }
400 }
402 realloc
404 }
405
406 #[allow(unused)]
407 pub(crate) fn read_buffer(&self, ctx: &WgpuContext) -> Option<Vec<u8>> {
408 let size = std::mem::size_of::<T>() * self.len;
409 let staging_buffer = ctx.device.create_buffer(&wgpu::BufferDescriptor {
410 label: Some("Debug Staging Buffer"),
411 size: size as u64,
412 usage: wgpu::BufferUsages::MAP_READ | wgpu::BufferUsages::COPY_DST,
413 mapped_at_creation: false,
414 });
415
416 let mut encoder = ctx
417 .device
418 .create_command_encoder(&wgpu::CommandEncoderDescriptor {
419 label: Some("Debug Read Encoder"),
420 });
421
422 encoder.copy_buffer_to_buffer(&self.buffer, 0, &staging_buffer, 0, size as u64);
423 ctx.queue.submit(Some(encoder.finish()));
424
425 let buffer_slice = staging_buffer.slice(..);
426 let (tx, rx) = async_channel::bounded(1);
427 buffer_slice.map_async(wgpu::MapMode::Read, move |result| {
428 tx.try_send(result).unwrap()
429 });
430 ctx.device
431 .poll(wgpu::PollType::wait_indefinitely())
432 .unwrap();
433 pollster::block_on(rx.recv()).unwrap().unwrap();
434
435 let x = buffer_slice.get_mapped_range().to_vec();
436 Some(x)
437 }
438}
439
440pub struct WgpuTexture {
441 inner: wgpu::Texture,
442}
443
444impl WgpuTexture {
445 pub fn new(ctx: &WgpuContext, desc: &wgpu::TextureDescriptor) -> Self {
446 Self {
447 inner: ctx.device.create_texture(desc),
448 }
449 }
450}
451
452impl Deref for WgpuTexture {
453 type Target = wgpu::Texture;
454 fn deref(&self) -> &Self::Target {
455 &self.inner
456 }
457}
458
459pub struct ReadbackWgpuTexture {
462 inner: WgpuTexture,
463 aligned_bytes_per_row: usize,
464 staging_buffer: wgpu::Buffer,
465 bytes: Vec<u8>,
466 pending_rx: Option<async_channel::Receiver<Result<(), wgpu::BufferAsyncError>>>,
469}
470
471impl Deref for ReadbackWgpuTexture {
472 type Target = WgpuTexture;
473 fn deref(&self) -> &Self::Target {
474 &self.inner
475 }
476}
477
478const ALIGNMENT: usize = 256;
479impl ReadbackWgpuTexture {
480 pub fn new(ctx: &WgpuContext, desc: &wgpu::TextureDescriptor) -> Self {
481 if !desc.usage.contains(wgpu::TextureUsages::COPY_SRC) {
482 warn!(
483 "ReadbackWgpuTexture should have COPY_SRC usage, but got {:?}, will auto add this usage",
484 desc.usage
485 );
486 }
487 let texture = WgpuTexture::new(
488 ctx,
489 &wgpu::TextureDescriptor {
490 usage: desc.usage | wgpu::TextureUsages::COPY_SRC,
491 ..*desc
492 },
493 );
494 let block_size = desc.format.block_copy_size(None).unwrap();
495 let bytes_per_row =
496 (texture.size().width * block_size).div_ceil(ALIGNMENT as u32) as usize * ALIGNMENT;
497
498 let staging_buffer_label = desc.label.map(|s| format!("{s} Staging Buffer"));
499 let staging_buffer = ctx.device.create_buffer(&wgpu::BufferDescriptor {
500 label: staging_buffer_label.as_deref(),
501 size: (bytes_per_row * texture.size().height as usize) as u64,
502 usage: wgpu::BufferUsages::MAP_READ | wgpu::BufferUsages::COPY_DST,
503 mapped_at_creation: false,
504 });
505 let len = texture.size().width * texture.size().height * block_size;
506 let bytes = vec![0u8; len as usize];
507
508 Self {
509 inner: texture,
510 aligned_bytes_per_row: bytes_per_row,
511 staging_buffer,
512 bytes,
513 pending_rx: None,
514 }
515 }
516 pub fn texture_data(&self) -> &[u8] {
517 &self.bytes
518 }
519
520 pub fn start_readback(&mut self, ctx: &WgpuContext) {
525 let size = self.size();
526
527 let mut encoder = ctx
528 .device
529 .create_command_encoder(&wgpu::CommandEncoderDescriptor {
530 label: Some("Readback Copy Encoder"),
531 });
532 encoder.copy_texture_to_buffer(
533 wgpu::TexelCopyTextureInfo {
534 aspect: wgpu::TextureAspect::All,
535 texture: self,
536 mip_level: 0,
537 origin: wgpu::Origin3d::ZERO,
538 },
539 wgpu::TexelCopyBufferInfo {
540 buffer: &self.staging_buffer,
541 layout: wgpu::TexelCopyBufferLayout {
542 offset: 0,
543 bytes_per_row: Some(self.aligned_bytes_per_row as u32),
544 rows_per_image: Some(size.height),
545 },
546 },
547 size,
548 );
549 ctx.queue.submit(Some(encoder.finish()));
550
551 let buffer_slice = self.staging_buffer.slice(..);
552 let (tx, rx) = async_channel::bounded(1);
553 buffer_slice.map_async(wgpu::MapMode::Read, move |result| {
554 let _ = tx.try_send(result);
555 });
556 self.pending_rx = Some(rx);
557 }
558
559 pub fn finish_readback(&mut self, ctx: &WgpuContext) {
564 let Some(rx) = self.pending_rx.take() else {
565 return;
566 };
567
568 ctx.device
569 .poll(wgpu::PollType::wait_indefinitely())
570 .unwrap();
571 pollster::block_on(rx.recv()).unwrap().unwrap();
572
573 self.copy_staging_to_bytes();
574 }
575
576 pub fn try_finish_readback(&mut self, ctx: &WgpuContext) -> bool {
579 let Some(rx) = self.pending_rx.as_ref() else {
580 return true;
581 };
582
583 let _ = ctx.device.poll(wgpu::PollType::Poll);
585
586 match rx.try_recv() {
588 Ok(result) => {
589 result.unwrap();
590 self.pending_rx = None;
591 self.copy_staging_to_bytes();
592 true
593 }
594 Err(async_channel::TryRecvError::Empty) => false,
595 Err(async_channel::TryRecvError::Closed) => {
596 self.pending_rx = None;
597 true
598 }
599 }
600 }
601
602 fn copy_staging_to_bytes(&mut self) {
603 let size = self.size();
604 let buffer_slice = self.staging_buffer.slice(..);
605 let view = buffer_slice.get_mapped_range();
606 let block_size = self.inner.format().block_copy_size(None).unwrap();
607 let bytes_in_row = (size.width * block_size) as usize;
608
609 for y in 0..size.height as usize {
610 let src_row_start = y * self.aligned_bytes_per_row;
611 let dst_row_start = y * bytes_in_row;
612
613 self.bytes[dst_row_start..dst_row_start + bytes_in_row]
614 .copy_from_slice(&view[src_row_start..src_row_start + bytes_in_row]);
615 }
616 drop(view);
617 self.staging_buffer.unmap();
618 }
619
620 pub fn update_texture_data(&mut self, ctx: &WgpuContext) -> &[u8] {
622 self.start_readback(ctx);
623 self.finish_readback(ctx);
624 &self.bytes
625 }
626}
627
628#[cfg(test)]
629mod test {
630 #[test]
631 fn test() {
632 }
638}