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 #[allow(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 #[allow(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 }
123}
124
125impl GPUTexture {
126 pub(crate) fn id(&self) -> WebGPUTexture {
127 self.texture
128 }
129
130 pub(crate) fn create(
132 device: &GPUDevice,
133 descriptor: &GPUTextureDescriptor,
134 can_gc: CanGc,
135 ) -> Fallible<DomRoot<GPUTexture>> {
136 let (desc, size) = convert_texture_descriptor(descriptor, device)?;
137
138 let texture_id = device.global().wgpu_id_hub().create_texture_id();
139
140 device
141 .channel()
142 .0
143 .send(WebGPURequest::CreateTexture {
144 device_id: device.id().0,
145 texture_id,
146 descriptor: desc,
147 })
148 .expect("Failed to create WebGPU Texture");
149
150 let texture = WebGPUTexture(texture_id);
151
152 Ok(GPUTexture::new(
153 &device.global(),
154 texture,
155 device,
156 device.channel().clone(),
157 size,
158 descriptor.mipLevelCount,
159 descriptor.sampleCount,
160 descriptor.dimension,
161 descriptor.format,
162 descriptor.usage,
163 descriptor.parent.label.clone(),
164 can_gc,
165 ))
166 }
167}
168
169impl GPUTextureMethods<crate::DomTypeHolder> for GPUTexture {
170 fn Label(&self) -> USVString {
172 self.label.borrow().clone()
173 }
174
175 fn SetLabel(&self, value: USVString) {
177 *self.label.borrow_mut() = value;
178 }
179
180 fn CreateView(
182 &self,
183 descriptor: &GPUTextureViewDescriptor,
184 ) -> Fallible<DomRoot<GPUTextureView>> {
185 let desc = if !matches!(descriptor.mipLevelCount, Some(0)) &&
186 !matches!(descriptor.arrayLayerCount, Some(0))
187 {
188 Some(resource::TextureViewDescriptor {
189 label: (&descriptor.parent).convert(),
190 format: descriptor
191 .format
192 .map(|f| self.device.validate_texture_format_required_features(&f))
193 .transpose()?,
194 dimension: descriptor.dimension.map(|dimension| dimension.convert()),
195 usage: Some(wgpu_types::TextureUsages::from_bits_retain(
196 descriptor.usage,
197 )),
198 range: wgpu_types::ImageSubresourceRange {
199 aspect: match descriptor.aspect {
200 GPUTextureAspect::All => wgpu_types::TextureAspect::All,
201 GPUTextureAspect::Stencil_only => wgpu_types::TextureAspect::StencilOnly,
202 GPUTextureAspect::Depth_only => wgpu_types::TextureAspect::DepthOnly,
203 },
204 base_mip_level: descriptor.baseMipLevel,
205 mip_level_count: descriptor.mipLevelCount,
206 base_array_layer: descriptor.baseArrayLayer,
207 array_layer_count: descriptor.arrayLayerCount,
208 },
209 })
210 } else {
211 self.device
212 .dispatch_error(webgpu_traits::Error::Validation(String::from(
213 "arrayLayerCount and mipLevelCount cannot be 0",
214 )));
215 None
216 };
217
218 let texture_view_id = self.global().wgpu_id_hub().create_texture_view_id();
219
220 self.channel
221 .0
222 .send(WebGPURequest::CreateTextureView {
223 texture_id: self.texture.0,
224 texture_view_id,
225 device_id: self.device.id().0,
226 descriptor: desc,
227 })
228 .expect("Failed to create WebGPU texture view");
229
230 let texture_view = WebGPUTextureView(texture_view_id);
231
232 Ok(GPUTextureView::new(
233 &self.global(),
234 self.channel.clone(),
235 texture_view,
236 self,
237 descriptor.parent.label.clone(),
238 CanGc::note(),
239 ))
240 }
241
242 fn Destroy(&self) {
244 if let Err(e) = self
245 .channel
246 .0
247 .send(WebGPURequest::DestroyTexture(self.texture.0))
248 {
249 warn!(
250 "Failed to send WebGPURequest::DestroyTexture({:?}) ({})",
251 self.texture.0, e
252 );
253 };
254 }
255
256 fn Width(&self) -> u32 {
258 self.texture_size.width
259 }
260
261 fn Height(&self) -> u32 {
263 self.texture_size.height
264 }
265
266 fn DepthOrArrayLayers(&self) -> u32 {
268 self.texture_size.depth_or_array_layers
269 }
270
271 fn MipLevelCount(&self) -> u32 {
273 self.mip_level_count
274 }
275
276 fn SampleCount(&self) -> u32 {
278 self.sample_count
279 }
280
281 fn Dimension(&self) -> GPUTextureDimension {
283 self.dimension
284 }
285
286 fn Format(&self) -> GPUTextureFormat {
288 self.format
289 }
290
291 fn Usage(&self) -> u32 {
293 self.texture_usage
294 }
295}