Skip to main content

script_webgpu/
gpushadermodule.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 js::realm::CurrentRealm;
8use log::warn;
9use malloc_size_of_derive::MallocSizeOf;
10use script_bindings::DomTypes;
11use script_bindings::cell::DomRefCell;
12use script_bindings::codegen::GenericBindings::WebGPUBinding::{
13    GPUShaderModuleDescriptor, GPUShaderModuleMethods, GPUShaderModuleWrap,
14};
15use script_bindings::interfaces::{
16    HeapTracedPromiseHelpers, PromiseHelpers, StackRootPromiseHelpers,
17};
18use script_bindings::reflector::{DomGlobalGeneric, Reflector, reflect_dom_object_with_wrap};
19use webgpu_traits::{WebGPU, WebGPURequest, WebGPUShaderModule};
20
21use crate::JSTraceable;
22use crate::dom::bindings::root::DomRoot;
23use crate::dom::bindings::str::USVString;
24use crate::dom::bindings::trace::RootedTraceableBox;
25use crate::traits::{Equivalence, GPUDeviceTrait, WebGPUGlobalTrait, WebGPUPromiseTrait};
26
27#[derive(JSTraceable, MallocSizeOf)]
28struct DroppableGPUShaderModule {
29    #[no_trace]
30    channel: WebGPU,
31    #[no_trace]
32    shader_module: WebGPUShaderModule,
33}
34
35impl Drop for DroppableGPUShaderModule {
36    fn drop(&mut self) {
37        if let Err(e) = self
38            .channel
39            .0
40            .send(WebGPURequest::DropShaderModule(self.shader_module.0))
41        {
42            warn!(
43                "Failed to send DropShaderModule ({:?}) ({})",
44                self.shader_module.0, e
45            );
46        }
47    }
48}
49
50#[dom_struct]
51pub struct GPUShaderModule<D: DomTypes> {
52    reflector_: Reflector,
53    label: DomRefCell<USVString>,
54    compilation_info_promise: <D::Promise as PromiseHelpers<D>>::HeapTraced,
55    droppable: DroppableGPUShaderModule,
56}
57
58impl<D: Equivalence> GPUShaderModule<D> {
59    fn new_inherited(
60        channel: WebGPU,
61        shader_module: WebGPUShaderModule,
62        label: USVString,
63        promise: &<D::Promise as PromiseHelpers<D>>::StackRoot,
64    ) -> Self {
65        Self {
66            reflector_: Reflector::new(),
67            label: DomRefCell::new(label),
68            compilation_info_promise: promise.to_traced(),
69            droppable: DroppableGPUShaderModule {
70                channel,
71                shader_module,
72            },
73        }
74    }
75
76    pub(crate) fn new(
77        cx: &mut JSContext,
78        global: &D::GlobalScope,
79        channel: WebGPU,
80        shader_module: WebGPUShaderModule,
81        label: USVString,
82        promise: &<D::Promise as PromiseHelpers<D>>::StackRoot,
83    ) -> DomRoot<Self> {
84        reflect_dom_object_with_wrap::<D, _, _>(
85            Box::new(GPUShaderModule::new_inherited(
86                channel,
87                shader_module,
88                label,
89                promise,
90            )),
91            global,
92            cx,
93            GPUShaderModuleWrap::<D>,
94        )
95    }
96}
97
98impl<D> GPUShaderModule<D>
99where
100    D: Equivalence,
101    D::Promise: PromiseHelpers<D>,
102    <D::Promise as PromiseHelpers<D>>::StackRoot: WebGPUPromiseTrait<D>,
103    D::GlobalScope: WebGPUGlobalTrait,
104    D::GPUDevice: GPUDeviceTrait<D>,
105{
106    pub(crate) fn id(&self) -> WebGPUShaderModule {
107        self.droppable.shader_module
108    }
109
110    /// <https://gpuweb.github.io/gpuweb/#dom-gpudevice-createshadermodule>
111    pub fn create(
112        cx: &mut CurrentRealm<'_>,
113        device: &D::GPUDevice,
114        descriptor: RootedTraceableBox<GPUShaderModuleDescriptor>,
115    ) -> DomRoot<GPUShaderModule<D>> {
116        let program_id = device
117            .global_from_reflector()
118            .global_wgpu_id_hub()
119            .create_shader_module_id();
120        let promise = D::Promise::new_in_realm_rooted(cx);
121        let shader_module = GPUShaderModule::new(
122            cx,
123            &*device.global_from_reflector(),
124            device.channel(),
125            WebGPUShaderModule(program_id),
126            descriptor.parent.label.clone(),
127            &promise,
128        );
129        let callback = promise.callback_promise_gpushadermodule(&*shader_module);
130        device
131            .channel()
132            .0
133            .send(WebGPURequest::CreateShaderModule {
134                device_id: device.id().0,
135                program_id,
136                program: descriptor.code.0.clone(),
137                label: None,
138                callback,
139            })
140            .expect("Failed to create WebGPU ShaderModule");
141        shader_module
142    }
143}
144
145impl<D: DomTypes> GPUShaderModuleMethods<D> for GPUShaderModule<D> {
146    /// <https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label>
147    fn Label(&self) -> USVString {
148        self.label.borrow().clone()
149    }
150
151    /// <https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label>
152    fn SetLabel(&self, no_gc: &NoGC, value: USVString) {
153        *self.label.safe_borrow_mut(no_gc) = value;
154    }
155
156    /// <https://gpuweb.github.io/gpuweb/#dom-gpushadermodule-getcompilationinfo>
157    fn GetCompilationInfo(&self) -> <D::Promise as PromiseHelpers<D>>::StackRoot {
158        self.compilation_info_promise.root()
159    }
160}