Skip to main content

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 script_bindings::cell::DomRefCell;
7use script_bindings::reflector::{Reflector, reflect_dom_object};
8use servo_base::generic_channel::GenericCallback;
9use webgpu_traits::{
10    WebGPU, WebGPUBindGroupLayout, WebGPUComputePipeline, WebGPUComputePipelineResponse,
11    WebGPURequest,
12};
13use wgpu_core::pipeline::ComputePipelineDescriptor;
14
15use crate::conversions::Convert;
16use crate::dom::bindings::codegen::Bindings::WebGPUBinding::{
17    GPUComputePipelineDescriptor, GPUComputePipelineMethods,
18};
19use crate::dom::bindings::error::Fallible;
20use crate::dom::bindings::reflector::DomGlobal;
21use crate::dom::bindings::root::{Dom, DomRoot};
22use crate::dom::bindings::str::USVString;
23use crate::dom::globalscope::GlobalScope;
24use crate::dom::webgpu::gpubindgrouplayout::GPUBindGroupLayout;
25use crate::dom::webgpu::gpudevice::GPUDevice;
26use crate::script_runtime::CanGc;
27
28#[derive(JSTraceable, MallocSizeOf)]
29struct DroppableGPUComputePipeline {
30    #[no_trace]
31    channel: WebGPU,
32    #[no_trace]
33    compute_pipeline: WebGPUComputePipeline,
34}
35
36impl Drop for DroppableGPUComputePipeline {
37    fn drop(&mut self) {
38        if let Err(e) = self
39            .channel
40            .0
41            .send(WebGPURequest::DropComputePipeline(self.compute_pipeline.0))
42        {
43            warn!(
44                "Failed to send WebGPURequest::DropComputePipeline({:?}) ({})",
45                self.compute_pipeline.0, e
46            );
47        };
48    }
49}
50
51#[dom_struct]
52pub(crate) struct GPUComputePipeline {
53    reflector_: Reflector,
54    label: DomRefCell<USVString>,
55    device: Dom<GPUDevice>,
56    droppable: DroppableGPUComputePipeline,
57}
58
59impl GPUComputePipeline {
60    fn new_inherited(
61        compute_pipeline: WebGPUComputePipeline,
62        label: USVString,
63        device: &GPUDevice,
64    ) -> Self {
65        Self {
66            reflector_: Reflector::new(),
67            label: DomRefCell::new(label),
68            device: Dom::from_ref(device),
69            droppable: DroppableGPUComputePipeline {
70                channel: device.channel(),
71                compute_pipeline,
72            },
73        }
74    }
75
76    pub(crate) fn new(
77        global: &GlobalScope,
78        compute_pipeline: WebGPUComputePipeline,
79        label: USVString,
80        device: &GPUDevice,
81        can_gc: CanGc,
82    ) -> DomRoot<Self> {
83        reflect_dom_object(
84            Box::new(GPUComputePipeline::new_inherited(
85                compute_pipeline,
86                label,
87                device,
88            )),
89            global,
90            can_gc,
91        )
92    }
93}
94
95impl GPUComputePipeline {
96    pub(crate) fn id(&self) -> &WebGPUComputePipeline {
97        &self.droppable.compute_pipeline
98    }
99
100    /// <https://gpuweb.github.io/gpuweb/#dom-gpudevice-createcomputepipeline>
101    pub(crate) fn create(
102        device: &GPUDevice,
103        descriptor: &GPUComputePipelineDescriptor,
104        async_sender: Option<GenericCallback<WebGPUComputePipelineResponse>>,
105    ) -> WebGPUComputePipeline {
106        let compute_pipeline_id = device.global().wgpu_id_hub().create_compute_pipeline_id();
107
108        let pipeline_layout = device.get_pipeline_layout_data(&descriptor.parent.layout);
109
110        let desc = ComputePipelineDescriptor {
111            label: (&descriptor.parent.parent).convert(),
112            layout: pipeline_layout.explicit(),
113            stage: (&descriptor.compute).convert(),
114            cache: None,
115        };
116
117        device
118            .channel()
119            .0
120            .send(WebGPURequest::CreateComputePipeline {
121                device_id: device.id().0,
122                compute_pipeline_id,
123                descriptor: desc,
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::deprecated_note(),
167        ))
168    }
169}