pebble/wgpu/compute_pass.rs
1use crate::wgpu::{buffer::Buffer, buffers::BindGroup, compute::ComputePipeline};
2
3/// A compute pass, opaque — the value [`CommandEncoder::compute_pass`]/
4/// [`WGPUFrame::compute_pass`](super::backend::WGPUFrame::compute_pass)
5/// hand back. There's no way to reach the underlying `wgpu::ComputePass`
6/// from outside this crate.
7pub struct ComputePass<'a> {
8 raw: wgpu::ComputePass<'a>,
9}
10
11impl<'a> ComputePass<'a> {
12 pub(crate) fn new(raw: wgpu::ComputePass<'a>) -> Self {
13 Self { raw }
14 }
15
16 pub fn set_pipeline(&mut self, pipeline: &ComputePipeline) {
17 self.raw.set_pipeline(pipeline.raw());
18 }
19
20 /// `offsets` is the dynamic-offset slice for any dynamic-offset entries
21 /// in this bind group's layout, in the order they appear — empty if
22 /// none. See [`RenderPass::set_bind_group`](super::render_pass::RenderPass::set_bind_group).
23 pub fn set_bind_group(&mut self, index: u32, bind_group: &BindGroup, offsets: &[u32]) {
24 self.raw.set_bind_group(index, Some(bind_group.raw()), offsets);
25 }
26
27 pub fn dispatch_workgroups(&mut self, x: u32, y: u32, z: u32) {
28 self.raw.dispatch_workgroups(x, y, z);
29 }
30
31 /// Same as [`dispatch_workgroups`](Self::dispatch_workgroups), but the
32 /// workgroup counts come from a [`DispatchIndirectArgs`] value already
33 /// written into `indirect_buffer` at `indirect_offset` bytes — for a
34 /// dispatch size the GPU itself computed (culling compaction, particle
35 /// counts, ...) the CPU never reads back.
36 pub fn dispatch_workgroups_indirect(&mut self, indirect_buffer: &'a Buffer, indirect_offset: u64) {
37 self.raw.dispatch_workgroups_indirect(indirect_buffer.raw(), indirect_offset);
38 }
39}
40
41/// The argument layout [`ComputePass::dispatch_workgroups_indirect`]
42/// expects — mirrors `wgpu::DispatchIndirectArgs` field-for-field. See
43/// [`DrawIndirectArgs`](super::render_pass::DrawIndirectArgs).
44#[repr(C)]
45#[derive(Copy, Clone, Debug, Default, bytemuck::Pod, bytemuck::Zeroable)]
46pub struct DispatchIndirectArgs {
47 pub x: u32,
48 pub y: u32,
49 pub z: u32,
50}
51
52impl DispatchIndirectArgs {
53 pub fn as_bytes(&self) -> &[u8] {
54 bytemuck::bytes_of(self)
55 }
56}
57
58/// A command encoder, opaque — built only via
59/// [`WGPUBackend::create_command_encoder`](super::backend::WGPUBackend::create_command_encoder).
60/// Its only job is starting a [`ComputePass`]; submit it when done via
61/// [`WGPUBackend::submit`](super::backend::WGPUBackend::submit). Render
62/// passes don't need this — [`ActiveFrame::begin_pass`](crate::rendering::active_frame::ActiveFrame::begin_pass)
63/// manages its own frame-tied encoder internally.
64pub struct CommandEncoder {
65 raw: wgpu::CommandEncoder,
66}
67
68impl CommandEncoder {
69 pub(crate) fn new(raw: wgpu::CommandEncoder) -> Self {
70 Self { raw }
71 }
72
73 pub fn compute_pass(&mut self, label: Option<&str>) -> ComputePass<'_> {
74 let raw = self.raw.begin_compute_pass(&wgpu::ComputePassDescriptor {
75 label,
76 timestamp_writes: None,
77 });
78 ComputePass::new(raw)
79 }
80
81 pub(crate) fn into_raw(self) -> wgpu::CommandEncoder {
82 self.raw
83 }
84}