script/dom/webgpu/
gpurenderpipeline.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 base::generic_channel::GenericCallback;
6use dom_struct::dom_struct;
7use webgpu_traits::{
8    WebGPU, WebGPUBindGroupLayout, WebGPURenderPipeline, WebGPURenderPipelineResponse,
9    WebGPURequest,
10};
11use wgpu_core::pipeline::RenderPipelineDescriptor;
12
13use crate::dom::bindings::cell::DomRefCell;
14use crate::dom::bindings::codegen::Bindings::WebGPUBinding::GPURenderPipelineMethods;
15use crate::dom::bindings::error::Fallible;
16use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object};
17use crate::dom::bindings::root::{Dom, DomRoot};
18use crate::dom::bindings::str::USVString;
19use crate::dom::globalscope::GlobalScope;
20use crate::dom::webgpu::gpubindgrouplayout::GPUBindGroupLayout;
21use crate::dom::webgpu::gpudevice::{GPUDevice, PipelineLayout};
22use crate::script_runtime::CanGc;
23
24#[derive(JSTraceable, MallocSizeOf)]
25struct DroppableGPURenderPipeline {
26    #[no_trace]
27    channel: WebGPU,
28    #[no_trace]
29    render_pipeline: WebGPURenderPipeline,
30}
31
32impl Drop for DroppableGPURenderPipeline {
33    fn drop(&mut self) {
34        if let Err(e) = self
35            .channel
36            .0
37            .send(WebGPURequest::DropRenderPipeline(self.render_pipeline.0))
38        {
39            warn!(
40                "Failed to send WebGPURequest::DropRenderPipeline({:?}) ({})",
41                self.render_pipeline.0, e
42            );
43        };
44    }
45}
46
47#[dom_struct]
48pub(crate) struct GPURenderPipeline {
49    reflector_: Reflector,
50    label: DomRefCell<USVString>,
51    device: Dom<GPUDevice>,
52    droppable: DroppableGPURenderPipeline,
53}
54
55impl GPURenderPipeline {
56    fn new_inherited(
57        render_pipeline: WebGPURenderPipeline,
58        label: USVString,
59        device: &GPUDevice,
60    ) -> Self {
61        Self {
62            reflector_: Reflector::new(),
63            label: DomRefCell::new(label),
64            device: Dom::from_ref(device),
65            droppable: DroppableGPURenderPipeline {
66                channel: device.channel(),
67                render_pipeline,
68            },
69        }
70    }
71
72    pub(crate) fn new(
73        global: &GlobalScope,
74        render_pipeline: WebGPURenderPipeline,
75        label: USVString,
76        device: &GPUDevice,
77        can_gc: CanGc,
78    ) -> DomRoot<Self> {
79        reflect_dom_object(
80            Box::new(GPURenderPipeline::new_inherited(
81                render_pipeline,
82                label,
83                device,
84            )),
85            global,
86            can_gc,
87        )
88    }
89}
90
91impl GPURenderPipeline {
92    pub(crate) fn id(&self) -> WebGPURenderPipeline {
93        self.droppable.render_pipeline
94    }
95
96    /// <https://gpuweb.github.io/gpuweb/#dom-gpudevice-createrenderpipeline>
97    pub(crate) fn create(
98        device: &GPUDevice,
99        pipeline_layout: PipelineLayout,
100        descriptor: RenderPipelineDescriptor<'static>,
101        async_sender: Option<GenericCallback<WebGPURenderPipelineResponse>>,
102    ) -> Fallible<WebGPURenderPipeline> {
103        let render_pipeline_id = device.global().wgpu_id_hub().create_render_pipeline_id();
104
105        device
106            .channel()
107            .0
108            .send(WebGPURequest::CreateRenderPipeline {
109                device_id: device.id().0,
110                render_pipeline_id,
111                descriptor,
112                implicit_ids: pipeline_layout.implicit(),
113                async_sender,
114            })
115            .expect("Failed to create WebGPU render pipeline");
116
117        Ok(WebGPURenderPipeline(render_pipeline_id))
118    }
119}
120
121impl GPURenderPipelineMethods<crate::DomTypeHolder> for GPURenderPipeline {
122    /// <https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label>
123    fn Label(&self) -> USVString {
124        self.label.borrow().clone()
125    }
126
127    /// <https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label>
128    fn SetLabel(&self, value: USVString) {
129        *self.label.borrow_mut() = value;
130    }
131
132    /// <https://gpuweb.github.io/gpuweb/#dom-gpupipelinebase-getbindgrouplayout>
133    fn GetBindGroupLayout(&self, index: u32) -> Fallible<DomRoot<GPUBindGroupLayout>> {
134        let id = self.global().wgpu_id_hub().create_bind_group_layout_id();
135
136        if let Err(e) = self
137            .droppable
138            .channel
139            .0
140            .send(WebGPURequest::RenderGetBindGroupLayout {
141                device_id: self.device.id().0,
142                pipeline_id: self.id().0,
143                index,
144                id,
145            })
146        {
147            warn!("Failed to send WebGPURequest::RenderGetBindGroupLayout {e:?}");
148        }
149
150        Ok(GPUBindGroupLayout::new(
151            &self.global(),
152            self.droppable.channel.clone(),
153            WebGPUBindGroupLayout(id),
154            USVString::default(),
155            CanGc::note(),
156        ))
157    }
158}