1use std::borrow::Cow;
6
7use dom_struct::dom_struct;
8use js::context::{JSContext, NoGC};
9use jstraceable_derive::JSTraceable;
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 GPUBindGroupDescriptor, GPUBindGroupMethods, GPUBindGroupWrap,
16};
17use script_bindings::interfaces::PromiseHelpers;
18use script_bindings::reflector::{DomGlobalGeneric, Reflector, reflect_dom_object_with_wrap};
19use webgpu_traits::{WebGPU, WebGPUBindGroup, WebGPUDevice, WebGPURequest};
20use wgpu_core::binding_model::BindGroupDescriptor;
21
22use crate::dom::bindings::root::{Dom, DomRoot};
23use crate::dom::bindings::str::USVString;
24use crate::gpubindgrouplayout::GPUBindGroupLayout;
25use crate::gpubuffer::GPUBuffer;
26use crate::gpuconvert::{WebGPUConvert, convert_bind_group_entry};
27use crate::traits::{
28 GPUDeviceTrait, GPUExternalTextureTrait, GPUSamplerTrait, GPUTextureTrait, GPUTextureViewTrait,
29 WebGPUGlobalTrait,
30};
31
32#[derive(JSTraceable, MallocSizeOf)]
33struct DroppableGPUBindGroup {
34 #[no_trace]
35 channel: WebGPU,
36 #[no_trace]
37 bind_group: WebGPUBindGroup,
38}
39
40impl Drop for DroppableGPUBindGroup {
41 fn drop(&mut self) {
42 if let Err(e) = self
43 .channel
44 .0
45 .send(WebGPURequest::DropBindGroup(self.bind_group.0))
46 {
47 warn!(
48 "Failed to send WebGPURequest::DropBindGroup({:?}) ({})",
49 self.bind_group.0, e
50 );
51 };
52 }
53}
54
55#[dom_struct]
56pub struct GPUBindGroup<D: DomTypes> {
57 reflector_: Reflector,
58 label: DomRefCell<USVString>,
59 #[no_trace]
60 device: WebGPUDevice,
61 layout: Dom<GPUBindGroupLayout<D>>,
62 droppable: DroppableGPUBindGroup,
63}
64
65impl<D> GPUBindGroup<D>
66where
67 D: DomTypes<GPUBindGroup = GPUBindGroup<D>>,
68{
69 fn new_inherited(
70 channel: WebGPU,
71 bind_group: WebGPUBindGroup,
72 device: WebGPUDevice,
73 layout: &GPUBindGroupLayout<D>,
74 label: USVString,
75 ) -> Self {
76 Self {
77 reflector_: Reflector::new(),
78 label: DomRefCell::new(label),
79 device,
80 layout: Dom::from_ref(layout),
81 droppable: DroppableGPUBindGroup {
82 channel,
83 bind_group,
84 },
85 }
86 }
87
88 pub(crate) fn new(
89 cx: &mut JSContext,
90 global: &D::GlobalScope,
91 channel: WebGPU,
92 bind_group: WebGPUBindGroup,
93 device: WebGPUDevice,
94 layout: &GPUBindGroupLayout<D>,
95 label: USVString,
96 ) -> DomRoot<Self> {
97 reflect_dom_object_with_wrap::<D, _, _>(
98 Box::new(GPUBindGroup::new_inherited(
99 channel, bind_group, device, layout, label,
100 )),
101 global,
102 cx,
103 GPUBindGroupWrap::<D>,
104 )
105 }
106}
107
108impl<D> GPUBindGroup<D>
109where
110 D: DomTypes<
111 GPUBuffer = GPUBuffer<D>,
112 GPUBindGroup = GPUBindGroup<D>,
113 GPUBindGroupLayout = GPUBindGroupLayout<D>,
114 >,
115 D::GPUDevice: DomGlobalGeneric<D> + GPUDeviceTrait<D>,
116 D::GlobalScope: WebGPUGlobalTrait,
117 D::GPUExternalTexture: GPUExternalTextureTrait,
118 D::GPUSampler: GPUSamplerTrait,
119 D::GPUTexture: GPUTextureTrait,
120 D::GPUTextureView: GPUTextureViewTrait,
121 D::Promise: PromiseHelpers<D>,
122{
123 pub fn id(&self) -> &WebGPUBindGroup {
124 &self.droppable.bind_group
125 }
126
127 pub fn create(
129 cx: &mut JSContext,
130 device: &D::GPUDevice,
131 descriptor: &GPUBindGroupDescriptor<D>,
132 ) -> DomRoot<GPUBindGroup<D>> {
133 let entries = descriptor
134 .entries
135 .iter()
136 .map(|bind| convert_bind_group_entry(cx, bind))
137 .collect::<Vec<_>>();
138
139 let desc = BindGroupDescriptor {
140 label: (&descriptor.parent).convert(),
141 layout: descriptor.layout.id().0,
142 entries: Cow::Owned(entries),
143 };
144
145 let bind_group_id = <D::GPUDevice as DomGlobalGeneric<D>>::global_from_reflector(device)
146 .global_wgpu_id_hub()
147 .create_bind_group_id();
148 device
149 .channel()
150 .0
151 .send(WebGPURequest::CreateBindGroup {
152 device_id: device.id().0,
153 bind_group_id,
154 descriptor: desc,
155 })
156 .expect("Failed to create WebGPU BindGroup");
157
158 let bind_group = WebGPUBindGroup(bind_group_id);
159
160 let global = <D::GPUDevice as DomGlobalGeneric<D>>::global_from_reflector(device);
161 GPUBindGroup::new(
162 cx,
163 &*global,
164 device.channel(),
165 bind_group,
166 device.id(),
167 &descriptor.layout,
168 descriptor.parent.label.clone(),
169 )
170 }
171}
172
173impl<D: DomTypes> GPUBindGroupMethods<D> for GPUBindGroup<D> {
174 fn Label(&self) -> USVString {
176 self.label.borrow().clone()
177 }
178
179 fn SetLabel(&self, no_gc: &NoGC, value: USVString) {
181 *self.label.safe_borrow_mut(no_gc) = value;
182 }
183}