1use 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 fn Label(&self) -> USVString {
111 self.label.borrow().clone()
112 }
113
114 fn SetLabel(&self, no_gc: &NoGC, value: USVString) {
116 *self.label.safe_borrow_mut(no_gc) = value;
117 }
118
119 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 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 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 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 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 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 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 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}