demo_vk/graphics/vulkan/frames_in_flight/
mod.rs1use {
2 crate::{
3 graphics::vulkan::{
4 raii, AcquireImageStatus, PresentImageStatus, Swapchain,
5 VulkanContext,
6 },
7 trace,
8 },
9 anyhow::{Context, Result},
10 ash::vk::{self, Handle},
11 std::{ffi::CString, sync::Arc},
12};
13
14#[derive(Debug, Copy, Clone, PartialEq, Eq)]
15pub enum FrameStatus {
16 FrameStarted(Frame),
21
22 SwapchainNeedsRebuild,
24}
25
26#[derive(Debug, Copy, Clone, PartialEq, Eq)]
29pub struct Frame {
30 command_buffer: vk::CommandBuffer,
31 swapchain_image_index: u32,
32 frame_index: usize,
33 swapchain_image: vk::Image,
34 swapchain_image_view: vk::ImageView,
35}
36
37impl Frame {
38 pub fn command_buffer(&self) -> vk::CommandBuffer {
39 self.command_buffer
40 }
41
42 pub fn swapchain_image_index(&self) -> u32 {
43 self.swapchain_image_index
44 }
45
46 pub fn frame_index(&self) -> usize {
47 self.frame_index
48 }
49
50 pub fn swapchain_image(&self) -> vk::Image {
51 self.swapchain_image
52 }
53
54 pub fn swapchain_image_view(&self) -> vk::ImageView {
55 self.swapchain_image_view
56 }
57}
58
59#[derive(Debug, Eq, PartialEq, Copy, Clone)]
61enum FrameSyncStatus {
62 Assembling,
66
67 Pending,
70}
71
72#[derive(Debug)]
74struct FrameSync {
75 status: FrameSyncStatus,
76 swapchain_image_acquired: raii::Semaphore,
77 graphics_commands_complete: raii::Fence,
78 command_pool: raii::CommandPool,
79 command_buffer: vk::CommandBuffer,
80}
81
82#[doc = simple_mermaid::mermaid!("./frames_in_flight_diagram.mmd")]
89#[derive(Debug)]
98pub struct FramesInFlight {
99 swapchain_image_present_semaphores: Vec<raii::Semaphore>,
102
103 frames: Vec<FrameSync>,
104 frame_index: usize,
105 cxt: Arc<VulkanContext>,
106}
107
108impl FramesInFlight {
109 pub fn new(
111 ctx: Arc<VulkanContext>,
112 swapchain_image_count: usize,
113 frame_count: usize,
114 ) -> Result<Self> {
115 let mut swapchain_image_present_semaphores =
117 Vec::with_capacity(swapchain_image_count);
118 for i in 0..swapchain_image_count {
119 swapchain_image_present_semaphores.push(raii::Semaphore::new(
120 format!("Swapchain Image Present [{}]", i),
121 ctx.device.clone(),
122 &vk::SemaphoreCreateInfo::default(),
123 )?);
124 }
125
126 let mut frames = Vec::with_capacity(frame_count);
128 for index in 0..frame_count {
129 let command_pool = raii::CommandPool::new(
130 format!("frame [{}]", index),
131 ctx.device.clone(),
132 &vk::CommandPoolCreateInfo {
133 flags: vk::CommandPoolCreateFlags::TRANSIENT,
134 queue_family_index: ctx.graphics_queue_family_index,
135 ..Default::default()
136 },
137 )
138 .with_context(trace!(
139 "Error while creating command pool for frame {}",
140 index
141 ))?;
142 let command_buffer = unsafe {
143 ctx.allocate_command_buffers(&vk::CommandBufferAllocateInfo {
144 command_pool: command_pool.raw,
145 level: vk::CommandBufferLevel::PRIMARY,
146 command_buffer_count: 1,
147 ..Default::default()
148 })?[0]
149 };
150 let buffer_name =
151 CString::new(format!("Frame [{}] Commands", index)).unwrap();
152 ctx.device
153 .set_debug_name(&vk::DebugUtilsObjectNameInfoEXT {
154 object_type: vk::ObjectType::COMMAND_BUFFER,
155 object_handle: command_buffer.as_raw(),
156 p_object_name: buffer_name.as_ptr(),
157 ..Default::default()
158 })?;
159 frames.push(FrameSync {
160 status: FrameSyncStatus::Pending,
161 swapchain_image_acquired: raii::Semaphore::new(
162 format!("image acquired - frame [{}]", index),
163 ctx.device.clone(),
164 &vk::SemaphoreCreateInfo::default(),
165 )
166 .with_context(trace!(
167 "Error while creating semaphore for frame {}",
168 index,
169 ))?,
170 graphics_commands_complete: raii::Fence::new(
171 format!("graphics commands complete - frame [{}]", index),
172 ctx.device.clone(),
173 &vk::FenceCreateInfo {
174 flags: vk::FenceCreateFlags::SIGNALED,
175 ..Default::default()
176 },
177 )
178 .with_context(trace!(
179 "Error creating fence for frame {}",
180 index
181 ))?,
182 command_pool,
183 command_buffer,
184 });
185 }
186 Ok(Self {
187 swapchain_image_present_semaphores,
188 frames,
189 frame_index: 0,
190 cxt: ctx,
191 })
192 }
193
194 pub fn frame_count(&self) -> usize {
196 self.frames.len()
197 }
198
199 pub fn wait_for_all_frames_to_complete(&self) -> Result<()> {
205 let fences = self
206 .frames
207 .iter()
208 .filter(|frame_sync| frame_sync.status == FrameSyncStatus::Pending)
209 .map(|frame_sync| frame_sync.graphics_commands_complete.raw)
210 .collect::<Vec<vk::Fence>>();
211 unsafe {
212 self.cxt
213 .wait_for_fences(&fences, true, u64::MAX)
214 .with_context(trace!(
215 "Error while waiting for all frames to finish rendering!"
216 ))?;
217 }
218 Ok(())
219 }
220
221 pub fn start_frame(
233 &mut self,
234 swapchain: &Swapchain,
235 ) -> Result<FrameStatus> {
236 self.frame_index = (self.frame_index + 1) % self.frames.len();
237
238 let frame_sync = &mut self.frames[self.frame_index];
240 unsafe {
241 self.cxt
244 .wait_for_fences(
245 &[frame_sync.graphics_commands_complete.raw],
246 true,
247 u64::MAX,
248 )
249 .with_context(trace!(
250 "Error while waiting for frame's commands to complete!"
251 ))?;
252 self.cxt
253 .reset_fences(&[frame_sync.graphics_commands_complete.raw])
254 .with_context(trace!(
255 "Error while resetting the frame's fence!"
256 ))?;
257 frame_sync.status = FrameSyncStatus::Assembling;
259 };
260
261 let status = swapchain
263 .acquire_image(frame_sync.swapchain_image_acquired.raw)
264 .with_context(trace!(
265 "Error while acquiring swapchain image for frame!"
266 ))?;
267 let swapchain_image_index = match status {
268 AcquireImageStatus::ImageAcquired(index) => index,
269 _ => {
270 return Ok(FrameStatus::SwapchainNeedsRebuild);
271 }
272 };
273
274 unsafe {
276 self.cxt
277 .reset_command_pool(
278 frame_sync.command_pool.raw,
279 vk::CommandPoolResetFlags::empty(),
280 )
281 .with_context(trace!(
282 "Error while resetting command buffer for frame!"
283 ))?;
284 self.cxt
285 .begin_command_buffer(
286 frame_sync.command_buffer,
287 &vk::CommandBufferBeginInfo {
288 flags: vk::CommandBufferUsageFlags::ONE_TIME_SUBMIT,
289 ..Default::default()
290 },
291 )
292 .with_context(trace!(
293 "Error while beginning the frame's command buffer!"
294 ))?;
295 };
296
297 Ok(FrameStatus::FrameStarted(Frame {
298 command_buffer: frame_sync.command_buffer,
299 swapchain_image_index,
300 frame_index: self.frame_index,
301 swapchain_image: swapchain.images()[swapchain_image_index as usize],
302 swapchain_image_view: swapchain.image_views()
303 [swapchain_image_index as usize]
304 .raw,
305 }))
306 }
307
308 pub fn present_frame(
310 &mut self,
311 swapchain: &Swapchain,
312 frame: Frame,
313 ) -> Result<PresentImageStatus> {
314 let frame_sync = &mut self.frames[frame.frame_index()];
315 unsafe {
316 self.cxt
317 .end_command_buffer(frame_sync.command_buffer)
318 .with_context(trace!(
319 "Error while ending the command buffer!"
320 ))?;
321
322 let wait_stage = vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT;
323 self.cxt
324 .queue_submit(
325 self.cxt.graphics_queue,
326 &[vk::SubmitInfo {
327 wait_semaphore_count: 1,
328 p_wait_semaphores: &frame_sync
329 .swapchain_image_acquired
330 .raw,
331 p_wait_dst_stage_mask: &wait_stage,
332 command_buffer_count: 1,
333 p_command_buffers: &frame_sync.command_buffer,
334 signal_semaphore_count: 1,
335 p_signal_semaphores: &self
336 .swapchain_image_present_semaphores
337 [frame.swapchain_image_index as usize]
338 .raw,
339 ..Default::default()
340 }],
341 frame_sync.graphics_commands_complete.raw,
342 )
343 .with_context(trace!(
344 "Error while submitting frame commands!"
345 ))?;
346 }
347 frame_sync.status = FrameSyncStatus::Pending;
348
349 swapchain
350 .present_image(
351 self.swapchain_image_present_semaphores
352 [frame.swapchain_image_index as usize]
353 .raw,
354 frame.swapchain_image_index(),
355 )
356 .with_context(trace!("Error while presenting swapchain image!"))
357 }
358}
359
360impl Drop for FramesInFlight {
361 fn drop(&mut self) {
362 self.wait_for_all_frames_to_complete().unwrap();
363 unsafe {
364 self.cxt.device_wait_idle().unwrap();
365 }
366 }
367}