Skip to main content

script/dom/webgpu/
gpurenderpassencoder.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 script_bindings::cell::DomRefCell;
7use script_bindings::reflector::{Reflector, reflect_dom_object};
8use webgpu_traits::{RenderCommand, WebGPU, WebGPURenderPass, WebGPURequest};
9
10use crate::conversions::TryConvert;
11use crate::dom::bindings::codegen::Bindings::WebGPUBinding::{
12    GPUColor, GPUIndexFormat, GPURenderPassEncoderMethods,
13};
14use crate::dom::bindings::error::Fallible;
15use crate::dom::bindings::num::Finite;
16use crate::dom::bindings::root::{Dom, DomRoot};
17use crate::dom::bindings::str::USVString;
18use crate::dom::globalscope::GlobalScope;
19use crate::dom::webgpu::gpubindgroup::GPUBindGroup;
20use crate::dom::webgpu::gpubuffer::GPUBuffer;
21use crate::dom::webgpu::gpucommandencoder::GPUCommandEncoder;
22use crate::dom::webgpu::gpurenderbundle::GPURenderBundle;
23use crate::dom::webgpu::gpurenderpipeline::GPURenderPipeline;
24use crate::script_runtime::CanGc;
25
26#[derive(JSTraceable, MallocSizeOf)]
27struct DroppableGPURenderPassEncoder {
28    #[no_trace]
29    channel: WebGPU,
30    #[no_trace]
31    render_pass: WebGPURenderPass,
32}
33
34impl Drop for DroppableGPURenderPassEncoder {
35    fn drop(&mut self) {
36        if let Err(e) = self
37            .channel
38            .0
39            .send(WebGPURequest::DropRenderPass(self.render_pass.0))
40        {
41            warn!("Failed to send WebGPURequest::DropRenderPass with {e:?}");
42        }
43    }
44}
45#[dom_struct]
46pub(crate) struct GPURenderPassEncoder {
47    reflector_: Reflector,
48    label: DomRefCell<USVString>,
49    command_encoder: Dom<GPUCommandEncoder>,
50    droppable: DroppableGPURenderPassEncoder,
51}
52
53impl GPURenderPassEncoder {
54    fn new_inherited(
55        channel: WebGPU,
56        render_pass: WebGPURenderPass,
57        parent: &GPUCommandEncoder,
58        label: USVString,
59    ) -> Self {
60        Self {
61            reflector_: Reflector::new(),
62            label: DomRefCell::new(label),
63            command_encoder: Dom::from_ref(parent),
64            droppable: DroppableGPURenderPassEncoder {
65                channel,
66                render_pass,
67            },
68        }
69    }
70
71    pub(crate) fn new(
72        global: &GlobalScope,
73        channel: WebGPU,
74        render_pass: WebGPURenderPass,
75        parent: &GPUCommandEncoder,
76        label: USVString,
77        can_gc: CanGc,
78    ) -> DomRoot<Self> {
79        reflect_dom_object(
80            Box::new(GPURenderPassEncoder::new_inherited(
81                channel,
82                render_pass,
83                parent,
84                label,
85            )),
86            global,
87            can_gc,
88        )
89    }
90
91    fn send_render_command(&self, render_command: RenderCommand) {
92        if let Err(e) = self
93            .droppable
94            .channel
95            .0
96            .send(WebGPURequest::RenderPassCommand {
97                render_pass_id: self.id().0,
98                render_command,
99                device_id: self.command_encoder.device_id().0,
100            })
101        {
102            warn!("Error sending WebGPURequest::RenderPassCommand: {e:?}")
103        }
104    }
105}
106
107impl GPURenderPassEncoder {
108    pub(crate) fn id(&self) -> WebGPURenderPass {
109        self.droppable.render_pass
110    }
111}
112
113impl GPURenderPassEncoderMethods<crate::DomTypeHolder> for GPURenderPassEncoder {
114    /// <https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label>
115    fn Label(&self) -> USVString {
116        self.label.borrow().clone()
117    }
118
119    /// <https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label>
120    fn SetLabel(&self, value: USVString) {
121        *self.label.borrow_mut() = value;
122    }
123
124    /// <https://gpuweb.github.io/gpuweb/#dom-gpuprogrammablepassencoder-setbindgroup>
125    fn SetBindGroup(&self, index: u32, bind_group: &GPUBindGroup, offsets: Vec<u32>) {
126        self.send_render_command(RenderCommand::SetBindGroup {
127            index,
128            bind_group_id: bind_group.id().0,
129            offsets,
130        })
131    }
132
133    /// <https://gpuweb.github.io/gpuweb/#dom-gpurenderpassencoder-setviewport>
134    fn SetViewport(
135        &self,
136        x: Finite<f32>,
137        y: Finite<f32>,
138        width: Finite<f32>,
139        height: Finite<f32>,
140        min_depth: Finite<f32>,
141        max_depth: Finite<f32>,
142    ) {
143        self.send_render_command(RenderCommand::SetViewport {
144            x: *x,
145            y: *y,
146            width: *width,
147            height: *height,
148            min_depth: *min_depth,
149            max_depth: *max_depth,
150        })
151    }
152
153    /// <https://gpuweb.github.io/gpuweb/#dom-gpurenderpassencoder-setscissorrect>
154    fn SetScissorRect(&self, x: u32, y: u32, width: u32, height: u32) {
155        self.send_render_command(RenderCommand::SetScissorRect {
156            x,
157            y,
158            width,
159            height,
160        })
161    }
162
163    /// <https://gpuweb.github.io/gpuweb/#dom-gpurenderpassencoder-setblendcolor>
164    fn SetBlendConstant(&self, color: GPUColor) -> Fallible<()> {
165        self.send_render_command(RenderCommand::SetBlendConstant((&color).try_convert()?));
166        Ok(())
167    }
168
169    /// <https://gpuweb.github.io/gpuweb/#dom-gpurenderpassencoder-setstencilreference>
170    fn SetStencilReference(&self, reference: u32) {
171        self.send_render_command(RenderCommand::SetStencilReference(reference))
172    }
173
174    /// <https://gpuweb.github.io/gpuweb/#dom-gpurenderpassencoder-end>
175    fn End(&self) {
176        if let Err(e) = self.droppable.channel.0.send(WebGPURequest::EndRenderPass {
177            render_pass_id: self.id().0,
178            device_id: self.command_encoder.device_id().0,
179        }) {
180            warn!("Failed to send WebGPURequest::EndRenderPass: {e:?}");
181        }
182    }
183
184    /// <https://gpuweb.github.io/gpuweb/#dom-gpurenderencoderbase-setpipeline>
185    fn SetPipeline(&self, pipeline: &GPURenderPipeline) {
186        self.send_render_command(RenderCommand::SetPipeline(pipeline.id().0))
187    }
188
189    /// <https://gpuweb.github.io/gpuweb/#dom-gpurendercommandsmixin-setindexbuffer>
190    fn SetIndexBuffer(
191        &self,
192        buffer: &GPUBuffer,
193        index_format: GPUIndexFormat,
194        offset: u64,
195        size: u64,
196    ) {
197        self.send_render_command(RenderCommand::SetIndexBuffer {
198            buffer_id: buffer.id().0,
199            index_format: match index_format {
200                GPUIndexFormat::Uint16 => wgpu_types::IndexFormat::Uint16,
201                GPUIndexFormat::Uint32 => wgpu_types::IndexFormat::Uint32,
202            },
203            offset,
204            size: wgpu_types::BufferSize::new(size),
205        })
206    }
207
208    /// <https://gpuweb.github.io/gpuweb/#dom-gpurenderencoderbase-setvertexbuffer>
209    fn SetVertexBuffer(&self, slot: u32, buffer: &GPUBuffer, offset: u64, size: u64) {
210        self.send_render_command(RenderCommand::SetVertexBuffer {
211            slot,
212            buffer_id: buffer.id().0,
213            offset,
214            size: wgpu_types::BufferSize::new(size),
215        })
216    }
217
218    /// <https://gpuweb.github.io/gpuweb/#dom-gpurenderencoderbase-draw>
219    fn Draw(&self, vertex_count: u32, instance_count: u32, first_vertex: u32, first_instance: u32) {
220        self.send_render_command(RenderCommand::Draw {
221            vertex_count,
222            instance_count,
223            first_vertex,
224            first_instance,
225        })
226    }
227
228    /// <https://gpuweb.github.io/gpuweb/#dom-gpurenderencoderbase-drawindexed>
229    fn DrawIndexed(
230        &self,
231        index_count: u32,
232        instance_count: u32,
233        first_index: u32,
234        base_vertex: i32,
235        first_instance: u32,
236    ) {
237        self.send_render_command(RenderCommand::DrawIndexed {
238            index_count,
239            instance_count,
240            first_index,
241            base_vertex,
242            first_instance,
243        })
244    }
245
246    /// <https://gpuweb.github.io/gpuweb/#dom-gpurenderencoderbase-drawindirect>
247    fn DrawIndirect(&self, buffer: &GPUBuffer, offset: u64) {
248        self.send_render_command(RenderCommand::DrawIndirect {
249            buffer_id: buffer.id().0,
250            offset,
251        })
252    }
253
254    /// <https://gpuweb.github.io/gpuweb/#dom-gpurenderencoderbase-drawindexedindirect>
255    fn DrawIndexedIndirect(&self, buffer: &GPUBuffer, offset: u64) {
256        self.send_render_command(RenderCommand::DrawIndexedIndirect {
257            buffer_id: buffer.id().0,
258            offset,
259        })
260    }
261
262    /// <https://gpuweb.github.io/gpuweb/#dom-gpurenderpassencoder-executebundles>
263    fn ExecuteBundles(&self, bundles: Vec<DomRoot<GPURenderBundle>>) {
264        let bundle_ids: Vec<_> = bundles.iter().map(|b| b.id().0).collect();
265        self.send_render_command(RenderCommand::ExecuteBundles(bundle_ids))
266    }
267}