script/dom/webgpu/
gpurenderpipeline.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 base::generic_channel::GenericCallback;
6use dom_struct::dom_struct;
7use webgpu_traits::{
8    WebGPU, WebGPUBindGroupLayout, WebGPURenderPipeline, WebGPURenderPipelineResponse,
9    WebGPURequest,
10};
11use wgpu_core::pipeline::RenderPipelineDescriptor;
12
13use crate::dom::bindings::cell::DomRefCell;
14use crate::dom::bindings::codegen::Bindings::WebGPUBinding::GPURenderPipelineMethods;
15use crate::dom::bindings::error::Fallible;
16use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object};
17use crate::dom::bindings::root::{Dom, DomRoot};
18use crate::dom::bindings::str::USVString;
19use crate::dom::globalscope::GlobalScope;
20use crate::dom::webgpu::gpubindgrouplayout::GPUBindGroupLayout;
21use crate::dom::webgpu::gpudevice::{GPUDevice, PipelineLayout};
22use crate::script_runtime::CanGc;
23
24#[dom_struct]
25pub(crate) struct GPURenderPipeline {
26    reflector_: Reflector,
27    #[no_trace]
28    channel: WebGPU,
29    label: DomRefCell<USVString>,
30    #[no_trace]
31    render_pipeline: WebGPURenderPipeline,
32    device: Dom<GPUDevice>,
33}
34
35impl GPURenderPipeline {
36    fn new_inherited(
37        render_pipeline: WebGPURenderPipeline,
38        label: USVString,
39        device: &GPUDevice,
40    ) -> Self {
41        Self {
42            reflector_: Reflector::new(),
43            channel: device.channel(),
44            label: DomRefCell::new(label),
45            render_pipeline,
46            device: Dom::from_ref(device),
47        }
48    }
49
50    pub(crate) fn new(
51        global: &GlobalScope,
52        render_pipeline: WebGPURenderPipeline,
53        label: USVString,
54        device: &GPUDevice,
55        can_gc: CanGc,
56    ) -> DomRoot<Self> {
57        reflect_dom_object(
58            Box::new(GPURenderPipeline::new_inherited(
59                render_pipeline,
60                label,
61                device,
62            )),
63            global,
64            can_gc,
65        )
66    }
67}
68
69impl GPURenderPipeline {
70    pub(crate) fn id(&self) -> WebGPURenderPipeline {
71        self.render_pipeline
72    }
73
74    /// <https://gpuweb.github.io/gpuweb/#dom-gpudevice-createrenderpipeline>
75    pub(crate) fn create(
76        device: &GPUDevice,
77        pipeline_layout: PipelineLayout,
78        descriptor: RenderPipelineDescriptor<'static>,
79        async_sender: Option<GenericCallback<WebGPURenderPipelineResponse>>,
80    ) -> Fallible<WebGPURenderPipeline> {
81        let render_pipeline_id = device.global().wgpu_id_hub().create_render_pipeline_id();
82
83        device
84            .channel()
85            .0
86            .send(WebGPURequest::CreateRenderPipeline {
87                device_id: device.id().0,
88                render_pipeline_id,
89                descriptor,
90                implicit_ids: pipeline_layout.implicit(),
91                async_sender,
92            })
93            .expect("Failed to create WebGPU render pipeline");
94
95        Ok(WebGPURenderPipeline(render_pipeline_id))
96    }
97}
98
99impl GPURenderPipelineMethods<crate::DomTypeHolder> for GPURenderPipeline {
100    /// <https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label>
101    fn Label(&self) -> USVString {
102        self.label.borrow().clone()
103    }
104
105    /// <https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label>
106    fn SetLabel(&self, value: USVString) {
107        *self.label.borrow_mut() = value;
108    }
109
110    /// <https://gpuweb.github.io/gpuweb/#dom-gpupipelinebase-getbindgrouplayout>
111    fn GetBindGroupLayout(&self, index: u32) -> Fallible<DomRoot<GPUBindGroupLayout>> {
112        let id = self.global().wgpu_id_hub().create_bind_group_layout_id();
113
114        if let Err(e) = self
115            .channel
116            .0
117            .send(WebGPURequest::RenderGetBindGroupLayout {
118                device_id: self.device.id().0,
119                pipeline_id: self.render_pipeline.0,
120                index,
121                id,
122            })
123        {
124            warn!("Failed to send WebGPURequest::RenderGetBindGroupLayout {e:?}");
125        }
126
127        Ok(GPUBindGroupLayout::new(
128            &self.global(),
129            self.channel.clone(),
130            WebGPUBindGroupLayout(id),
131            USVString::default(),
132            CanGc::note(),
133        ))
134    }
135}
136
137impl Drop for GPURenderPipeline {
138    fn drop(&mut self) {
139        if let Err(e) = self
140            .channel
141            .0
142            .send(WebGPURequest::DropRenderPipeline(self.render_pipeline.0))
143        {
144            warn!(
145                "Failed to send WebGPURequest::DropRenderPipeline({:?}) ({})",
146                self.render_pipeline.0, e
147            );
148        };
149    }
150}