Skip to main content

pebble/wgpu/
render_bundle.rs

1use crate::wgpu::{
2    buffer::Buffer, buffers::BindGroup, material::RenderPipeline, render_pass::IndexFormat,
3    texture_format::TextureFormat,
4};
5
6/// Describes a [`RenderBundleEncoder`] — the color/depth-stencil formats and
7/// sample count it (and every render pass it's later executed in via
8/// [`RenderPass::execute_bundles`](super::render_pass::RenderPass::execute_bundles))
9/// must match exactly.
10pub struct RenderBundleEncoderDescriptor<'a> {
11    pub label: Option<&'a str>,
12    /// One entry per color attachment the bundle will be executed against,
13    /// in the same order — `None` for an attachment slot the bundle doesn't
14    /// touch.
15    pub color_formats: Vec<Option<TextureFormat>>,
16    /// `None` if the render pass(es) this bundle runs in have no depth
17    /// attachment.
18    pub depth_stencil_format: Option<TextureFormat>,
19    /// Whether this bundle only reads the depth aspect (never writes it).
20    pub depth_read_only: bool,
21    /// Whether this bundle only reads the stencil aspect (never writes it).
22    pub stencil_read_only: bool,
23    /// Must match the sample count of every attachment the bundle is
24    /// executed against — see [`TextureBuilder::sample_count`](super::texture_view::TextureBuilder::sample_count).
25    pub sample_count: u32,
26}
27
28impl<'a> Default for RenderBundleEncoderDescriptor<'a> {
29    fn default() -> Self {
30        Self {
31            label: None,
32            color_formats: Vec::new(),
33            depth_stencil_format: None,
34            depth_read_only: false,
35            stencil_read_only: false,
36            sample_count: 1,
37        }
38    }
39}
40
41/// Records a reusable sequence of draw calls — build via
42/// [`WGPUBackend::create_render_bundle_encoder`](super::backend::WGPUBackend::create_render_bundle_encoder),
43/// record with the same `set_pipeline`/`set_bind_group`/`set_vertex_buffer`/
44/// `set_index_buffer`/`draw`/`draw_indexed` shape as
45/// [`RenderPass`](super::render_pass::RenderPass), then
46/// [`finish`](Self::finish) into a [`RenderBundle`]. Re-executing a bundle
47/// via [`RenderPass::execute_bundles`](super::render_pass::RenderPass::execute_bundles)
48/// is often cheaper than re-recording the same draws by hand every frame —
49/// worth it once you have many draw calls that don't change pipeline/bind
50/// group/buffers from one frame to the next (static scene geometry, say).
51pub struct RenderBundleEncoder<'a> {
52    raw: wgpu::RenderBundleEncoder<'a>,
53}
54
55impl<'a> RenderBundleEncoder<'a> {
56    pub(crate) fn new(raw: wgpu::RenderBundleEncoder<'a>) -> Self {
57        Self { raw }
58    }
59
60    pub fn set_pipeline(&mut self, pipeline: &'a RenderPipeline) {
61        self.raw.set_pipeline(pipeline.raw());
62    }
63
64    /// `offsets` is the dynamic-offset slice for any dynamic-offset entries
65    /// in this bind group's layout — see
66    /// [`RenderPass::set_bind_group`](super::render_pass::RenderPass::set_bind_group).
67    pub fn set_bind_group(&mut self, index: u32, bind_group: &'a BindGroup, offsets: &[u32]) {
68        self.raw.set_bind_group(index, Some(bind_group.raw()), offsets);
69    }
70
71    /// Binds `buffer` in its entirety at vertex slot `slot`.
72    pub fn set_vertex_buffer(&mut self, slot: u32, buffer: &'a Buffer) {
73        self.raw.set_vertex_buffer(slot, buffer.raw().slice(..));
74    }
75
76    /// Binds `buffer` in its entirety as the index buffer.
77    pub fn set_index_buffer(&mut self, buffer: &'a Buffer, format: IndexFormat) {
78        self.raw.set_index_buffer(buffer.raw().slice(..), format.into());
79    }
80
81    pub fn draw(&mut self, vertices: std::ops::Range<u32>, instances: std::ops::Range<u32>) {
82        self.raw.draw(vertices, instances);
83    }
84
85    pub fn draw_indexed(
86        &mut self,
87        indices: std::ops::Range<u32>,
88        base_vertex: i32,
89        instances: std::ops::Range<u32>,
90    ) {
91        self.raw.draw_indexed(indices, base_vertex, instances);
92    }
93
94    /// Stops recording and returns the replayable [`RenderBundle`].
95    pub fn finish(self, label: Option<&str>) -> RenderBundle {
96        RenderBundle(self.raw.finish(&wgpu::RenderBundleDescriptor { label }))
97    }
98}
99
100/// A pre-recorded, replayable sequence of draw calls — built via
101/// [`RenderBundleEncoder::finish`], replayed via
102/// [`RenderPass::execute_bundles`](super::render_pass::RenderPass::execute_bundles).
103/// There's no way to reach the underlying `wgpu::RenderBundle` from outside
104/// this crate.
105pub struct RenderBundle(wgpu::RenderBundle);
106
107impl RenderBundle {
108    pub(crate) fn raw(&self) -> &wgpu::RenderBundle {
109        &self.0
110    }
111}