Skip to main content

script/dom/webgpu/
gpupipelinelayout.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 std::borrow::Cow;
6
7use dom_struct::dom_struct;
8use script_bindings::cell::DomRefCell;
9use script_bindings::reflector::{Reflector, reflect_dom_object};
10use webgpu_traits::{WebGPU, WebGPUBindGroupLayout, WebGPUPipelineLayout, WebGPURequest};
11use wgpu_core::binding_model::PipelineLayoutDescriptor;
12
13use crate::conversions::Convert;
14use crate::dom::bindings::codegen::Bindings::WebGPUBinding::{
15    GPUPipelineLayoutDescriptor, GPUPipelineLayoutMethods,
16};
17use crate::dom::bindings::reflector::DomGlobal;
18use crate::dom::bindings::root::DomRoot;
19use crate::dom::bindings::str::USVString;
20use crate::dom::globalscope::GlobalScope;
21use crate::dom::webgpu::gpudevice::GPUDevice;
22use crate::script_runtime::CanGc;
23
24#[derive(JSTraceable, MallocSizeOf)]
25struct DroppableGPUPipelineLayout {
26    #[no_trace]
27    channel: WebGPU,
28    #[no_trace]
29    pipeline_layout: WebGPUPipelineLayout,
30}
31
32impl Drop for DroppableGPUPipelineLayout {
33    fn drop(&mut self) {
34        if let Err(e) = self
35            .channel
36            .0
37            .send(WebGPURequest::DropPipelineLayout(self.pipeline_layout.0))
38        {
39            warn!(
40                "Failed to send DropPipelineLayout ({:?}) ({})",
41                self.pipeline_layout.0, e
42            );
43        }
44    }
45}
46
47#[dom_struct]
48pub(crate) struct GPUPipelineLayout {
49    reflector_: Reflector,
50    label: DomRefCell<USVString>,
51    #[no_trace]
52    bind_group_layouts: Vec<WebGPUBindGroupLayout>,
53    droppable: DroppableGPUPipelineLayout,
54}
55
56impl GPUPipelineLayout {
57    fn new_inherited(
58        channel: WebGPU,
59        pipeline_layout: WebGPUPipelineLayout,
60        label: USVString,
61        bgls: Vec<WebGPUBindGroupLayout>,
62    ) -> Self {
63        Self {
64            reflector_: Reflector::new(),
65            label: DomRefCell::new(label),
66            bind_group_layouts: bgls,
67            droppable: DroppableGPUPipelineLayout {
68                channel,
69                pipeline_layout,
70            },
71        }
72    }
73
74    pub(crate) fn new(
75        global: &GlobalScope,
76        channel: WebGPU,
77        pipeline_layout: WebGPUPipelineLayout,
78        label: USVString,
79        bgls: Vec<WebGPUBindGroupLayout>,
80        can_gc: CanGc,
81    ) -> DomRoot<Self> {
82        reflect_dom_object(
83            Box::new(GPUPipelineLayout::new_inherited(
84                channel,
85                pipeline_layout,
86                label,
87                bgls,
88            )),
89            global,
90            can_gc,
91        )
92    }
93}
94
95impl GPUPipelineLayout {
96    pub(crate) fn id(&self) -> WebGPUPipelineLayout {
97        self.droppable.pipeline_layout
98    }
99
100    pub(crate) fn bind_group_layouts(&self) -> Vec<WebGPUBindGroupLayout> {
101        self.bind_group_layouts.clone()
102    }
103
104    /// <https://gpuweb.github.io/gpuweb/#dom-gpudevice-createpipelinelayout>
105    pub(crate) fn create(
106        device: &GPUDevice,
107        descriptor: &GPUPipelineLayoutDescriptor,
108        can_gc: CanGc,
109    ) -> DomRoot<GPUPipelineLayout> {
110        let bgls = descriptor
111            .bindGroupLayouts
112            .iter()
113            .map(|each| each.id())
114            .collect::<Vec<_>>();
115
116        let desc = PipelineLayoutDescriptor {
117            label: (&descriptor.parent).convert(),
118            // TODO(sagudev): this needs webidl sync
119            bind_group_layouts: Cow::Owned(bgls.iter().map(|l| Some(l.0)).collect::<Vec<_>>()),
120            immediate_size: 0,
121        };
122
123        let pipeline_layout_id = device.global().wgpu_id_hub().create_pipeline_layout_id();
124        device
125            .channel()
126            .0
127            .send(WebGPURequest::CreatePipelineLayout {
128                device_id: device.id().0,
129                pipeline_layout_id,
130                descriptor: desc,
131            })
132            .expect("Failed to create WebGPU PipelineLayout");
133
134        let pipeline_layout = WebGPUPipelineLayout(pipeline_layout_id);
135        GPUPipelineLayout::new(
136            &device.global(),
137            device.channel(),
138            pipeline_layout,
139            descriptor.parent.label.clone(),
140            bgls,
141            can_gc,
142        )
143    }
144}
145
146impl GPUPipelineLayoutMethods<crate::DomTypeHolder> for GPUPipelineLayout {
147    /// <https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label>
148    fn Label(&self) -> USVString {
149        self.label.borrow().clone()
150    }
151
152    /// <https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label>
153    fn SetLabel(&self, value: USVString) {
154        *self.label.borrow_mut() = value;
155    }
156}