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