1use std::borrow::Cow;
6
7use dom_struct::dom_struct;
8use js::context::{JSContext, NoGC};
9use script_bindings::cell::DomRefCell;
10use script_bindings::reflector::{Reflector, reflect_dom_object_with_cx};
11use webgpu_traits::{
12 RenderBundleCommand, WebGPU, WebGPURenderBundle, WebGPURenderBundleEncoder, WebGPURequest,
13};
14use wgpu_core::command::RenderBundleEncoderDescriptor;
15
16use crate::conversions::Convert;
17use crate::dom::bindings::codegen::Bindings::WebGPUBinding::{
18 GPUIndexFormat, GPURenderBundleDescriptor, GPURenderBundleEncoderDescriptor,
19 GPURenderBundleEncoderMethods,
20};
21use crate::dom::bindings::error::Fallible;
22use crate::dom::bindings::reflector::DomGlobal;
23use crate::dom::bindings::root::{Dom, DomRoot};
24use crate::dom::bindings::str::USVString;
25use crate::dom::globalscope::GlobalScope;
26use crate::dom::webgpu::gpubindgroup::GPUBindGroup;
27use crate::dom::webgpu::gpubuffer::GPUBuffer;
28use crate::dom::webgpu::gpudevice::GPUDevice;
29use crate::dom::webgpu::gpurenderbundle::GPURenderBundle;
30use crate::dom::webgpu::gpurenderpipeline::GPURenderPipeline;
31
32#[derive(JSTraceable, MallocSizeOf)]
33struct DroppableGPURenderBundleEncoder {
34 #[no_trace]
35 channel: WebGPU,
36 #[no_trace]
37 render_bundle_encoder: WebGPURenderBundleEncoder,
38}
39
40impl Drop for DroppableGPURenderBundleEncoder {
41 fn drop(&mut self) {
42 if let Err(error) = self.channel.0.send(WebGPURequest::DropRenderBundleEncoder(
43 self.render_bundle_encoder.0,
44 )) {
45 warn!(
46 "Failed to send WebGPURequest::DropRenderBundleEncoder({:?}) ({error})",
47 self.render_bundle_encoder.0
48 );
49 }
50 }
51}
52
53#[dom_struct]
54pub(crate) struct GPURenderBundleEncoder {
55 reflector_: Reflector,
56 device: Dom<GPUDevice>,
57 label: DomRefCell<USVString>,
58 droppable: DroppableGPURenderBundleEncoder,
59}
60
61impl GPURenderBundleEncoder {
62 fn new_inherited(
63 device: &GPUDevice,
64 channel: WebGPU,
65 label: USVString,
66 render_bundle_encoder: WebGPURenderBundleEncoder,
67 ) -> Self {
68 Self {
69 reflector_: Reflector::new(),
70 device: Dom::from_ref(device),
71 droppable: DroppableGPURenderBundleEncoder {
72 channel,
73 render_bundle_encoder,
74 },
75 label: DomRefCell::new(label),
76 }
77 }
78
79 pub(crate) fn new(
80 cx: &mut JSContext,
81 global: &GlobalScope,
82 render_bundle_encoder: WebGPURenderBundleEncoder,
83 device: &GPUDevice,
84 channel: WebGPU,
85 label: USVString,
86 ) -> DomRoot<Self> {
87 reflect_dom_object_with_cx(
88 Box::new(GPURenderBundleEncoder::new_inherited(
89 device,
90 channel,
91 label,
92 render_bundle_encoder,
93 )),
94 global,
95 cx,
96 )
97 }
98}
99
100impl GPURenderBundleEncoder {
101 pub(crate) fn create(
103 cx: &mut JSContext,
104 device: &GPUDevice,
105 descriptor: &GPURenderBundleEncoderDescriptor,
106 ) -> Fallible<DomRoot<GPURenderBundleEncoder>> {
107 let desc = RenderBundleEncoderDescriptor {
108 label: (&descriptor.parent.parent).convert(),
109 color_formats: Cow::Owned(
110 descriptor
111 .parent
112 .colorFormats
113 .iter()
114 .map(|format| {
115 device
116 .validate_texture_format_required_features(format)
117 .map(Some)
118 })
119 .collect::<Fallible<Vec<_>>>()?,
120 ),
121 depth_stencil: descriptor
122 .parent
123 .depthStencilFormat
124 .map(|dsf| {
125 device
126 .validate_texture_format_required_features(&dsf)
127 .map(|format| wgpu_types::RenderBundleDepthStencil {
128 format,
129 depth_read_only: descriptor.depthReadOnly,
130 stencil_read_only: descriptor.stencilReadOnly,
131 })
132 })
133 .transpose()?,
134 sample_count: descriptor.parent.sampleCount,
135 multiview: None,
136 };
137
138 let id = device
139 .global()
140 .wgpu_id_hub()
141 .create_render_bundle_encoder_id();
142 let render_bundle_encoder = WebGPURenderBundleEncoder(id);
143
144 let channel = device.channel();
145
146 if let Err(error) = channel.0.send(WebGPURequest::CreateRenderBundleEncoder {
147 device_id: device.id().0,
148 desc,
149 render_bundle_encoder_id: render_bundle_encoder.0,
150 }) {
151 warn!(
152 "Failed to send WebGPURequest::CreateRenderBundleEncoder({:?}) ({error})",
153 render_bundle_encoder.0
154 );
155 }
156
157 Ok(GPURenderBundleEncoder::new(
158 cx,
159 &device.global(),
160 render_bundle_encoder,
161 device,
162 device.channel(),
163 descriptor.parent.parent.label.clone(),
164 ))
165 }
166
167 pub(crate) fn id(&self) -> WebGPURenderBundleEncoder {
168 self.droppable.render_bundle_encoder
169 }
170}
171
172impl GPURenderBundleEncoderMethods<crate::DomTypeHolder> for GPURenderBundleEncoder {
173 fn Label(&self) -> USVString {
175 self.label.borrow().clone()
176 }
177
178 fn SetLabel(&self, no_gc: &NoGC, value: USVString) {
180 *self.label.safe_borrow_mut(no_gc) = value;
181 }
182
183 fn SetBindGroup(&self, index: u32, bind_group: &GPUBindGroup, dynamic_offsets: Vec<u32>) {
185 if let Err(error) =
186 self.droppable
187 .channel
188 .0
189 .send(WebGPURequest::RenderBundleEncoderCommand {
190 render_bundle_encoder_id: self.droppable.render_bundle_encoder.0,
191 render_command: RenderBundleCommand::SetBindGroup {
192 index,
193 bind_group_id: bind_group.id().0,
194 offsets: dynamic_offsets,
195 },
196 device_id: self.device.id().0,
197 })
198 {
199 warn!(
200 "Failed to send WebGPURequest::RenderBundleEncoderSetBindGroup({:?}) ({error})",
201 self.droppable.render_bundle_encoder.0
202 );
203 }
204 }
205
206 fn SetPipeline(&self, pipeline: &GPURenderPipeline) {
208 if let Err(error) =
209 self.droppable
210 .channel
211 .0
212 .send(WebGPURequest::RenderBundleEncoderCommand {
213 render_bundle_encoder_id: self.droppable.render_bundle_encoder.0,
214 render_command: RenderBundleCommand::SetPipeline(pipeline.id().0),
215 device_id: self.device.id().0,
216 })
217 {
218 warn!(
219 "Failed to send WebGPURequest::RenderBundleEncoderSetPipeline({:?}) ({error})",
220 self.droppable.render_bundle_encoder.0
221 );
222 }
223 }
224
225 fn SetIndexBuffer(
227 &self,
228 buffer: &GPUBuffer,
229 index_format: GPUIndexFormat,
230 offset: u64,
231 size: u64,
232 ) {
233 if let Err(error) =
234 self.droppable
235 .channel
236 .0
237 .send(WebGPURequest::RenderBundleEncoderCommand {
238 render_bundle_encoder_id: self.droppable.render_bundle_encoder.0,
239 render_command: RenderBundleCommand::SetIndexBuffer {
240 buffer_id: buffer.id().0,
241 index_format: index_format.convert(),
242 offset,
243 size: wgpu_types::BufferSize::new(size),
244 },
245 device_id: self.device.id().0,
246 })
247 {
248 warn!(
249 "Failed to send WebGPURequest::RenderBundleEncoderSetIndexBuffer({:?}) ({error})",
250 self.droppable.render_bundle_encoder.0
251 );
252 }
253 }
254
255 fn SetVertexBuffer(&self, slot: u32, buffer: Option<&GPUBuffer>, offset: u64, size: u64) {
257 if let Err(error) =
258 self.droppable
259 .channel
260 .0
261 .send(WebGPURequest::RenderBundleEncoderCommand {
262 render_bundle_encoder_id: self.droppable.render_bundle_encoder.0,
263 render_command: RenderBundleCommand::SetVertexBuffer {
264 slot,
265 buffer_id: buffer.map(|b| b.id().0),
266 offset,
267 size: wgpu_types::BufferSize::new(size),
268 },
269 device_id: self.device.id().0,
270 })
271 {
272 warn!(
273 "Failed to send WebGPURequest::RenderBundleEncoderSetVertexBuffer({:?}) ({error})",
274 self.droppable.render_bundle_encoder.0
275 );
276 }
277 }
278
279 fn Draw(&self, vertex_count: u32, instance_count: u32, first_vertex: u32, first_instance: u32) {
281 if let Err(error) =
282 self.droppable
283 .channel
284 .0
285 .send(WebGPURequest::RenderBundleEncoderCommand {
286 render_bundle_encoder_id: self.droppable.render_bundle_encoder.0,
287 render_command: RenderBundleCommand::Draw {
288 vertex_count,
289 instance_count,
290 first_vertex,
291 first_instance,
292 },
293 device_id: self.device.id().0,
294 })
295 {
296 warn!(
297 "Failed to send WebGPURequest::RenderBundleEncoderDraw({:?}) ({error})",
298 self.droppable.render_bundle_encoder.0
299 );
300 }
301 }
302
303 fn DrawIndexed(
305 &self,
306 index_count: u32,
307 instance_count: u32,
308 first_index: u32,
309 base_vertex: i32,
310 first_instance: u32,
311 ) {
312 if let Err(error) =
313 self.droppable
314 .channel
315 .0
316 .send(WebGPURequest::RenderBundleEncoderCommand {
317 render_bundle_encoder_id: self.droppable.render_bundle_encoder.0,
318 render_command: RenderBundleCommand::DrawIndexed {
319 index_count,
320 instance_count,
321 first_index,
322 base_vertex,
323 first_instance,
324 },
325 device_id: self.device.id().0,
326 })
327 {
328 warn!(
329 "Failed to send WebGPURequest::RenderBundleEncoderDrawIndexed({:?}) ({error})",
330 self.droppable.render_bundle_encoder.0
331 );
332 }
333 }
334
335 fn DrawIndirect(&self, indirect_buffer: &GPUBuffer, indirect_offset: u64) {
337 if let Err(error) =
338 self.droppable
339 .channel
340 .0
341 .send(WebGPURequest::RenderBundleEncoderCommand {
342 render_bundle_encoder_id: self.droppable.render_bundle_encoder.0,
343 render_command: RenderBundleCommand::DrawIndirect {
344 buffer_id: indirect_buffer.id().0,
345 offset: indirect_offset,
346 },
347 device_id: self.device.id().0,
348 })
349 {
350 warn!(
351 "Failed to send WebGPURequest::RenderBundleEncoderDrawIndirect({:?}) ({error})",
352 self.droppable.render_bundle_encoder.0
353 );
354 }
355 }
356
357 fn DrawIndexedIndirect(&self, indirect_buffer: &GPUBuffer, indirect_offset: u64) {
359 if let Err(error) =
360 self.droppable
361 .channel
362 .0
363 .send(WebGPURequest::RenderBundleEncoderCommand {
364 render_bundle_encoder_id: self.droppable.render_bundle_encoder.0,
365 render_command: RenderBundleCommand::DrawIndexedIndirect {
366 buffer_id: indirect_buffer.id().0,
367 offset: indirect_offset,
368 },
369 device_id: self.device.id().0,
370 })
371 {
372 warn!(
373 "Failed to send WebGPURequest::RenderBundleEncoderDrawIndexedIndirect({:?}) ({error})",
374 self.droppable.render_bundle_encoder.0
375 );
376 }
377 }
378
379 fn PushDebugGroup(&self, group_label: USVString) {
381 if let Err(error) =
382 self.droppable
383 .channel
384 .0
385 .send(WebGPURequest::RenderBundleEncoderCommand {
386 render_bundle_encoder_id: self.droppable.render_bundle_encoder.0,
387 render_command: RenderBundleCommand::PushDebugGroup(group_label.to_string()),
388 device_id: self.device.id().0,
389 })
390 {
391 warn!(
392 "Failed to send WebGPURequest::RenderBundleEncoderPushDebugGroup({:?}) ({error})",
393 self.droppable.render_bundle_encoder.0
394 );
395 }
396 }
397
398 fn PopDebugGroup(&self) {
400 if let Err(error) =
401 self.droppable
402 .channel
403 .0
404 .send(WebGPURequest::RenderBundleEncoderCommand {
405 render_bundle_encoder_id: self.droppable.render_bundle_encoder.0,
406 render_command: RenderBundleCommand::PopDebugGroup,
407 device_id: self.device.id().0,
408 })
409 {
410 warn!(
411 "Failed to send WebGPURequest::RenderBundleEncoderPopDebugGroup({:?}) ({error})",
412 self.id()
413 );
414 }
415 }
416
417 fn InsertDebugMarker(&self, marker_label: USVString) {
419 if let Err(error) =
420 self.droppable
421 .channel
422 .0
423 .send(WebGPURequest::RenderBundleEncoderCommand {
424 render_bundle_encoder_id: self.droppable.render_bundle_encoder.0,
425 render_command: RenderBundleCommand::InsertDebugMarker(
426 marker_label.to_string(),
427 ),
428 device_id: self.device.id().0,
429 })
430 {
431 warn!(
432 "Failed to send WebGPURequest::RenderBundleEncoderInsertDebugMarker({:?}) ({error})",
433 self.id()
434 );
435 }
436 }
437
438 fn Finish(
440 &self,
441 cx: &mut JSContext,
442 descriptor: &GPURenderBundleDescriptor,
443 ) -> DomRoot<GPURenderBundle> {
444 let desc = wgpu_types::RenderBundleDescriptor {
445 label: (&descriptor.parent).convert(),
446 };
447 let render_bundle_id = self.global().wgpu_id_hub().create_render_bundle_id();
448
449 if let Err(error) =
450 self.droppable
451 .channel
452 .0
453 .send(WebGPURequest::RenderBundleEncoderFinish {
454 render_bundle_encoder_id: self.id().0,
455 descriptor: desc,
456 render_bundle_id,
457 device_id: self.device.id().0,
458 })
459 {
460 warn!(
461 "Failed to send WebGPURequest::RenderBundleEncoderFinish({:?}) ({error})",
462 self.id()
463 );
464 }
465
466 let render_bundle = WebGPURenderBundle(render_bundle_id);
467 GPURenderBundle::new(
468 cx,
469 &self.global(),
470 render_bundle,
471 self.device.id(),
472 self.droppable.channel.clone(),
473 descriptor.parent.label.clone(),
474 )
475 }
476}