Skip to main content

script_webgpu/
gpucomputepassencoder.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use dom_struct::dom_struct;
6use js::context::{JSContext, NoGC};
7use log::warn;
8use malloc_size_of_derive::MallocSizeOf;
9use script_bindings::DomTypes;
10use script_bindings::cell::DomRefCell;
11use script_bindings::codegen::GenericBindings::WebGPUBinding::{
12    GPUComputePassEncoderMethods, GPUComputePassEncoderWrap,
13};
14use script_bindings::interfaces::PromiseHelpers;
15use script_bindings::reflector::{Reflector, reflect_dom_object_with_wrap};
16use webgpu_traits::{
17    ComputePassEncoderCommand, DebugCommand, WebGPU, WebGPUComputePass, WebGPURequest,
18};
19
20use crate::JSTraceable;
21use crate::dom::bindings::root::{Dom, DomRoot};
22use crate::dom::bindings::str::USVString;
23use crate::gpubindgroup::GPUBindGroup;
24use crate::gpubuffer::GPUBuffer;
25use crate::gpucommandencoder::GPUCommandEncoder;
26use crate::gpucomputepipeline::GPUComputePipeline;
27use crate::traits::{Equivalence, WebGPUPromise};
28
29#[derive(MallocSizeOf)]
30struct DroppableGPUComputePassEncoder {
31    channel: WebGPU,
32    compute_pass: WebGPUComputePass,
33}
34
35impl Drop for DroppableGPUComputePassEncoder {
36    fn drop(&mut self) {
37        if let Err(e) = self
38            .channel
39            .0
40            .send(WebGPURequest::DropComputePass(self.compute_pass.0))
41        {
42            warn!("Failed to send WebGPURequest::DropComputePass with {e:?}");
43        }
44    }
45}
46
47#[dom_struct]
48pub struct GPUComputePassEncoder<D: DomTypes> {
49    reflector_: Reflector,
50    label: DomRefCell<USVString>,
51    command_encoder: Dom<GPUCommandEncoder<D>>,
52    #[no_trace]
53    droppable: DroppableGPUComputePassEncoder,
54}
55
56impl<D> GPUComputePassEncoder<D>
57where
58    D: Equivalence,
59    <D::Promise as PromiseHelpers<D>>::StackRoot: WebGPUPromise<D>,
60{
61    fn new_inherited(
62        channel: WebGPU,
63        parent: &GPUCommandEncoder<D>,
64        compute_pass: WebGPUComputePass,
65        label: USVString,
66    ) -> Self {
67        Self {
68            reflector_: Reflector::new(),
69            label: DomRefCell::new(label),
70            command_encoder: Dom::from_ref(parent),
71            droppable: DroppableGPUComputePassEncoder {
72                channel,
73                compute_pass,
74            },
75        }
76    }
77
78    pub(crate) fn new(
79        cx: &mut JSContext,
80        global: &D::GlobalScope,
81        channel: WebGPU,
82        parent: &GPUCommandEncoder<D>,
83        compute_pass: WebGPUComputePass,
84        label: USVString,
85    ) -> DomRoot<Self> {
86        reflect_dom_object_with_wrap::<D, _, _>(
87            cx,
88            Box::new(GPUComputePassEncoder::new_inherited(
89                channel,
90                parent,
91                compute_pass,
92                label,
93            )),
94            global,
95            GPUComputePassEncoderWrap::<D>,
96        )
97    }
98
99    fn send_command(&self, command: ComputePassEncoderCommand) {
100        if let Err(e) = self
101            .droppable
102            .channel
103            .0
104            .send(WebGPURequest::ComputePassCommand {
105                compute_pass_id: self.droppable.compute_pass.0,
106                compute_command: command,
107                device_id: self.command_encoder.device_id().0,
108            })
109        {
110            warn!("Error sending WebGPURequest::ComputePassCommand: {e:?}")
111        }
112    }
113}
114
115impl<D> GPUComputePassEncoderMethods<D> for GPUComputePassEncoder<D>
116where
117    D: Equivalence,
118    <D::Promise as PromiseHelpers<D>>::StackRoot: WebGPUPromise<D>,
119{
120    /// <https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label>
121    fn Label(&self) -> USVString {
122        self.label.borrow().clone()
123    }
124
125    /// <https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label>
126    fn SetLabel(&self, no_gc: &NoGC, value: USVString) {
127        *self.label.safe_borrow_mut(no_gc) = value;
128    }
129
130    /// <https://gpuweb.github.io/gpuweb/#dom-gpucomputepassencoder-dispatchworkgroups>
131    fn DispatchWorkgroups(&self, x: u32, y: u32, z: u32) {
132        self.send_command(ComputePassEncoderCommand::DispatchWorkgroups {
133            workgroup_count_x: x,
134            workgroup_count_y: y,
135            workgroup_count_z: z,
136        });
137    }
138
139    /// <https://gpuweb.github.io/gpuweb/#dom-gpucomputepassencoder-dispatchworkgroupsindirect>
140    fn DispatchWorkgroupsIndirect(&self, buffer: &GPUBuffer<D>, offset: u64) {
141        self.send_command(ComputePassEncoderCommand::DispatchWorkgroupsIndirect {
142            indirect_buffer: buffer.id().0,
143            indirect_offset: offset,
144        });
145    }
146
147    /// <https://gpuweb.github.io/gpuweb/#dom-gpurenderpassencoder-endpass>
148    fn End(&self) {
149        if let Err(e) = self
150            .droppable
151            .channel
152            .0
153            .send(WebGPURequest::EndComputePass {
154                compute_pass_id: self.droppable.compute_pass.0,
155                device_id: self.command_encoder.device_id().0,
156            })
157        {
158            warn!("Failed to send WebGPURequest::EndComputePass: {e:?}");
159        }
160    }
161
162    /// <https://gpuweb.github.io/gpuweb/#dom-gpuprogrammablepassencoder-setbindgroup>
163    fn SetBindGroup(&self, index: u32, bind_group: &GPUBindGroup<D>, offsets: Vec<u32>) {
164        self.send_command(ComputePassEncoderCommand::BindingCommand(
165            webgpu_traits::BindingCommand::SetBindGroup {
166                index,
167                bind_group: Some(bind_group.id().0),
168                dynamic_offsets: offsets,
169            },
170        ));
171    }
172
173    /// <https://gpuweb.github.io/gpuweb/#dom-gpucomputepassencoder-setpipeline>
174    fn SetPipeline(&self, pipeline: &GPUComputePipeline<D>) {
175        self.send_command(ComputePassEncoderCommand::SetPipeline(pipeline.id().0));
176    }
177
178    /// <https://gpuweb.github.io/gpuweb/#dom-gpudebugcommandsmixin-pushdebuggroup>
179    fn PushDebugGroup(&self, group_label: USVString) {
180        self.send_command(ComputePassEncoderCommand::DebugCommand(
181            DebugCommand::PushDebugGroup(group_label.to_string()),
182        ));
183    }
184
185    /// <https://gpuweb.github.io/gpuweb/#dom-gpudebugcommandsmixin-popdebuggroup>
186    fn PopDebugGroup(&self) {
187        self.send_command(ComputePassEncoderCommand::DebugCommand(
188            DebugCommand::PopDebugGroup,
189        ));
190    }
191
192    /// <https://gpuweb.github.io/gpuweb/#dom-gpudebugcommandsmixin-insertdebugmarker>
193    fn InsertDebugMarker(&self, marker_label: USVString) {
194        self.send_command(ComputePassEncoderCommand::DebugCommand(
195            DebugCommand::InsertDebugMarker(marker_label.to_string()),
196        ));
197    }
198}