sierra/backend/vulkan/
epochs.rs

1use std::{collections::VecDeque, convert::TryFrom as _};
2
3use hashbrown::HashMap;
4use parking_lot::Mutex;
5use smallvec::SmallVec;
6
7use crate::QueueId;
8
9use super::{
10    encode::CommandBuffer,
11    resources::{
12        AccelerationStructure, Buffer, ComputePipeline, DescriptorSet, Framebuffer,
13        GraphicsPipeline, Image, ImageView, PipelineLayout, RayTracingPipeline, Sampler,
14    },
15};
16
17pub(super) struct Epochs {
18    queues: HashMap<QueueId, Mutex<QueueEpochs>>,
19}
20
21impl Epochs {
22    pub fn new(queues: impl Iterator<Item = QueueId>) -> Self {
23        Epochs {
24            queues: queues
25                .map(|q| (q, Mutex::new(QueueEpochs::new())))
26                .collect(),
27        }
28    }
29
30    pub fn next_epoch(&self, queue: QueueId) -> u64 {
31        let mut queue = self.queues[&queue].lock();
32        queue.current += 1;
33
34        let epoch = queue.cache.pop_front().unwrap_or_else(Epoch::new);
35        queue.epochs.push_front(epoch);
36
37        #[cfg(feature = "leak-detection")]
38        if queue.epochs.len() > 32 {
39            warn!(
40                "Too many active epochs ({}) accumulated",
41                queue.epochs.len()
42            );
43        }
44
45        queue.current - 1
46    }
47
48    pub fn close_epoch(&self, queue: QueueId, epoch: u64) {
49        let mut queue = self.queues[&queue].lock();
50        debug_assert!(queue.current > epoch);
51        if let Ok(len) = usize::try_from(queue.current - epoch) {
52            if len < queue.epochs.len() {
53                let epochs = queue.epochs.drain(len..).collect::<SmallVec<[_; 16]>>();
54
55                for mut epoch in epochs {
56                    for mut cbuf in epoch.cbufs.drain(..) {
57                        cbuf.references().clear();
58                        queue.cbufs.push(cbuf);
59                    }
60                    queue.cache.push_back(epoch);
61                }
62            }
63        }
64
65        if queue.cache.len() > 64 {
66            warn!("Too large epochs cache accumulated");
67        }
68
69        if queue.cbufs.len() > 1024 {
70            warn!("Too large cbuf cache accumulated");
71        }
72    }
73
74    pub fn next_epoch_all_queues(&self) -> Vec<(QueueId, u64)> {
75        let mut result = Vec::new();
76        for (id, queue) in &self.queues {
77            let mut queue = queue.lock();
78            queue.current += 1;
79
80            let epoch = queue.cache.pop_front().unwrap_or_else(Epoch::new);
81            queue.epochs.push_front(epoch);
82            result.push((*id, queue.current - 1))
83        }
84        result
85    }
86
87    pub fn drain_cbuf(&self, queue: QueueId, cbufs: &mut Vec<CommandBuffer>) {
88        let mut queue = self.queues[&queue].lock();
89        cbufs.append(&mut queue.cbufs);
90    }
91
92    pub fn submit(&self, queue: QueueId, cbufs: impl Iterator<Item = CommandBuffer>) {
93        let mut queue = self.queues[&queue].lock();
94        let front = queue
95            .epochs
96            .front_mut()
97            .unwrap_or_else(|| unsafe { std::hint::unreachable_unchecked() });
98        front.cbufs.extend(cbufs);
99    }
100}
101
102struct QueueEpochs {
103    current: u64,
104    cbufs: Vec<CommandBuffer>,
105    cache: VecDeque<Epoch>,
106    epochs: VecDeque<Epoch>,
107}
108
109impl Drop for QueueEpochs {
110    fn drop(&mut self) {
111        if !std::thread::panicking() {
112            assert!(
113                self.cbufs
114                    .iter_mut()
115                    .all(|cbuf| cbuf.references().is_empty()),
116                "All cbufs must be flushed"
117            );
118            assert!(
119                self.epochs.iter().all(|e| e.cbufs.is_empty()),
120                "All epochs must be flushed"
121            );
122        }
123
124        self.cbufs.clear();
125        self.epochs.clear();
126        self.cache.clear();
127    }
128}
129
130struct Epoch {
131    cbufs: Vec<CommandBuffer>,
132}
133
134impl Epoch {
135    fn new() -> Self {
136        Epoch { cbufs: Vec::new() }
137    }
138}
139
140pub(super) struct References {
141    buffers: Vec<Buffer>,
142    images: Vec<Image>,
143    image_views: Vec<ImageView>,
144    graphics_pipelines: Vec<GraphicsPipeline>,
145    compute_pipelines: Vec<ComputePipeline>,
146    ray_tracing_pipelines: Vec<RayTracingPipeline>,
147    pipeline_layouts: Vec<PipelineLayout>,
148    framebuffers: Vec<Framebuffer>,
149    acceleration_strucutres: Vec<AccelerationStructure>,
150    samplers: Vec<Sampler>,
151    descriptor_sets: Vec<DescriptorSet>,
152}
153
154impl References {
155    pub const fn new() -> Self {
156        References {
157            buffers: Vec::new(),
158            images: Vec::new(),
159            image_views: Vec::new(),
160            graphics_pipelines: Vec::new(),
161            compute_pipelines: Vec::new(),
162            ray_tracing_pipelines: Vec::new(),
163            pipeline_layouts: Vec::new(),
164            framebuffers: Vec::new(),
165            acceleration_strucutres: Vec::new(),
166            samplers: Vec::new(),
167            descriptor_sets: Vec::new(),
168        }
169    }
170
171    pub fn add_buffer(&mut self, buffer: Buffer) {
172        self.buffers.push(buffer);
173    }
174
175    pub fn add_image(&mut self, image: Image) {
176        self.images.push(image);
177    }
178
179    // pub fn add_image_view(&mut self, image_view: ImageView) {
180    //     self.image_views.push(image_view);
181    // }
182
183    pub fn add_graphics_pipeline(&mut self, graphics_pipeline: GraphicsPipeline) {
184        self.graphics_pipelines.push(graphics_pipeline);
185    }
186
187    pub fn add_compute_pipeline(&mut self, compute_pipeline: ComputePipeline) {
188        self.compute_pipelines.push(compute_pipeline);
189    }
190
191    pub fn add_ray_tracing_pipeline(&mut self, ray_tracing_pipeline: RayTracingPipeline) {
192        self.ray_tracing_pipelines.push(ray_tracing_pipeline);
193    }
194
195    pub fn add_pipeline_layout(&mut self, pipeline_layout: PipelineLayout) {
196        self.pipeline_layouts.push(pipeline_layout);
197    }
198
199    pub fn add_framebuffer(&mut self, framebuffer: Framebuffer) {
200        self.framebuffers.push(framebuffer);
201    }
202
203    pub fn add_acceleration_strucutre(&mut self, acceleration_strucutre: AccelerationStructure) {
204        self.acceleration_strucutres.push(acceleration_strucutre);
205    }
206
207    // pub fn add_sampler(&mut self, sampler: Sampler) {
208    //     self.samplers.push(sampler);
209    // }
210
211    pub fn add_descriptor_set(&mut self, descriptor_set: DescriptorSet) {
212        self.descriptor_sets.push(descriptor_set);
213    }
214
215    pub fn is_empty(&self) -> bool {
216        self.buffers.is_empty()
217            && self.images.is_empty()
218            && self.image_views.is_empty()
219            && self.graphics_pipelines.is_empty()
220            && self.compute_pipelines.is_empty()
221            && self.ray_tracing_pipelines.is_empty()
222            && self.pipeline_layouts.is_empty()
223            && self.framebuffers.is_empty()
224            && self.acceleration_strucutres.is_empty()
225            && self.samplers.is_empty()
226            && self.descriptor_sets.is_empty()
227    }
228
229    pub fn clear(&mut self) {
230        self.buffers.clear();
231        self.images.clear();
232        self.image_views.clear();
233        self.graphics_pipelines.clear();
234        self.compute_pipelines.clear();
235        self.ray_tracing_pipelines.clear();
236        self.pipeline_layouts.clear();
237        self.framebuffers.clear();
238        self.acceleration_strucutres.clear();
239        self.samplers.clear();
240        self.descriptor_sets.clear();
241    }
242}
243
244impl QueueEpochs {
245    fn new() -> Self {
246        QueueEpochs {
247            current: 0,
248            cbufs: Vec::new(),
249            cache: VecDeque::new(),
250            epochs: std::iter::once(Epoch::new()).collect(),
251        }
252    }
253}