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}