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::interfaces::PromiseHelpers;
16use script_bindings::reflector::{DomGlobalGeneric, Reflector, reflect_dom_object_with_wrap};
17use servo_base::generic_channel::GenericCallback;
18use webgpu_traits::{
19 RenderPipelineDescriptor, WebGPU, WebGPUBindGroupLayout, WebGPURenderPipeline,
20 WebGPURenderPipelineResponse, WebGPURequest,
21};
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::gpudevice::GPUDevice;
28use crate::traits::{Equivalence, WebGPUGlobalTrait, WebGPUPromise};
29
30#[derive(JSTraceable, MallocSizeOf)]
31struct DroppableGPURenderPipeline {
32 #[no_trace]
33 channel: WebGPU,
34 #[no_trace]
35 render_pipeline: WebGPURenderPipeline,
36}
37
38impl Drop for DroppableGPURenderPipeline {
39 fn drop(&mut self) {
40 if let Err(e) = self
41 .channel
42 .0
43 .send(WebGPURequest::DropRenderPipeline(self.render_pipeline.0))
44 {
45 warn!(
46 "Failed to send WebGPURequest::DropRenderPipeline({:?}) ({})",
47 self.render_pipeline.0, e
48 );
49 };
50 }
51}
52
53#[dom_struct]
54pub struct GPURenderPipeline<D: DomTypes> {
55 reflector_: Reflector,
56 label: DomRefCell<USVString>,
57 device: Dom<D::GPUDevice>,
58 droppable: DroppableGPURenderPipeline,
59}
60
61impl<D> GPURenderPipeline<D>
62where
63 D: Equivalence,
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 cx,
90 Box::new(GPURenderPipeline::new_inherited(
91 render_pipeline,
92 label,
93 device,
94 )),
95 global,
96 GPURenderPipelineWrap::<D>,
97 )
98 }
99}
100
101impl<D> GPURenderPipeline<D>
102where
103 D: Equivalence,
104 <D::Promise as PromiseHelpers<D>>::StackRoot: WebGPUPromise<D>,
105{
106 pub(crate) fn id(&self) -> WebGPURenderPipeline {
107 self.droppable.render_pipeline
108 }
109
110 pub(crate) fn create(
112 device: &GPUDevice<D>,
113 descriptor: RenderPipelineDescriptor<'static>,
114 async_sender: Option<GenericCallback<WebGPURenderPipelineResponse>>,
115 ) -> Fallible<WebGPURenderPipeline> {
116 let render_pipeline_id = device
117 .global_from_reflector()
118 .global_wgpu_id_hub()
119 .create_render_pipeline_id();
120
121 device
122 .channel()
123 .0
124 .send(WebGPURequest::CreateRenderPipeline {
125 device_id: device.id().0,
126 render_pipeline_id,
127 descriptor,
128 async_sender,
129 })
130 .expect("Failed to create WebGPU render pipeline");
131
132 Ok(WebGPURenderPipeline(render_pipeline_id))
133 }
134}
135
136impl<D> GPURenderPipelineMethods<D> for GPURenderPipeline<D>
137where
138 D: Equivalence,
139 <D::Promise as PromiseHelpers<D>>::StackRoot: WebGPUPromise<D>,
140{
141 fn Label(&self) -> USVString {
143 self.label.borrow().clone()
144 }
145
146 fn SetLabel(&self, no_gc: &NoGC, value: USVString) {
148 *self.label.safe_borrow_mut(no_gc) = value;
149 }
150
151 fn GetBindGroupLayout(
153 &self,
154 cx: &mut JSContext,
155 index: u32,
156 ) -> Fallible<DomRoot<GPUBindGroupLayout<D>>> {
157 let id = self
158 .global_from_reflector()
159 .global_wgpu_id_hub()
160 .create_bind_group_layout_id();
161
162 if let Err(e) = self
163 .droppable
164 .channel
165 .0
166 .send(WebGPURequest::RenderGetBindGroupLayout {
167 device_id: self.device.id().0,
168 pipeline_id: self.id().0,
169 index,
170 id,
171 })
172 {
173 warn!("Failed to send WebGPURequest::RenderGetBindGroupLayout {e:?}");
174 }
175
176 Ok(GPUBindGroupLayout::new(
177 cx,
178 &*self.global_from_reflector(),
179 self.droppable.channel.clone(),
180 WebGPUBindGroupLayout(id),
181 USVString::default(),
182 ))
183 }
184}