1use std::string::String;
6
7use dom_struct::dom_struct;
8use script_bindings::cell::DomRefCell;
9use script_bindings::reflector::{Reflector, reflect_dom_object};
10use webgpu_traits::{WebGPU, WebGPURequest, WebGPUTexture, WebGPUTextureView};
11use wgpu_core::resource;
12
13use super::gpuconvert::convert_texture_descriptor;
14use crate::conversions::Convert;
15use crate::dom::bindings::codegen::Bindings::WebGPUBinding::{
16 GPUTextureAspect, GPUTextureDescriptor, GPUTextureDimension, GPUTextureFormat,
17 GPUTextureMethods, GPUTextureViewDescriptor,
18};
19use crate::dom::bindings::error::Fallible;
20use crate::dom::bindings::reflector::DomGlobal;
21use crate::dom::bindings::root::{Dom, DomRoot};
22use crate::dom::bindings::str::USVString;
23use crate::dom::globalscope::GlobalScope;
24use crate::dom::webgpu::gpudevice::GPUDevice;
25use crate::dom::webgpu::gputextureview::GPUTextureView;
26use crate::script_runtime::CanGc;
27
28#[derive(JSTraceable, MallocSizeOf)]
29struct DroppableGPUTexture {
30 #[no_trace]
31 channel: WebGPU,
32 #[no_trace]
33 texture: WebGPUTexture,
34}
35
36impl Drop for DroppableGPUTexture {
37 fn drop(&mut self) {
38 if let Err(e) = self
39 .channel
40 .0
41 .send(WebGPURequest::DropTexture(self.texture.0))
42 {
43 warn!(
44 "Failed to send WebGPURequest::DropTexture({:?}) ({})",
45 self.texture.0, e
46 );
47 };
48 }
49}
50
51#[dom_struct]
52pub(crate) struct GPUTexture {
53 reflector_: Reflector,
54 label: DomRefCell<USVString>,
55 device: Dom<GPUDevice>,
56 #[no_trace]
57 #[ignore_malloc_size_of = "External type"]
58 texture_size: wgpu_types::Extent3d,
59 mip_level_count: u32,
60 sample_count: u32,
61 dimension: GPUTextureDimension,
62 format: GPUTextureFormat,
63 texture_usage: u32,
64 droppable: DroppableGPUTexture,
65}
66
67impl GPUTexture {
68 #[expect(clippy::too_many_arguments)]
69 fn new_inherited(
70 texture: WebGPUTexture,
71 device: &GPUDevice,
72 channel: WebGPU,
73 texture_size: wgpu_types::Extent3d,
74 mip_level_count: u32,
75 sample_count: u32,
76 dimension: GPUTextureDimension,
77 format: GPUTextureFormat,
78 texture_usage: u32,
79 label: USVString,
80 ) -> Self {
81 Self {
82 reflector_: Reflector::new(),
83 label: DomRefCell::new(label),
84 device: Dom::from_ref(device),
85 texture_size,
86 mip_level_count,
87 sample_count,
88 dimension,
89 format,
90 texture_usage,
91 droppable: DroppableGPUTexture { channel, texture },
92 }
93 }
94
95 #[expect(clippy::too_many_arguments)]
96 pub(crate) fn new(
97 global: &GlobalScope,
98 texture: WebGPUTexture,
99 device: &GPUDevice,
100 channel: WebGPU,
101 texture_size: wgpu_types::Extent3d,
102 mip_level_count: u32,
103 sample_count: u32,
104 dimension: GPUTextureDimension,
105 format: GPUTextureFormat,
106 texture_usage: u32,
107 label: USVString,
108 can_gc: CanGc,
109 ) -> DomRoot<Self> {
110 reflect_dom_object(
111 Box::new(GPUTexture::new_inherited(
112 texture,
113 device,
114 channel,
115 texture_size,
116 mip_level_count,
117 sample_count,
118 dimension,
119 format,
120 texture_usage,
121 label,
122 )),
123 global,
124 can_gc,
125 )
126 }
127}
128
129impl GPUTexture {
130 pub(crate) fn id(&self) -> WebGPUTexture {
131 self.droppable.texture
132 }
133
134 pub(crate) fn create(
136 device: &GPUDevice,
137 descriptor: &GPUTextureDescriptor,
138 can_gc: CanGc,
139 ) -> Fallible<DomRoot<GPUTexture>> {
140 let (desc, size) = convert_texture_descriptor(descriptor, device)?;
141
142 let texture_id = device.global().wgpu_id_hub().create_texture_id();
143
144 device
145 .channel()
146 .0
147 .send(WebGPURequest::CreateTexture {
148 device_id: device.id().0,
149 texture_id,
150 descriptor: desc,
151 })
152 .expect("Failed to create WebGPU Texture");
153
154 let texture = WebGPUTexture(texture_id);
155
156 Ok(GPUTexture::new(
157 &device.global(),
158 texture,
159 device,
160 device.channel(),
161 size,
162 descriptor.mipLevelCount,
163 descriptor.sampleCount,
164 descriptor.dimension,
165 descriptor.format,
166 descriptor.usage,
167 descriptor.parent.label.clone(),
168 can_gc,
169 ))
170 }
171}
172
173impl GPUTextureMethods<crate::DomTypeHolder> for GPUTexture {
174 fn Label(&self) -> USVString {
176 self.label.borrow().clone()
177 }
178
179 fn SetLabel(&self, value: USVString) {
181 *self.label.borrow_mut() = value;
182 }
183
184 fn CreateView(
186 &self,
187 descriptor: &GPUTextureViewDescriptor,
188 ) -> Fallible<DomRoot<GPUTextureView>> {
189 let desc = if !matches!(descriptor.mipLevelCount, Some(0)) &&
190 !matches!(descriptor.arrayLayerCount, Some(0))
191 {
192 Some(resource::TextureViewDescriptor {
193 label: (&descriptor.parent).convert(),
194 format: descriptor
195 .format
196 .map(|f| self.device.validate_texture_format_required_features(&f))
197 .transpose()?,
198 dimension: descriptor.dimension.map(|dimension| dimension.convert()),
199 usage: Some(wgpu_types::TextureUsages::from_bits_retain(
200 descriptor.usage,
201 )),
202 range: wgpu_types::ImageSubresourceRange {
203 aspect: match descriptor.aspect {
204 GPUTextureAspect::All => wgpu_types::TextureAspect::All,
205 GPUTextureAspect::Stencil_only => wgpu_types::TextureAspect::StencilOnly,
206 GPUTextureAspect::Depth_only => wgpu_types::TextureAspect::DepthOnly,
207 },
208 base_mip_level: descriptor.baseMipLevel,
209 mip_level_count: descriptor.mipLevelCount,
210 base_array_layer: descriptor.baseArrayLayer,
211 array_layer_count: descriptor.arrayLayerCount,
212 },
213 })
214 } else {
215 self.device
216 .dispatch_error(webgpu_traits::Error::Validation(String::from(
217 "arrayLayerCount and mipLevelCount cannot be 0",
218 )));
219 None
220 };
221
222 let texture_view_id = self.global().wgpu_id_hub().create_texture_view_id();
223
224 self.droppable
225 .channel
226 .0
227 .send(WebGPURequest::CreateTextureView {
228 texture_id: self.id().0,
229 texture_view_id,
230 device_id: self.device.id().0,
231 descriptor: desc,
232 })
233 .expect("Failed to create WebGPU texture view");
234
235 let texture_view = WebGPUTextureView(texture_view_id);
236
237 Ok(GPUTextureView::new(
238 &self.global(),
239 self.droppable.channel.clone(),
240 texture_view,
241 self,
242 descriptor.parent.label.clone(),
243 CanGc::deprecated_note(),
244 ))
245 }
246
247 fn Destroy(&self) {
249 if let Err(e) = self
250 .droppable
251 .channel
252 .0
253 .send(WebGPURequest::DestroyTexture(self.id().0))
254 {
255 warn!(
256 "Failed to send WebGPURequest::DestroyTexture({:?}) ({})",
257 self.id().0,
258 e
259 );
260 };
261 }
262
263 fn Width(&self) -> u32 {
265 self.texture_size.width
266 }
267
268 fn Height(&self) -> u32 {
270 self.texture_size.height
271 }
272
273 fn DepthOrArrayLayers(&self) -> u32 {
275 self.texture_size.depth_or_array_layers
276 }
277
278 fn MipLevelCount(&self) -> u32 {
280 self.mip_level_count
281 }
282
283 fn SampleCount(&self) -> u32 {
285 self.sample_count
286 }
287
288 fn Dimension(&self) -> GPUTextureDimension {
290 self.dimension
291 }
292
293 fn Format(&self) -> GPUTextureFormat {
295 self.format
296 }
297
298 fn Usage(&self) -> u32 {
300 self.texture_usage
301 }
302}