Skip to main content

pebble/wgpu/
render_pass.rs

1use crate::wgpu::{buffer::Buffer, buffers::BindGroup, material::RenderPipeline};
2
3/// A render pass, opaque — the value [`ActiveFrame::begin_pass`](crate::rendering::active_frame::ActiveFrame::begin_pass)/
4/// [`render_context`](crate::rendering::active_frame::ActiveFrame::render_context)
5/// hands back for [`WGPUBackend`](super::backend::WGPUBackend). There's no
6/// way to reach the underlying `wgpu::RenderPass` from outside this crate —
7/// every draw-time operation is a method here instead.
8pub struct RenderPass<'a> {
9    raw: wgpu::RenderPass<'a>,
10}
11
12impl<'a> RenderPass<'a> {
13    pub(crate) fn new(raw: wgpu::RenderPass<'a>) -> Self {
14        Self { raw }
15    }
16
17    pub fn set_pipeline(&mut self, pipeline: &RenderPipeline) {
18        self.raw.set_pipeline(pipeline.raw());
19    }
20
21    /// `offsets` is the dynamic-offset slice for any
22    /// [`BindingKind::dynamic_uniform_buffer`](super::binding::BindingKind::dynamic_uniform_buffer)/
23    /// [`dynamic_storage_buffer`](super::binding::BindingKind::dynamic_storage_buffer)
24    /// entries in this bind group's layout, in the order they appear —
25    /// empty if none.
26    pub fn set_bind_group(&mut self, index: u32, bind_group: &BindGroup, offsets: &[u32]) {
27        self.raw.set_bind_group(index, Some(bind_group.raw()), offsets);
28    }
29
30    /// Binds `buffer` in its entirety at vertex slot `slot`.
31    pub fn set_vertex_buffer(&mut self, slot: u32, buffer: &'a Buffer) {
32        self.raw.set_vertex_buffer(slot, buffer.raw().slice(..));
33    }
34
35    /// Binds `buffer` in its entirety as the index buffer.
36    pub fn set_index_buffer(&mut self, buffer: &'a Buffer, format: IndexFormat) {
37        self.raw.set_index_buffer(buffer.raw().slice(..), format.into());
38    }
39
40    pub fn draw(&mut self, vertices: std::ops::Range<u32>, instances: std::ops::Range<u32>) {
41        self.raw.draw(vertices, instances);
42    }
43
44    pub fn draw_indexed(
45        &mut self,
46        indices: std::ops::Range<u32>,
47        base_vertex: i32,
48        instances: std::ops::Range<u32>,
49    ) {
50        self.raw.draw_indexed(indices, base_vertex, instances);
51    }
52
53    /// Same as [`draw`](Self::draw), but the vertex/instance counts come
54    /// from a [`DrawIndirectArgs`] value already written into
55    /// `indirect_buffer` at `indirect_offset` bytes — for a GPU-driven draw
56    /// count (culling compaction, particle counts, ...) the CPU never reads
57    /// back.
58    pub fn draw_indirect(&mut self, indirect_buffer: &'a Buffer, indirect_offset: u64) {
59        self.raw.draw_indirect(indirect_buffer.raw(), indirect_offset);
60    }
61
62    /// Same as [`draw_indexed`](Self::draw_indexed), but the counts come
63    /// from a [`DrawIndexedIndirectArgs`] value already written into
64    /// `indirect_buffer` at `indirect_offset` bytes.
65    pub fn draw_indexed_indirect(&mut self, indirect_buffer: &'a Buffer, indirect_offset: u64) {
66        self.raw.draw_indexed_indirect(indirect_buffer.raw(), indirect_offset);
67    }
68
69    /// Replays every bundle in `bundles`, in order, as if their recorded
70    /// commands had been issued directly against this pass.
71    pub fn execute_bundles(&mut self, bundles: &[&super::render_bundle::RenderBundle]) {
72        self.raw.execute_bundles(bundles.iter().map(|b| b.raw()));
73    }
74
75    /// Drops the borrow-checker tie to whatever this pass's encoder was
76    /// borrowed from, without actually extending its real lifetime — see
77    /// `wgpu::RenderPass::forget_lifetime`'s own docs for the safety
78    /// contract. `pub(crate)` only, and only compiled in with the
79    /// `profiler` feature: needed by [`profiler`](super::profiler) to
80    /// satisfy `egui_wgpu::Renderer::render`'s `RenderPass<'static>`
81    /// requirement, not something ordinary rendering code needs.
82    #[cfg(feature = "profiler")]
83    pub(crate) fn forget_lifetime(self) -> RenderPass<'static> {
84        RenderPass { raw: self.raw.forget_lifetime() }
85    }
86
87    /// `pub(crate)` escape hatch for internal code (the profiler overlay)
88    /// that hands this pass to a third-party renderer (`egui_wgpu`)
89    /// expecting a raw `wgpu::RenderPass`.
90    #[cfg(feature = "profiler")]
91    pub(crate) fn raw_mut(&mut self) -> &mut wgpu::RenderPass<'a> {
92        &mut self.raw
93    }
94}
95
96/// Index buffer element width — mirrors `wgpu::IndexFormat` (which has
97/// exactly these two variants).
98#[derive(Clone, Copy, PartialEq, Eq)]
99pub enum IndexFormat {
100    Uint16,
101    Uint32,
102}
103
104impl From<IndexFormat> for wgpu::IndexFormat {
105    fn from(format: IndexFormat) -> Self {
106        match format {
107            IndexFormat::Uint16 => wgpu::IndexFormat::Uint16,
108            IndexFormat::Uint32 => wgpu::IndexFormat::Uint32,
109        }
110    }
111}
112
113/// The argument layout [`RenderPass::draw_indirect`] expects at
114/// `indirect_offset` in the indirect buffer — mirrors `wgpu::DrawIndirectArgs`
115/// field-for-field, so writing one via [`as_bytes`](Self::as_bytes) into a
116/// buffer built with [`BufferUsages::INDIRECT`](super::flags::BufferUsages::INDIRECT)
117/// produces the exact same bytes wgpu itself would.
118#[repr(C)]
119#[derive(Copy, Clone, Debug, Default, bytemuck::Pod, bytemuck::Zeroable)]
120pub struct DrawIndirectArgs {
121    pub vertex_count: u32,
122    pub instance_count: u32,
123    pub first_vertex: u32,
124    pub first_instance: u32,
125}
126
127impl DrawIndirectArgs {
128    pub fn as_bytes(&self) -> &[u8] {
129        bytemuck::bytes_of(self)
130    }
131}
132
133/// The argument layout [`RenderPass::draw_indexed_indirect`] expects —
134/// mirrors `wgpu::DrawIndexedIndirectArgs` field-for-field. See
135/// [`DrawIndirectArgs`].
136#[repr(C)]
137#[derive(Copy, Clone, Debug, Default, bytemuck::Pod, bytemuck::Zeroable)]
138pub struct DrawIndexedIndirectArgs {
139    pub index_count: u32,
140    pub instance_count: u32,
141    pub first_index: u32,
142    pub base_vertex: i32,
143    pub first_instance: u32,
144}
145
146impl DrawIndexedIndirectArgs {
147    pub fn as_bytes(&self) -> &[u8] {
148        bytemuck::bytes_of(self)
149    }
150}