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