script_webgpu/
gpurenderpipeline.rs1use dom_struct::dom_struct;
6use js::context::{JSContext, NoGC};
7use jstraceable_derive::JSTraceable;
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 GPURenderPipelineMethods, GPURenderPipelineWrap,
14};
15use script_bindings::reflector::{DomGlobalGeneric, Reflector, reflect_dom_object_with_wrap};
16use servo_base::generic_channel::GenericCallback;
17use webgpu_traits::{
18 WebGPU, WebGPUBindGroupLayout, WebGPURenderPipeline, WebGPURenderPipelineResponse,
19 WebGPURequest,
20};
21use wgpu_core::pipeline::RenderPipelineDescriptor;
22
23use crate::dom::bindings::error::Fallible;
24use crate::dom::bindings::root::{Dom, DomRoot};
25use crate::dom::bindings::str::USVString;
26use crate::gpubindgrouplayout::GPUBindGroupLayout;
27use crate::traits::{Equivalence, GPUDeviceTrait, WebGPUGlobalTrait};
28
29#[derive(JSTraceable, MallocSizeOf)]
30struct DroppableGPURenderPipeline {
31 #[no_trace]
32 channel: WebGPU,
33 #[no_trace]
34 render_pipeline: WebGPURenderPipeline,
35}
36
37impl Drop for DroppableGPURenderPipeline {
38 fn drop(&mut self) {
39 if let Err(e) = self
40 .channel
41 .0
42 .send(WebGPURequest::DropRenderPipeline(self.render_pipeline.0))
43 {
44 warn!(
45 "Failed to send WebGPURequest::DropRenderPipeline({:?}) ({})",
46 self.render_pipeline.0, e
47 );
48 };
49 }
50}
51
52#[dom_struct]
53pub struct GPURenderPipeline<D: DomTypes> {
54 reflector_: Reflector,
55 label: DomRefCell<USVString>,
56 device: Dom<D::GPUDevice>,
57 droppable: DroppableGPURenderPipeline,
58}
59
60impl<D> GPURenderPipeline<D>
61where
62 D: Equivalence,
63 D::GPUDevice: GPUDeviceTrait<D>,
64{
65 fn new_inherited(
66 render_pipeline: WebGPURenderPipeline,
67 label: USVString,
68 device: &D::GPUDevice,
69 ) -> Self {
70 Self {
71 reflector_: Reflector::new(),
72 label: DomRefCell::new(label),
73 device: Dom::from_ref(device),
74 droppable: DroppableGPURenderPipeline {
75 channel: device.channel(),
76 render_pipeline,
77 },
78 }
79 }
80
81 pub fn new(
82 cx: &mut JSContext,
83 global: &D::GlobalScope,
84 render_pipeline: WebGPURenderPipeline,
85 label: USVString,
86 device: &D::GPUDevice,
87 ) -> DomRoot<Self> {
88 reflect_dom_object_with_wrap::<D, _, _>(
89 Box::new(GPURenderPipeline::new_inherited(
90 render_pipeline,
91 label,
92 device,
93 )),
94 global,
95 cx,
96 GPURenderPipelineWrap::<D>,
97 )
98 }
99}
100
101impl<D> GPURenderPipeline<D>
102where
103 D: Equivalence,
104 D::GPUDevice: GPUDeviceTrait<D>,
105 D::GlobalScope: WebGPUGlobalTrait,
106 Self: DomGlobalGeneric<D>,
107{
108 pub(crate) fn id(&self) -> WebGPURenderPipeline {
109 self.droppable.render_pipeline
110 }
111
112 pub fn create(
114 device: &D::GPUDevice,
115 descriptor: RenderPipelineDescriptor<'static>,
116 async_sender: Option<GenericCallback<WebGPURenderPipelineResponse>>,
117 ) -> Fallible<WebGPURenderPipeline> {
118 let render_pipeline_id = device
119 .global_from_reflector()
120 .global_wgpu_id_hub()
121 .create_render_pipeline_id();
122
123 device
124 .channel()
125 .0
126 .send(WebGPURequest::CreateRenderPipeline {
127 device_id: device.id().0,
128 render_pipeline_id,
129 descriptor,
130 async_sender,
131 })
132 .expect("Failed to create WebGPU render pipeline");
133
134 Ok(WebGPURenderPipeline(render_pipeline_id))
135 }
136}
137
138impl<D> GPURenderPipelineMethods<D> for GPURenderPipeline<D>
139where
140 D: Equivalence,
141 D::GlobalScope: DomGlobalGeneric<D> + WebGPUGlobalTrait,
142 D::GPUDevice: GPUDeviceTrait<D>,
143 Self: DomGlobalGeneric<D>,
144{
145 fn Label(&self) -> USVString {
147 self.label.borrow().clone()
148 }
149
150 fn SetLabel(&self, no_gc: &NoGC, value: USVString) {
152 *self.label.safe_borrow_mut(no_gc) = value;
153 }
154
155 fn GetBindGroupLayout(
157 &self,
158 cx: &mut JSContext,
159 index: u32,
160 ) -> Fallible<DomRoot<GPUBindGroupLayout<D>>> {
161 let id = self
162 .global_from_reflector()
163 .global_wgpu_id_hub()
164 .create_bind_group_layout_id();
165
166 if let Err(e) = self
167 .droppable
168 .channel
169 .0
170 .send(WebGPURequest::RenderGetBindGroupLayout {
171 device_id: self.device.id().0,
172 pipeline_id: self.id().0,
173 index,
174 id,
175 })
176 {
177 warn!("Failed to send WebGPURequest::RenderGetBindGroupLayout {e:?}");
178 }
179
180 Ok(GPUBindGroupLayout::new(
181 cx,
182 &*self.global_from_reflector(),
183 self.droppable.channel.clone(),
184 WebGPUBindGroupLayout(id),
185 USVString::default(),
186 ))
187 }
188}