Skip to main content

script_webgpu/
gpubindgrouplayout.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;
6use std::marker::PhantomData;
7
8use dom_struct::dom_struct;
9use js::context::{JSContext, NoGC};
10use jstraceable_derive::JSTraceable;
11use log::warn;
12use malloc_size_of_derive::MallocSizeOf;
13use script_bindings::DomTypes;
14use script_bindings::cell::DomRefCell;
15use script_bindings::codegen::GenericBindings::WebGPUBinding::{
16    GPUBindGroupLayoutDescriptor, GPUBindGroupLayoutMethods, GPUBindGroupLayoutWrap,
17};
18use script_bindings::interfaces::GlobalScopeHelpers;
19use script_bindings::reflector::{DomGlobalGeneric, Reflector, reflect_dom_object_with_wrap};
20use webgpu_traits::{WebGPU, WebGPUBindGroupLayout, WebGPURequest};
21use wgpu_core::binding_model::BindGroupLayoutDescriptor;
22
23use crate::dom::bindings::error::Fallible;
24use crate::dom::bindings::root::DomRoot;
25use crate::dom::bindings::str::USVString;
26use crate::gpuconvert::{WebGPUConvert, convert_bind_group_layout_entry};
27use crate::traits::{GPUDeviceTrait, WebGPUGlobalTrait};
28
29#[derive(JSTraceable, MallocSizeOf)]
30struct DroppableGPUBindGroupLayout {
31    #[no_trace]
32    channel: WebGPU,
33    #[no_trace]
34    bind_group_layout: WebGPUBindGroupLayout,
35}
36
37impl Drop for DroppableGPUBindGroupLayout {
38    fn drop(&mut self) {
39        if let Err(e) = self
40            .channel
41            .0
42            .send(WebGPURequest::DropBindGroupLayout(self.bind_group_layout.0))
43        {
44            warn!(
45                "Failed to send WebGPURequest::DropBindGroupLayout({:?}) ({})",
46                self.bind_group_layout.0, e
47            );
48        };
49    }
50}
51
52#[dom_struct]
53pub struct GPUBindGroupLayout<D: DomTypes> {
54    reflector_: Reflector,
55    label: DomRefCell<USVString>,
56    droppable: DroppableGPUBindGroupLayout,
57    #[no_trace = "PhantomData does not exist"]
58    phantom: PhantomData<D>,
59}
60
61impl<D> GPUBindGroupLayout<D>
62where
63    D: DomTypes<GPUBindGroupLayout = GPUBindGroupLayout<D>>,
64{
65    fn new_inherited(
66        channel: WebGPU,
67        bind_group_layout: WebGPUBindGroupLayout,
68        label: USVString,
69    ) -> Self {
70        Self {
71            reflector_: Reflector::new(),
72            label: DomRefCell::new(label),
73            droppable: DroppableGPUBindGroupLayout {
74                channel,
75                bind_group_layout,
76            },
77            phantom: PhantomData,
78        }
79    }
80
81    pub fn new(
82        cx: &mut JSContext,
83        global: &D::GlobalScope,
84        channel: WebGPU,
85        bind_group_layout: WebGPUBindGroupLayout,
86        label: USVString,
87    ) -> DomRoot<Self> {
88        reflect_dom_object_with_wrap::<D, _, _>(
89            Box::new(GPUBindGroupLayout::new_inherited(
90                channel,
91                bind_group_layout,
92                label,
93            )),
94            global,
95            cx,
96            GPUBindGroupLayoutWrap::<D>,
97        )
98    }
99}
100
101impl<D> GPUBindGroupLayout<D>
102where
103    D: DomTypes<GPUBindGroupLayout = GPUBindGroupLayout<D>>,
104    D::GPUDevice: GPUDeviceTrait<D>,
105    D::GlobalScope: WebGPUGlobalTrait + GlobalScopeHelpers<D>,
106{
107    pub fn id(&self) -> WebGPUBindGroupLayout {
108        self.droppable.bind_group_layout
109    }
110
111    /// <https://gpuweb.github.io/gpuweb/#GPUDevice-createBindGroupLayout>
112    pub fn create(
113        cx: &mut JSContext,
114        device: &D::GPUDevice,
115        descriptor: &GPUBindGroupLayoutDescriptor,
116    ) -> Fallible<DomRoot<GPUBindGroupLayout<D>>> {
117        let entries = descriptor
118            .entries
119            .iter()
120            .map(|bgle| convert_bind_group_layout_entry::<D>(bgle, device))
121            .collect::<Fallible<Result<Vec<_>, _>>>()?;
122
123        let desc = match entries {
124            Ok(entries) => Some(BindGroupLayoutDescriptor {
125                label: (&descriptor.parent).convert(),
126                entries: Cow::Owned(entries),
127            }),
128            Err(error) => {
129                device.dispatch_error(error);
130                None
131            },
132        };
133
134        let global = <D::GPUDevice as DomGlobalGeneric<D>>::global_from_reflector(device);
135        let bind_group_layout_id = global.global_wgpu_id_hub().create_bind_group_layout_id();
136        device
137            .channel()
138            .0
139            .send(WebGPURequest::CreateBindGroupLayout {
140                device_id: device.id().0,
141                bind_group_layout_id,
142                descriptor: desc,
143            })
144            .expect("Failed to create WebGPU BindGroupLayout");
145
146        let bgl = WebGPUBindGroupLayout(bind_group_layout_id);
147
148        Ok(GPUBindGroupLayout::new(
149            cx,
150            &*global,
151            device.channel(),
152            bgl,
153            descriptor.parent.label.clone(),
154        ))
155    }
156}
157
158impl<D: DomTypes> GPUBindGroupLayoutMethods<D> for GPUBindGroupLayout<D> {
159    /// <https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label>
160    fn Label(&self) -> USVString {
161        self.label.borrow().clone()
162    }
163
164    /// <https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label>
165    fn SetLabel(&self, no_gc: &NoGC, value: USVString) {
166        *self.label.safe_borrow_mut(no_gc) = value;
167    }
168}