script_webgpu/
gpupipelinelayout.rs1use std::borrow::Cow;
6use std::marker::PhantomData;
7
8use dom_struct::dom_struct;
9use js::context::{JSContext, NoGC};
10use log::warn;
11use malloc_size_of_derive::MallocSizeOf;
12use script_bindings::DomTypes;
13use script_bindings::cell::DomRefCell;
14use script_bindings::codegen::GenericBindings::WebGPUBinding::{
15 GPUPipelineLayoutDescriptor, GPUPipelineLayoutMethods, GPUPipelineLayoutWrap,
16};
17use script_bindings::reflector::{DomGlobalGeneric, Reflector, reflect_dom_object_with_wrap};
18use webgpu_traits::{WebGPU, WebGPUBindGroupLayout, WebGPUPipelineLayout, WebGPURequest};
19use wgpu_core::binding_model::PipelineLayoutDescriptor;
20
21use crate::JSTraceable;
22use crate::dom::bindings::root::DomRoot;
23use crate::dom::bindings::str::USVString;
24use crate::gpuconvert::WebGPUConvert;
25use crate::traits::{Equivalence, GPUDeviceTrait, WebGPUGlobalTrait};
26
27#[derive(MallocSizeOf)]
28struct DroppableGPUPipelineLayout {
29 channel: WebGPU,
30 pipeline_layout: WebGPUPipelineLayout,
31}
32
33impl Drop for DroppableGPUPipelineLayout {
34 fn drop(&mut self) {
35 if let Err(e) = self
36 .channel
37 .0
38 .send(WebGPURequest::DropPipelineLayout(self.pipeline_layout.0))
39 {
40 warn!(
41 "Failed to send DropPipelineLayout ({:?}) ({})",
42 self.pipeline_layout.0, e
43 );
44 }
45 }
46}
47
48#[dom_struct]
49pub struct GPUPipelineLayout<D: DomTypes> {
50 reflector_: Reflector,
51 label: DomRefCell<USVString>,
52 #[no_trace]
53 bind_group_layouts: Vec<WebGPUBindGroupLayout>,
54 #[no_trace]
55 droppable: DroppableGPUPipelineLayout,
56 #[no_trace = "PhantomData does not exist"]
57 phantom: PhantomData<D>,
58}
59
60impl<D> GPUPipelineLayout<D>
61where
62 D: Equivalence,
63{
64 fn new_inherited(
65 channel: WebGPU,
66 pipeline_layout: WebGPUPipelineLayout,
67 label: USVString,
68 bgls: Vec<WebGPUBindGroupLayout>,
69 ) -> Self {
70 Self {
71 reflector_: Reflector::new(),
72 label: DomRefCell::new(label),
73 bind_group_layouts: bgls,
74 droppable: DroppableGPUPipelineLayout {
75 channel,
76 pipeline_layout,
77 },
78 phantom: PhantomData,
79 }
80 }
81
82 pub(crate) fn new(
83 cx: &mut JSContext,
84 global: &D::GlobalScope,
85 channel: WebGPU,
86 pipeline_layout: WebGPUPipelineLayout,
87 label: USVString,
88 bgls: Vec<WebGPUBindGroupLayout>,
89 ) -> DomRoot<Self> {
90 reflect_dom_object_with_wrap::<D, _, _>(
91 Box::new(GPUPipelineLayout::new_inherited(
92 channel,
93 pipeline_layout,
94 label,
95 bgls,
96 )),
97 global,
98 cx,
99 GPUPipelineLayoutWrap::<D>,
100 )
101 }
102}
103
104impl<D> GPUPipelineLayout<D>
105where
106 D: Equivalence,
107 D::GPUDevice: GPUDeviceTrait<D>,
108 D::GlobalScope: WebGPUGlobalTrait,
109{
110 pub fn id(&self) -> WebGPUPipelineLayout {
111 self.droppable.pipeline_layout
112 }
113
114 #[expect(unused)]
115 fn bind_group_layouts(&self) -> Vec<WebGPUBindGroupLayout> {
116 self.bind_group_layouts.clone()
117 }
118
119 pub fn create(
121 cx: &mut JSContext,
122 device: &D::GPUDevice,
123 descriptor: &GPUPipelineLayoutDescriptor<D>,
124 ) -> DomRoot<GPUPipelineLayout<D>> {
125 let bgls = descriptor
126 .bindGroupLayouts
127 .iter()
128 .map(|each| each.id())
129 .collect::<Vec<_>>();
130
131 let desc = PipelineLayoutDescriptor {
132 label: (&descriptor.parent).convert(),
133 bind_group_layouts: Cow::Owned(bgls.iter().map(|l| Some(l.0)).collect::<Vec<_>>()),
135 immediate_size: 0,
136 };
137
138 let pipeline_layout_id = device
139 .global_from_reflector()
140 .global_wgpu_id_hub()
141 .create_pipeline_layout_id();
142 device
143 .channel()
144 .0
145 .send(WebGPURequest::CreatePipelineLayout {
146 device_id: device.id().0,
147 pipeline_layout_id,
148 descriptor: desc,
149 })
150 .expect("Failed to create WebGPU PipelineLayout");
151
152 let pipeline_layout = WebGPUPipelineLayout(pipeline_layout_id);
153 GPUPipelineLayout::new(
154 cx,
155 &*device.global_from_reflector(),
156 device.channel(),
157 pipeline_layout,
158 descriptor.parent.label.clone(),
159 bgls,
160 )
161 }
162}
163
164impl<D: DomTypes> GPUPipelineLayoutMethods<D> for GPUPipelineLayout<D> {
165 fn Label(&self) -> USVString {
167 self.label.borrow().clone()
168 }
169
170 fn SetLabel(&self, no_gc: &NoGC, value: USVString) {
172 *self.label.safe_borrow_mut(no_gc) = value;
173 }
174}