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