script_webgpu/
gpucomputepipeline.rs1use dom_struct::dom_struct;
6use js::context::{JSContext, NoGC};
7use log::warn;
8use malloc_size_of_derive::MallocSizeOf;
9use script_bindings::DomTypes;
10use script_bindings::cell::DomRefCell;
11use script_bindings::codegen::GenericBindings::WebGPUBinding::{
12 GPUComputePipelineDescriptor, GPUComputePipelineMethods, GPUComputePipelineWrap,
13};
14use script_bindings::interfaces::PromiseHelpers;
15use script_bindings::reflector::{DomGlobalGeneric, Reflector, reflect_dom_object_with_wrap};
16use servo_base::generic_channel::GenericCallback;
17use webgpu_traits::{
18 ComputePipelineDescriptor, WebGPU, WebGPUBindGroupLayout, WebGPUComputePipeline,
19 WebGPUComputePipelineResponse, WebGPURequest,
20};
21
22use crate::JSTraceable;
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::gpuconvert::WebGPUConvert;
28use crate::traits::{Equivalence, WebGPUGlobalTrait, WebGPUPromise};
29
30#[derive(JSTraceable, MallocSizeOf)]
31struct DroppableGPUComputePipeline {
32 #[no_trace]
33 channel: WebGPU,
34 #[no_trace]
35 compute_pipeline: WebGPUComputePipeline,
36}
37
38impl Drop for DroppableGPUComputePipeline {
39 fn drop(&mut self) {
40 if let Err(e) = self
41 .channel
42 .0
43 .send(WebGPURequest::DropComputePipeline(self.compute_pipeline.0))
44 {
45 warn!(
46 "Failed to send WebGPURequest::DropComputePipeline({:?}) ({})",
47 self.compute_pipeline.0, e
48 );
49 };
50 }
51}
52
53#[dom_struct]
54pub struct GPUComputePipeline<D: DomTypes> {
55 reflector_: Reflector,
56 label: DomRefCell<USVString>,
57 device: Dom<D::GPUDevice>,
58 droppable: DroppableGPUComputePipeline,
59}
60
61impl<D> GPUComputePipeline<D>
62where
63 D: Equivalence,
64{
65 fn new_inherited(
66 compute_pipeline: WebGPUComputePipeline,
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: DroppableGPUComputePipeline {
75 channel: device.channel(),
76 compute_pipeline,
77 },
78 }
79 }
80
81 pub fn new(
82 cx: &mut JSContext,
83 global: &D::GlobalScope,
84 compute_pipeline: WebGPUComputePipeline,
85 label: USVString,
86 device: &D::GPUDevice,
87 ) -> DomRoot<Self> {
88 reflect_dom_object_with_wrap::<D, _, _>(
89 cx,
90 Box::new(GPUComputePipeline::new_inherited(
91 compute_pipeline,
92 label,
93 device,
94 )),
95 global,
96 GPUComputePipelineWrap::<D>,
97 )
98 }
99}
100
101impl<D> GPUComputePipeline<D>
102where
103 D: Equivalence,
104 <D::Promise as PromiseHelpers<D>>::StackRoot: WebGPUPromise<D>,
105{
106 pub(crate) fn id(&self) -> &WebGPUComputePipeline {
107 &self.droppable.compute_pipeline
108 }
109
110 pub(crate) fn create(
112 device: &D::GPUDevice,
113 descriptor: &GPUComputePipelineDescriptor<D>,
114 async_sender: Option<GenericCallback<WebGPUComputePipelineResponse>>,
115 ) -> WebGPUComputePipeline {
116 let compute_pipeline_id = device
117 .global_from_reflector()
118 .global_wgpu_id_hub()
119 .create_compute_pipeline_id();
120
121 let pipeline_layout = device.get_pipeline_layout_data(&descriptor.parent.layout);
122
123 let desc = ComputePipelineDescriptor {
124 label: (&descriptor.parent.parent).convert(),
125 layout: pipeline_layout.explicit(),
126 stage: (&descriptor.compute).convert(),
127 cache: None,
128 };
129
130 device
131 .channel()
132 .0
133 .send(WebGPURequest::CreateComputePipeline {
134 device_id: device.id().0,
135 compute_pipeline_id,
136 descriptor: desc,
137 async_sender,
138 })
139 .expect("Failed to create WebGPU ComputePipeline");
140
141 WebGPUComputePipeline(compute_pipeline_id)
142 }
143}
144
145impl<D> GPUComputePipelineMethods<D> for GPUComputePipeline<D>
146where
147 D: Equivalence,
148 <D::Promise as PromiseHelpers<D>>::StackRoot: WebGPUPromise<D>,
149{
150 fn Label(&self) -> USVString {
152 self.label.borrow().clone()
153 }
154
155 fn SetLabel(&self, no_gc: &NoGC, value: USVString) {
157 *self.label.safe_borrow_mut(no_gc) = value;
158 }
159
160 fn GetBindGroupLayout(
162 &self,
163 cx: &mut JSContext,
164 index: u32,
165 ) -> Fallible<DomRoot<GPUBindGroupLayout<D>>> {
166 let id = self
167 .global_from_reflector()
168 .global_wgpu_id_hub()
169 .create_bind_group_layout_id();
170
171 if let Err(e) = self
172 .droppable
173 .channel
174 .0
175 .send(WebGPURequest::ComputeGetBindGroupLayout {
176 device_id: self.device.id().0,
177 pipeline_id: self.id().0,
178 index,
179 id,
180 })
181 {
182 warn!("Failed to send WebGPURequest::ComputeGetBindGroupLayout {e:?}");
183 }
184
185 Ok(GPUBindGroupLayout::new(
186 cx,
187 &*self.global_from_reflector(),
188 self.droppable.channel.clone(),
189 WebGPUBindGroupLayout(id),
190 USVString::default(),
191 ))
192 }
193}