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::{WebGPU, WebGPUComputePass, WebGPURequest};
17
18use crate::JSTraceable;
19use crate::dom::bindings::root::{Dom, DomRoot};
20use crate::dom::bindings::str::USVString;
21use crate::gpubindgroup::GPUBindGroup;
22use crate::gpubuffer::GPUBuffer;
23use crate::gpucommandencoder::GPUCommandEncoder;
24use crate::gpucomputepipeline::GPUComputePipeline;
25use crate::traits::{
26    Equivalence, GPUDeviceTrait, GPUExternalTextureTrait, WebGPUGlobalTrait, WebGPUPromiseTrait,
27};
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::GPUDevice: GPUDeviceTrait<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            Box::new(GPUComputePassEncoder::new_inherited(
88                channel,
89                parent,
90                compute_pass,
91                label,
92            )),
93            global,
94            cx,
95            GPUComputePassEncoderWrap::<D>,
96        )
97    }
98}
99
100impl<D> GPUComputePassEncoderMethods<D> for GPUComputePassEncoder<D>
101where
102    D: Equivalence,
103    D::GlobalScope: WebGPUGlobalTrait,
104    D::GPUDevice: GPUDeviceTrait<D>,
105    D::GPUExternalTexture: GPUExternalTextureTrait<D>,
106    D::Promise: PromiseHelpers<D>,
107    <D::Promise as PromiseHelpers<D>>::StackRoot: WebGPUPromiseTrait<D>,
108{
109    /// <https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label>
110    fn Label(&self) -> USVString {
111        self.label.borrow().clone()
112    }
113
114    /// <https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label>
115    fn SetLabel(&self, no_gc: &NoGC, value: USVString) {
116        *self.label.safe_borrow_mut(no_gc) = value;
117    }
118
119    /// <https://gpuweb.github.io/gpuweb/#dom-gpucomputepassencoder-dispatchworkgroups>
120    fn DispatchWorkgroups(&self, x: u32, y: u32, z: u32) {
121        if let Err(e) =
122            self.droppable
123                .channel
124                .0
125                .send(WebGPURequest::ComputePassDispatchWorkgroups {
126                    compute_pass_id: self.droppable.compute_pass.0,
127                    x,
128                    y,
129                    z,
130                    device_id: self.command_encoder.device_id().0,
131                })
132        {
133            warn!("Error sending WebGPURequest::ComputePassDispatchWorkgroups: {e:?}")
134        }
135    }
136
137    /// <https://gpuweb.github.io/gpuweb/#dom-gpucomputepassencoder-dispatchworkgroupsindirect>
138    fn DispatchWorkgroupsIndirect(&self, buffer: &GPUBuffer<D>, offset: u64) {
139        if let Err(e) =
140            self.droppable
141                .channel
142                .0
143                .send(WebGPURequest::ComputePassDispatchWorkgroupsIndirect {
144                    compute_pass_id: self.droppable.compute_pass.0,
145                    buffer_id: buffer.id().0,
146                    offset,
147                    device_id: self.command_encoder.device_id().0,
148                })
149        {
150            warn!("Error sending WebGPURequest::ComputePassDispatchWorkgroupsIndirect: {e:?}")
151        }
152    }
153
154    /// <https://gpuweb.github.io/gpuweb/#dom-gpurenderpassencoder-endpass>
155    fn End(&self) {
156        if let Err(e) = self
157            .droppable
158            .channel
159            .0
160            .send(WebGPURequest::EndComputePass {
161                compute_pass_id: self.droppable.compute_pass.0,
162                device_id: self.command_encoder.device_id().0,
163            })
164        {
165            warn!("Failed to send WebGPURequest::EndComputePass: {e:?}");
166        }
167    }
168
169    /// <https://gpuweb.github.io/gpuweb/#dom-gpuprogrammablepassencoder-setbindgroup>
170    fn SetBindGroup(&self, index: u32, bind_group: &GPUBindGroup<D>, offsets: Vec<u32>) {
171        if let Err(e) = self
172            .droppable
173            .channel
174            .0
175            .send(WebGPURequest::ComputePassSetBindGroup {
176                compute_pass_id: self.droppable.compute_pass.0,
177                index,
178                bind_group_id: bind_group.id().0,
179                offsets,
180                device_id: self.command_encoder.device_id().0,
181            })
182        {
183            warn!("Error sending WebGPURequest::ComputePassSetBindGroup: {e:?}")
184        }
185    }
186
187    /// <https://gpuweb.github.io/gpuweb/#dom-gpucomputepassencoder-setpipeline>
188    fn SetPipeline(&self, pipeline: &GPUComputePipeline<D>) {
189        if let Err(e) = self
190            .droppable
191            .channel
192            .0
193            .send(WebGPURequest::ComputePassSetPipeline {
194                compute_pass_id: self.droppable.compute_pass.0,
195                pipeline_id: pipeline.id().0,
196                device_id: self.command_encoder.device_id().0,
197            })
198        {
199            warn!("Error sending WebGPURequest::ComputePassSetPipeline: {e:?}")
200        }
201    }
202
203    /// <https://gpuweb.github.io/gpuweb/#dom-gpudebugcommandsmixin-pushdebuggroup>
204    fn PushDebugGroup(&self, group_label: USVString) {
205        if let Err(e) = self
206            .droppable
207            .channel
208            .0
209            .send(WebGPURequest::ComputePassPushDebugGroup {
210                compute_pass_id: self.droppable.compute_pass.0,
211                label: group_label.to_string(),
212                device_id: self.command_encoder.device_id().0,
213            })
214        {
215            warn!("Error sending WebGPURequest::ComputePassPushDebugGroup: {e:?}")
216        }
217    }
218
219    /// <https://gpuweb.github.io/gpuweb/#dom-gpudebugcommandsmixin-popdebuggroup>
220    fn PopDebugGroup(&self) {
221        if let Err(e) = self
222            .droppable
223            .channel
224            .0
225            .send(WebGPURequest::ComputePassPopDebugGroup {
226                compute_pass_id: self.droppable.compute_pass.0,
227                device_id: self.command_encoder.device_id().0,
228            })
229        {
230            warn!("Error sending WebGPURequest::ComputePassPopDebugGroup: {e:?}")
231        }
232    }
233
234    /// <https://gpuweb.github.io/gpuweb/#dom-gpudebugcommandsmixin-insertdebugmarker>
235    fn InsertDebugMarker(&self, marker_label: USVString) {
236        if let Err(e) = self
237            .droppable
238            .channel
239            .0
240            .send(WebGPURequest::ComputePassInsertDebugMarker {
241                compute_pass_id: self.droppable.compute_pass.0,
242                label: marker_label.to_string(),
243                device_id: self.command_encoder.device_id().0,
244            })
245        {
246            warn!("Error sending WebGPURequest::ComputePassInsertDebugMarker: {e:?}")
247        }
248    }
249}