script_webgpu/
gpucomputepassencoder.rs1use 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 fn Label(&self) -> USVString {
122 self.label.borrow().clone()
123 }
124
125 fn SetLabel(&self, no_gc: &NoGC, value: USVString) {
127 *self.label.safe_borrow_mut(no_gc) = value;
128 }
129
130 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 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 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 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 fn SetPipeline(&self, pipeline: &GPUComputePipeline<D>) {
175 self.send_command(ComputePassEncoderCommand::SetPipeline(pipeline.id().0));
176 }
177
178 fn PushDebugGroup(&self, group_label: USVString) {
180 self.send_command(ComputePassEncoderCommand::DebugCommand(
181 DebugCommand::PushDebugGroup(group_label.to_string()),
182 ));
183 }
184
185 fn PopDebugGroup(&self) {
187 self.send_command(ComputePassEncoderCommand::DebugCommand(
188 DebugCommand::PopDebugGroup,
189 ));
190 }
191
192 fn InsertDebugMarker(&self, marker_label: USVString) {
194 self.send_command(ComputePassEncoderCommand::DebugCommand(
195 DebugCommand::InsertDebugMarker(marker_label.to_string()),
196 ));
197 }
198}