sierra/backend/vulkan/
epochs.rs1use 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_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_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}