1mod view;
2pub use view::*;
3
4mod sampler;
5pub use sampler::*;
6
7mod builder;
8pub use builder::*;
9
10use crate::Gpu;
11
12pub use wgpu::TextureFormat;
14
15pub trait TextureFormatExt {
16 fn target(&self) -> wgpu::ColorTargetState;
17}
18impl TextureFormatExt for TextureFormat {
19 fn target(&self) -> wgpu::ColorTargetState {
20 wgpu::ColorTargetState {
21 format: *self,
22 blend: None,
23 write_mask: wgpu::ColorWrites::ALL,
24 }
25 }
26}
27
28pub struct Texture<D>
29where
30 D: TextureDimensions,
31{
32 pub(crate) gpu: Gpu,
33 inner: wgpu::Texture,
34 pub view: wgpu::TextureView,
35 pub format: wgpu::TextureFormat,
36 pub size: D,
37 pub usage: wgpu::TextureUsages,
38}
39impl<D> std::ops::Deref for Texture<D>
40where
41 D: TextureDimensions,
42{
43 type Target = wgpu::Texture;
44
45 fn deref(&self) -> &Self::Target {
46 &self.inner
47 }
48}
49impl<D> std::ops::DerefMut for Texture<D>
50where
51 D: TextureDimensions,
52{
53 fn deref_mut(&mut self) -> &mut Self::Target {
54 &mut self.inner
55 }
56}
57
58impl<D> Texture<D>
59where
60 D: crate::TextureDimensions,
61{
62 pub fn resize(&mut self, size: D) {
78 let new_texture = self.gpu.create_texture(&wgpu::TextureDescriptor {
79 label: None,
81 size: size.as_extent(),
82 mip_level_count: 1,
84 sample_count: 1,
85 dimension: size.dim(),
86 format: self.format,
87 usage: self.usage,
88 });
89
90 let view = new_texture.create_view(&Default::default());
92
93 self.inner = new_texture;
94 self.size = size;
95 self.view = view;
96 }
97
98 pub fn resize_with_copy(&mut self, size: D) {
100 let new_usage = self.usage | wgpu::TextureUsages::COPY_DST;
101
102 let new_texture = self.gpu.create_texture(&wgpu::TextureDescriptor {
103 label: None,
105 size: size.as_extent(),
106 mip_level_count: 1,
108 sample_count: 1,
109 dimension: size.dim(),
110 format: self.format,
111 usage: new_usage,
112 });
113
114 match self.format {
116 wgpu::TextureFormat::Depth32Float
117 | wgpu::TextureFormat::Depth24Plus
118 | wgpu::TextureFormat::Depth24PlusStencil8 => {}
119 _ => {
120 let mut enc = self.gpu.create_command_encoder("Texture resize encoder");
121 enc.copy_texture_to_texture(
122 self.inner.as_image_copy(),
123 new_texture.as_image_copy(),
124 self.size.as_extent(),
125 );
126 self.gpu.queue.submit([enc.finish()]);
127 }
128 }
129
130 let view = new_texture.create_view(&Default::default());
132
133 self.inner = new_texture;
134 self.size = size;
135 self.usage = new_usage;
136 self.view = view;
137 }
138
139 pub fn write<T>(&self, size: D, data: &[T])
140 where
141 T: bytemuck::Pod,
142 {
143 self.write_block(D::ZEROED, size, data)
144 }
145
146 pub fn write_block<T>(&self, texel: D, size: D, data: &[T])
147 where
148 T: bytemuck::Pod,
149 {
150 let data_bytes = bytemuck::cast_slice::<_, u8>(data);
151
152 self.gpu.queue.write_texture(
153 wgpu::ImageCopyTextureBase {
154 texture: &self.inner,
155 mip_level: 0,
156 origin: texel.as_origin(),
157 aspect: wgpu::TextureAspect::All,
158 },
159 data_bytes,
160 wgpu::ImageDataLayout {
161 offset: 0,
163 bytes_per_row: std::num::NonZeroU32::new(
164 size.width() * self.format.describe().block_size as u32,
165 ),
166 rows_per_image: None,
167 },
168 size.as_extent(),
169 )
170 }
171
172 #[allow(unreachable_code)]
174 pub fn read_immediately(&self) -> Result<wgpu::util::DownloadBuffer, wgpu::BufferAsyncError> {
175 let format = self.format.describe();
176 let texel_count = self.size.width() * self.size.height() * self.size.depth();
177 let read_size = texel_count * format.block_size as u32
178 / (format.block_dimensions.0 as u32 * format.block_dimensions.1 as u32);
179 println!("texel_count: {}, read_size: {}", texel_count, read_size);
180 let staging_buf = self
181 .gpu
182 .new_buffer("texture read staging buffer")
183 .allow_copy_to()
184 .allow_map_read()
185 .create_uninit(read_size as _);
186
187 let buffer_dimensions = BufferDimensions::new(self.size.width(), self.size.height());
188
189 let staging_copy = wgpu::ImageCopyBuffer {
190 buffer: &staging_buf,
191 layout: wgpu::ImageDataLayout {
192 offset: 0,
193 bytes_per_row: std::num::NonZeroU32::new(buffer_dimensions.padded_bytes_per_row),
194 rows_per_image: None,
195 },
196 };
197
198 let mut enc = self
199 .gpu
200 .create_command_encoder("texture read immediately enc");
201
202 enc.copy_texture_to_buffer(
203 self.inner.as_image_copy(),
204 staging_copy,
205 self.size.as_extent(),
206 );
207
208 self.gpu.queue.submit([enc.finish()]);
209
210 staging_buf.download_immediately()
211 }
212}
213
214pub type D1 = (u32,);
215pub type D2 = (u32, u32);
216pub type D3 = (u32, u32, u32);
217
218pub trait TextureDimensions: Copy {
219 const ZEROED: Self;
220 fn dim(&self) -> wgpu::TextureDimension;
221 fn as_extent(&self) -> wgpu::Extent3d;
222 fn as_origin(&self) -> wgpu::Origin3d;
223 fn width(&self) -> u32;
224 fn height(&self) -> u32;
225 fn depth(&self) -> u32;
226}
227
228impl TextureDimensions for (u32, u32, u32) {
229 const ZEROED: Self = (0, 0, 0);
230 fn dim(&self) -> wgpu::TextureDimension {
231 wgpu::TextureDimension::D3
232 }
233 fn as_extent(&self) -> wgpu::Extent3d {
234 wgpu::Extent3d {
235 width: self.0,
236 height: self.1,
237 depth_or_array_layers: self.2,
238 }
239 }
240 fn as_origin(&self) -> wgpu::Origin3d {
241 wgpu::Origin3d {
242 x: self.0,
243 y: self.1,
244 z: self.2,
245 }
246 }
247 fn width(&self) -> u32 {
248 self.0
249 }
250 fn height(&self) -> u32 {
251 self.1
252 }
253 fn depth(&self) -> u32 {
254 self.2
255 }
256}
257
258impl TextureDimensions for (u32, u32) {
259 const ZEROED: Self = (0, 0);
260 fn dim(&self) -> wgpu::TextureDimension {
261 wgpu::TextureDimension::D2
262 }
263 fn as_extent(&self) -> wgpu::Extent3d {
264 wgpu::Extent3d {
265 width: self.0,
266 height: self.1,
267 depth_or_array_layers: 1,
268 }
269 }
270 fn as_origin(&self) -> wgpu::Origin3d {
271 wgpu::Origin3d {
272 x: self.0,
273 y: self.1,
274 z: 0,
275 }
276 }
277 fn width(&self) -> u32 {
278 self.0
279 }
280 fn height(&self) -> u32 {
281 self.1
282 }
283 fn depth(&self) -> u32 {
284 1
285 }
286}
287
288impl TextureDimensions for (u32,) {
289 const ZEROED: Self = (0,);
290 fn dim(&self) -> wgpu::TextureDimension {
291 wgpu::TextureDimension::D1
292 }
293 fn as_extent(&self) -> wgpu::Extent3d {
294 wgpu::Extent3d {
295 width: self.0,
296 height: 1,
297 depth_or_array_layers: 1,
298 }
299 }
300 fn as_origin(&self) -> wgpu::Origin3d {
301 wgpu::Origin3d {
302 x: self.0,
303 y: 0,
304 z: 0,
305 }
306 }
307 fn width(&self) -> u32 {
308 self.0
309 }
310 fn height(&self) -> u32 {
311 1
312 }
313 fn depth(&self) -> u32 {
314 1
315 }
316}
317
318#[allow(unused)]
319struct BufferDimensions {
320 width: u32,
321 height: u32,
322 unpadded_bytes_per_row: u32,
323 padded_bytes_per_row: u32,
324}
325
326impl BufferDimensions {
327 fn new(width: u32, height: u32) -> Self {
328 let bytes_per_pixel = std::mem::size_of::<u32>();
329 let unpadded_bytes_per_row = width * bytes_per_pixel as u32;
330 let align = wgpu::COPY_BYTES_PER_ROW_ALIGNMENT;
331 let padded_bytes_per_row_padding = (align - unpadded_bytes_per_row % align) % align;
332 let padded_bytes_per_row = unpadded_bytes_per_row + padded_bytes_per_row_padding;
333 Self {
334 width,
335 height,
336 unpadded_bytes_per_row,
337 padded_bytes_per_row,
338 }
339 }
340}
341
342