Skip to main content

pebble/graphics/render/
frame.rs

1use crate::graphics::render::{render_pass::RenderPass, targets::Pass};
2
3/// The acquired swapchain frame for this tick — access it via
4/// [`CurrentFrame::active`], not directly.
5pub struct Frame {
6    encoder: wgpu::CommandEncoder,
7    view: wgpu::TextureView,
8    surface: wgpu::SurfaceTexture
9}
10
11impl Frame {
12    pub(crate) fn new(encoder: wgpu::CommandEncoder, view: wgpu::TextureView, surface: wgpu::SurfaceTexture) -> Self {
13        Self { encoder, view, surface }
14    }
15
16    pub(crate) fn finish(self) -> (wgpu::CommandEncoder, wgpu::SurfaceTexture) {
17        (self.encoder, self.surface)
18    }
19
20    /// Begins a render pass for `pass`'s color/depth targets — an
21    /// unattached color target falls back to the swapchain's own view.
22    pub fn begin<'a>(&'a mut self, pass: Pass) -> RenderPass<'a> {
23        let color_attachments: Vec<_> = pass
24            .colors
25            .iter()
26            .map(|target| {
27                let view = target.attachment.map(|t| t.raw()).unwrap_or(&self.view);
28
29                Some(wgpu::RenderPassColorAttachment {
30                    view,
31                    resolve_target: None,
32                    depth_slice: None,
33                    ops: wgpu::Operations {
34                        load: wgpu::LoadOp::Clear(wgpu::Color {
35                            r: target.clear[0] as f64,
36                            g: target.clear[1] as f64,
37                            b: target.clear[2] as f64,
38                            a: target.clear[3] as f64,
39                        }),
40                        store: wgpu::StoreOp::Store
41                    }
42                })
43            }).collect();
44
45        let depth_stencil_attachment = pass.depth.as_ref().map(|d| wgpu::RenderPassDepthStencilAttachment {
46            view: d.attachment.raw(),
47            depth_ops: Some(wgpu::Operations {
48                load: wgpu::LoadOp::Clear(d.clear.unwrap()),
49                store: wgpu::StoreOp::Store,
50            }),
51            stencil_ops: None
52        });
53
54        RenderPass::new(self.encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
55            label: None,
56            color_attachments: &color_attachments,
57            depth_stencil_attachment,
58            timestamp_writes: None,
59            occlusion_query_set: None,
60            multiview_mask: None
61        }))
62    }
63}
64
65/// A frame known to be acquired, from [`CurrentFrame::active`]. `Deref`s to
66/// [`Frame`].
67pub struct ActiveFrame<'a> {
68    frame: &'a mut Frame
69}
70
71impl<'a> ActiveFrame<'a>{
72    /// Begins a render pass — see [`Frame::begin`].
73    pub fn begin_pass(&'a mut self, pass: Pass) -> RenderPass<'a> {
74        self.frame.begin(pass)
75    }
76}
77
78impl<'a> std::ops::Deref for ActiveFrame<'a> {
79    type Target = Frame;
80    
81    fn deref(&self) -> &Self::Target {
82        self.frame
83    }
84}
85
86impl<'a> std::ops::DerefMut for ActiveFrame<'a> {
87    fn deref_mut(&mut self) -> &mut Self::Target {
88        self.frame
89    }
90}
91
92/// Resource holding this tick's acquired frame, if any — `None` when the
93/// surface couldn't be acquired (occluded, resizing, etc.), in which case
94/// rendering this tick should just be skipped.
95#[derive(Default)]
96pub struct CurrentFrame {
97    frame: Option<Frame>
98}
99
100impl CurrentFrame {
101    pub(crate) fn set(&mut self, frame: Frame) {
102        self.frame = Some(frame);
103    }
104
105    pub(crate) fn take(&mut self) -> Option<Frame> {
106        self.frame.take()
107    }
108
109    /// The active frame to render into, if one was acquired this tick.
110    pub fn active<'a>(&'a mut self) -> Option<ActiveFrame<'a>>{
111        self.frame.as_mut().map(|f| ActiveFrame {
112            frame: f
113        })
114    }
115}