Skip to main content

script_webgpu/
gpubindgroup.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 js::context::{JSContext, NoGC};
9use jstraceable_derive::JSTraceable;
10use log::warn;
11use malloc_size_of_derive::MallocSizeOf;
12use script_bindings::DomTypes;
13use script_bindings::cell::DomRefCell;
14use script_bindings::codegen::GenericBindings::WebGPUBinding::{
15    GPUBindGroupDescriptor, GPUBindGroupMethods, GPUBindGroupWrap,
16};
17use script_bindings::interfaces::PromiseHelpers;
18use script_bindings::reflector::{DomGlobalGeneric, Reflector, reflect_dom_object_with_wrap};
19use webgpu_traits::{WebGPU, WebGPUBindGroup, WebGPUDevice, WebGPURequest};
20use wgpu_core::binding_model::BindGroupDescriptor;
21
22use crate::dom::bindings::root::{Dom, DomRoot};
23use crate::dom::bindings::str::USVString;
24use crate::gpubindgrouplayout::GPUBindGroupLayout;
25use crate::gpubuffer::GPUBuffer;
26use crate::gpuconvert::{WebGPUConvert, convert_bind_group_entry};
27use crate::traits::{
28    GPUDeviceTrait, GPUExternalTextureTrait, GPUSamplerTrait, GPUTextureTrait, GPUTextureViewTrait,
29    WebGPUGlobalTrait,
30};
31
32#[derive(JSTraceable, MallocSizeOf)]
33struct DroppableGPUBindGroup {
34    #[no_trace]
35    channel: WebGPU,
36    #[no_trace]
37    bind_group: WebGPUBindGroup,
38}
39
40impl Drop for DroppableGPUBindGroup {
41    fn drop(&mut self) {
42        if let Err(e) = self
43            .channel
44            .0
45            .send(WebGPURequest::DropBindGroup(self.bind_group.0))
46        {
47            warn!(
48                "Failed to send WebGPURequest::DropBindGroup({:?}) ({})",
49                self.bind_group.0, e
50            );
51        };
52    }
53}
54
55#[dom_struct]
56pub struct GPUBindGroup<D: DomTypes> {
57    reflector_: Reflector,
58    label: DomRefCell<USVString>,
59    #[no_trace]
60    device: WebGPUDevice,
61    layout: Dom<GPUBindGroupLayout<D>>,
62    droppable: DroppableGPUBindGroup,
63}
64
65impl<D> GPUBindGroup<D>
66where
67    D: DomTypes<GPUBindGroup = GPUBindGroup<D>>,
68{
69    fn new_inherited(
70        channel: WebGPU,
71        bind_group: WebGPUBindGroup,
72        device: WebGPUDevice,
73        layout: &GPUBindGroupLayout<D>,
74        label: USVString,
75    ) -> Self {
76        Self {
77            reflector_: Reflector::new(),
78            label: DomRefCell::new(label),
79            device,
80            layout: Dom::from_ref(layout),
81            droppable: DroppableGPUBindGroup {
82                channel,
83                bind_group,
84            },
85        }
86    }
87
88    pub(crate) fn new(
89        cx: &mut JSContext,
90        global: &D::GlobalScope,
91        channel: WebGPU,
92        bind_group: WebGPUBindGroup,
93        device: WebGPUDevice,
94        layout: &GPUBindGroupLayout<D>,
95        label: USVString,
96    ) -> DomRoot<Self> {
97        reflect_dom_object_with_wrap::<D, _, _>(
98            Box::new(GPUBindGroup::new_inherited(
99                channel, bind_group, device, layout, label,
100            )),
101            global,
102            cx,
103            GPUBindGroupWrap::<D>,
104        )
105    }
106}
107
108impl<D> GPUBindGroup<D>
109where
110    D: DomTypes<
111            GPUBuffer = GPUBuffer<D>,
112            GPUBindGroup = GPUBindGroup<D>,
113            GPUBindGroupLayout = GPUBindGroupLayout<D>,
114        >,
115    D::GPUDevice: DomGlobalGeneric<D> + GPUDeviceTrait<D>,
116    D::GlobalScope: WebGPUGlobalTrait,
117    D::GPUExternalTexture: GPUExternalTextureTrait,
118    D::GPUSampler: GPUSamplerTrait,
119    D::GPUTexture: GPUTextureTrait,
120    D::GPUTextureView: GPUTextureViewTrait,
121    D::Promise: PromiseHelpers<D>,
122{
123    pub fn id(&self) -> &WebGPUBindGroup {
124        &self.droppable.bind_group
125    }
126
127    /// <https://gpuweb.github.io/gpuweb/#dom-gpudevice-createbindgroup>
128    pub fn create(
129        cx: &mut JSContext,
130        device: &D::GPUDevice,
131        descriptor: &GPUBindGroupDescriptor<D>,
132    ) -> DomRoot<GPUBindGroup<D>> {
133        let entries = descriptor
134            .entries
135            .iter()
136            .map(|bind| convert_bind_group_entry(cx, bind))
137            .collect::<Vec<_>>();
138
139        let desc = BindGroupDescriptor {
140            label: (&descriptor.parent).convert(),
141            layout: descriptor.layout.id().0,
142            entries: Cow::Owned(entries),
143        };
144
145        let bind_group_id = <D::GPUDevice as DomGlobalGeneric<D>>::global_from_reflector(device)
146            .global_wgpu_id_hub()
147            .create_bind_group_id();
148        device
149            .channel()
150            .0
151            .send(WebGPURequest::CreateBindGroup {
152                device_id: device.id().0,
153                bind_group_id,
154                descriptor: desc,
155            })
156            .expect("Failed to create WebGPU BindGroup");
157
158        let bind_group = WebGPUBindGroup(bind_group_id);
159
160        let global = <D::GPUDevice as DomGlobalGeneric<D>>::global_from_reflector(device);
161        GPUBindGroup::new(
162            cx,
163            &*global,
164            device.channel(),
165            bind_group,
166            device.id(),
167            &descriptor.layout,
168            descriptor.parent.label.clone(),
169        )
170    }
171}
172
173impl<D: DomTypes> GPUBindGroupMethods<D> for GPUBindGroup<D> {
174    /// <https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label>
175    fn Label(&self) -> USVString {
176        self.label.borrow().clone()
177    }
178
179    /// <https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label>
180    fn SetLabel(&self, no_gc: &NoGC, value: USVString) {
181        *self.label.safe_borrow_mut(no_gc) = value;
182    }
183}