rendy_resource/
resources.rs

1use {
2    crate::escape::{Escape, Handle, Terminal},
3    smallvec::SmallVec,
4    std::collections::VecDeque,
5};
6
7/// Resource usage epochs.
8#[doc(hidden)]
9#[derive(Clone, Debug)]
10pub struct Epochs {
11    /// 2D array of epochs.
12    pub values: SmallVec<[SmallVec<[u64; 8]>; 4]>,
13}
14
15impl Epochs {
16    fn is_before(&self, other: &Self) -> bool {
17        debug_assert_eq!(self.values.len(), other.values.len());
18        self.values.iter().zip(other.values.iter()).all(|(a, b)| {
19            debug_assert_eq!(a.len(), b.len());
20            a.iter().zip(b.iter()).all(|(a, b)| a < b)
21        })
22    }
23}
24
25/// Resource handler.
26#[derive(Debug)]
27pub struct ResourceTracker<T> {
28    terminal: Terminal<T>,
29    dropped: VecDeque<(Epochs, T)>,
30}
31
32impl<T> Default for ResourceTracker<T> {
33    fn default() -> Self {
34        ResourceTracker {
35            terminal: Terminal::default(),
36            dropped: VecDeque::default(),
37        }
38    }
39}
40
41impl<T> ResourceTracker<T> {
42    /// Create new resource manager.
43    pub fn new() -> Self {
44        Self::default()
45    }
46
47    /// Wrap resource instance into `Escape`.
48    pub fn escape(&self, resource: T) -> Escape<T>
49    where
50        T: Sized,
51    {
52        Escape::escape(resource, &self.terminal)
53    }
54
55    /// Wrap resource instance into `Handle`.
56    pub fn handle(&self, resource: T) -> Handle<T>
57    where
58        T: Sized,
59    {
60        self.escape(resource).into()
61    }
62
63    /// Cleanup dropped resources.
64    ///
65    /// # Safety
66    ///
67    /// `next` epochs must contain epoch indices that aren't started yet
68    /// `complete` epochs must contain epoch indices that are complete.
69    /// Can be guaranteed with fence wait.
70    ///
71    pub fn cleanup(&mut self, mut dispose: impl FnMut(T), next: &Epochs, complete: &Epochs) {
72        while let Some((epoch, resource)) = self.dropped.pop_front() {
73            if !epoch.is_before(complete) {
74                self.dropped.push_front((epoch, resource));
75                break;
76            }
77
78            dispose(resource);
79        }
80
81        self.dropped
82            .extend(self.terminal.drain().map(|res| (next.clone(), res)));
83    }
84
85    /// Cleanup all dropped resources.
86    ///
87    /// # Safety
88    ///
89    /// All dropped resources must be unused.
90    /// Can be guaranteed with device idle wait.
91    ///
92    pub fn dispose(&mut self, dispose: impl FnMut(T)) {
93        self.dropped
94            .drain(..)
95            .map(|(_, res)| res)
96            .chain(self.terminal.drain())
97            .for_each(dispose);
98    }
99}