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