Skip to main content

pebble/rendering/
render_plugin.rs

1use crate::{
2    prelude::{Backend, CurrentFrame, Plugin, ResMut, SystemStage},
3    rendering::errors::AcquireError,
4};
5
6/// Plugin that manages the per-frame acquire / present cycle.
7///
8/// Adds a [`CurrentFrame<B>`] resource and two systems:
9/// - [`PreRender`](SystemStage::PreRender): acquires a frame from the backend.
10/// - [`PostRender`](SystemStage::PostRender): presents the completed frame.
11///
12/// Rendering systems should check [`CurrentFrame::is_active`] before issuing
13/// draw calls, as the frame may be absent when the backend is not yet ready or
14/// a transient acquire error occurs.
15pub struct RenderPlugin<B: Backend> {
16    _marker: std::marker::PhantomData<B>,
17}
18
19impl<B: Backend> RenderPlugin<B> {
20    pub fn new() -> Self {
21        Self {
22            _marker: std::marker::PhantomData,
23        }
24    }
25}
26
27impl<B: Backend> Plugin for RenderPlugin<B> {
28    fn build(&self, app: &mut crate::prelude::App) {
29        app.add_resource(CurrentFrame::<B> { frame: None })
30            .add_system(SystemStage::PreRender, begin_frame::<B>)
31            .add_system(SystemStage::PostRender, end_frame::<B>);
32    }
33}
34
35/// PreRender system: acquire the next frame. Clears the current frame on
36/// transient errors and logs fatal ones.
37fn begin_frame<B: Backend>(backend: Option<ResMut<B>>, mut frame: ResMut<CurrentFrame<B>>) {
38    let Some(mut backend) = backend else { return };
39
40    match backend.acquire() {
41        Ok(f) => frame.frame = Some(f),
42        Err(AcquireError::Transient) => frame.frame = None,
43        Err(AcquireError::Fatal(msg)) => {
44            tracing::error!("Fatal frame acquisition error: {msg}");
45            frame.frame = None;
46        }
47    }
48}
49
50/// PostRender system: present the completed frame to the display.
51fn end_frame<B: Backend>(backend: Option<ResMut<B>>, mut current: ResMut<CurrentFrame<B>>) {
52    let Some(mut backend) = backend else { return };
53    if let Some(frame) = current.frame.take() {
54        backend.present(frame);
55    }
56}