Skip to main content

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