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