blade_render/util/
frame_pacer.rs

1use crate::render::FrameResources;
2use std::mem;
3
4/// Utility object that encapsulates the logic
5/// of always rendering 1 frame at a time, and
6/// cleaning up the temporary resources.
7pub struct FramePacer {
8    frame_index: usize,
9    prev_resources: FrameResources,
10    prev_sync_point: Option<blade_graphics::SyncPoint>,
11    command_encoder: blade_graphics::CommandEncoder,
12    next_resources: FrameResources,
13}
14
15impl FramePacer {
16    pub fn new(context: &blade_graphics::Context) -> Self {
17        let encoder = context.create_command_encoder(blade_graphics::CommandEncoderDesc {
18            name: "main",
19            buffer_count: 2,
20        });
21        Self {
22            frame_index: 0,
23            prev_resources: FrameResources::default(),
24            prev_sync_point: None,
25            command_encoder: encoder,
26            next_resources: FrameResources::default(),
27        }
28    }
29
30    #[profiling::function]
31    pub fn wait_for_previous_frame(&mut self, context: &blade_graphics::Context) {
32        if let Some(sp) = self.prev_sync_point.take() {
33            context.wait_for(&sp, !0);
34        }
35        for buffer in self.prev_resources.buffers.drain(..) {
36            context.destroy_buffer(buffer);
37        }
38        for accel_structure in self.prev_resources.acceleration_structures.drain(..) {
39            context.destroy_acceleration_structure(accel_structure);
40        }
41    }
42
43    pub fn last_sync_point(&self) -> Option<&blade_graphics::SyncPoint> {
44        self.prev_sync_point.as_ref()
45    }
46
47    pub fn destroy(&mut self, context: &blade_graphics::Context) {
48        self.wait_for_previous_frame(context);
49        context.destroy_command_encoder(&mut self.command_encoder);
50    }
51
52    pub fn begin_frame(&mut self) -> (&mut blade_graphics::CommandEncoder, &mut FrameResources) {
53        self.command_encoder.start();
54        (&mut self.command_encoder, &mut self.next_resources)
55    }
56
57    pub fn end_frame(&mut self, context: &blade_graphics::Context) -> &blade_graphics::SyncPoint {
58        let sync_point = context.submit(&mut self.command_encoder);
59        self.frame_index += 1;
60        // Wait for the previous frame immediately - this ensures that we are
61        // only processing one frame at a time, and yet not stalling.
62        self.wait_for_previous_frame(context);
63        self.prev_sync_point = Some(sync_point);
64        mem::swap(&mut self.prev_resources, &mut self.next_resources);
65        self.prev_sync_point.as_ref().unwrap()
66    }
67
68    pub fn timings(&self) -> &blade_graphics::Timings {
69        self.command_encoder.timings()
70    }
71}