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 js::context::JSContext;
7use script_bindings::cell::DomRefCell;
8use script_bindings::reflector::{Reflector, reflect_dom_object_with_cx};
9use servo_base::generic_channel::GenericCallback;
10use webgpu_traits::{
11    WebGPU, WebGPUBindGroupLayout, WebGPURenderPipeline, WebGPURenderPipelineResponse,
12    WebGPURequest,
13};
14use wgpu_core::pipeline::RenderPipelineDescriptor;
15
16use crate::dom::bindings::codegen::Bindings::WebGPUBinding::GPURenderPipelineMethods;
17use crate::dom::bindings::error::Fallible;
18use crate::dom::bindings::reflector::DomGlobal;
19use crate::dom::bindings::root::{Dom, DomRoot};
20use crate::dom::bindings::str::USVString;
21use crate::dom::globalscope::GlobalScope;
22use crate::dom::webgpu::gpubindgrouplayout::GPUBindGroupLayout;
23use crate::dom::webgpu::gpudevice::GPUDevice;
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        cx: &mut JSContext,
75        global: &GlobalScope,
76        render_pipeline: WebGPURenderPipeline,
77        label: USVString,
78        device: &GPUDevice,
79    ) -> DomRoot<Self> {
80        reflect_dom_object_with_cx(
81            Box::new(GPURenderPipeline::new_inherited(
82                render_pipeline,
83                label,
84                device,
85            )),
86            global,
87            cx,
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(
133        &self,
134        cx: &mut JSContext,
135        index: u32,
136    ) -> Fallible<DomRoot<GPUBindGroupLayout>> {
137        let id = self.global().wgpu_id_hub().create_bind_group_layout_id();
138
139        if let Err(e) = self
140            .droppable
141            .channel
142            .0
143            .send(WebGPURequest::RenderGetBindGroupLayout {
144                device_id: self.device.id().0,
145                pipeline_id: self.id().0,
146                index,
147                id,
148            })
149        {
150            warn!("Failed to send WebGPURequest::RenderGetBindGroupLayout {e:?}");
151        }
152
153        Ok(GPUBindGroupLayout::new(
154            cx,
155            &self.global(),
156            self.droppable.channel.clone(),
157            WebGPUBindGroupLayout(id),
158            USVString::default(),
159        ))
160    }
161}