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