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 js::context::{JSContext, NoGC};
7use script_bindings::cell::DomRefCell;
8use script_bindings::reflector::{Reflector, reflect_dom_object_with_cx};
9use servo_base::generic_channel::GenericCallback;
10use webgpu_traits::{
11    WebGPU, WebGPUBindGroupLayout, WebGPUComputePipeline, WebGPUComputePipelineResponse,
12    WebGPURequest,
13};
14use wgpu_core::pipeline::ComputePipelineDescriptor;
15
16use crate::conversions::Convert;
17use crate::dom::bindings::codegen::Bindings::WebGPUBinding::{
18    GPUComputePipelineDescriptor, GPUComputePipelineMethods,
19};
20use crate::dom::bindings::error::Fallible;
21use crate::dom::bindings::reflector::DomGlobal;
22use crate::dom::bindings::root::{Dom, DomRoot};
23use crate::dom::bindings::str::USVString;
24use crate::dom::globalscope::GlobalScope;
25use crate::dom::webgpu::gpubindgrouplayout::GPUBindGroupLayout;
26use crate::dom::webgpu::gpudevice::GPUDevice;
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        cx: &mut JSContext,
78        global: &GlobalScope,
79        compute_pipeline: WebGPUComputePipeline,
80        label: USVString,
81        device: &GPUDevice,
82    ) -> DomRoot<Self> {
83        reflect_dom_object_with_cx(
84            Box::new(GPUComputePipeline::new_inherited(
85                compute_pipeline,
86                label,
87                device,
88            )),
89            global,
90            cx,
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, no_gc: &NoGC, value: USVString) {
140        *self.label.safe_borrow_mut(no_gc) = value;
141    }
142
143    /// <https://gpuweb.github.io/gpuweb/#dom-gpupipelinebase-getbindgrouplayout>
144    fn GetBindGroupLayout(
145        &self,
146        cx: &mut JSContext,
147        index: u32,
148    ) -> Fallible<DomRoot<GPUBindGroupLayout>> {
149        let id = self.global().wgpu_id_hub().create_bind_group_layout_id();
150
151        if let Err(e) = self
152            .droppable
153            .channel
154            .0
155            .send(WebGPURequest::ComputeGetBindGroupLayout {
156                device_id: self.device.id().0,
157                pipeline_id: self.id().0,
158                index,
159                id,
160            })
161        {
162            warn!("Failed to send WebGPURequest::ComputeGetBindGroupLayout {e:?}");
163        }
164
165        Ok(GPUBindGroupLayout::new(
166            cx,
167            &self.global(),
168            self.droppable.channel.clone(),
169            WebGPUBindGroupLayout(id),
170            USVString::default(),
171        ))
172    }
173}