wgpu_mipmap/backends/
copy.rs1use crate::backends::RenderMipmapGenerator;
2use crate::core::*;
3use crate::util::get_mip_extent;
4
5pub struct CopyMipmapGenerator<'a> {
7 generator: &'a RenderMipmapGenerator,
8}
9
10impl<'a> CopyMipmapGenerator<'a> {
11 pub fn new(generator: &'a RenderMipmapGenerator) -> Self {
15 Self { generator }
16 }
17
18 pub fn required_usage() -> wgpu::TextureUsage {
21 wgpu::TextureUsage::SAMPLED | wgpu::TextureUsage::COPY_DST
22 }
23}
24
25impl<'a> MipmapGenerator for CopyMipmapGenerator<'a> {
26 fn generate(
27 &self,
28 device: &wgpu::Device,
29 encoder: &mut wgpu::CommandEncoder,
30 texture: &wgpu::Texture,
31 texture_descriptor: &wgpu::TextureDescriptor,
32 ) -> Result<(), Error> {
33 let tmp_descriptor = wgpu::TextureDescriptor {
38 label: None,
39 size: get_mip_extent(&texture_descriptor.size, 1),
40 mip_level_count: texture_descriptor.mip_level_count - 1,
41 sample_count: texture_descriptor.sample_count,
42 dimension: texture_descriptor.dimension,
43 format: texture_descriptor.format,
44 usage: RenderMipmapGenerator::required_usage() | wgpu::TextureUsage::COPY_SRC,
45 };
46 let tmp_texture = device.create_texture(&tmp_descriptor);
47 self.generator.generate_src_dst(
48 device,
49 encoder,
50 &texture,
51 &tmp_texture,
52 texture_descriptor,
53 &tmp_descriptor,
54 1,
55 )?;
56 let mip_count = tmp_descriptor.mip_level_count;
57 for i in 0..mip_count {
58 encoder.copy_texture_to_texture(
59 wgpu::TextureCopyView {
60 texture: &tmp_texture,
61 mip_level: i,
62 origin: wgpu::Origin3d::default(),
63 },
64 wgpu::TextureCopyView {
65 texture: &texture,
66 mip_level: i + 1,
67 origin: wgpu::Origin3d::default(),
68 },
69 get_mip_extent(&tmp_descriptor.size, i),
70 );
71 }
72 Ok(())
73 }
74}
75
76#[cfg(test)]
77mod tests {
78 use super::*;
79 use crate::util::*;
80
81 fn init() {
82 let _ = env_logger::builder().is_test(true).try_init();
83 }
84
85 #[allow(dead_code)]
86 async fn generate_and_copy_to_cpu_render_slow(
87 buffer: &[u8],
88 texture_descriptor: &wgpu::TextureDescriptor<'_>,
89 ) -> Result<Vec<MipBuffer>, Error> {
90 let (_instance, _adaptor, device, queue) = wgpu_setup().await;
91
92 let generator = crate::backends::RenderMipmapGenerator::new_with_format_hints(
93 &device,
94 &[texture_descriptor.format],
95 );
96 let fallback = CopyMipmapGenerator::new(&generator);
97 Ok(
98 generate_and_copy_to_cpu(&device, &queue, &fallback, buffer, texture_descriptor)
99 .await?,
100 )
101 }
102
103 async fn generate_test(texture_descriptor: &wgpu::TextureDescriptor<'_>) -> Result<(), Error> {
104 let (_instance, _adapter, device, _queue) = wgpu_setup().await;
105 let render = crate::backends::RenderMipmapGenerator::new_with_format_hints(
106 &device,
107 &[texture_descriptor.format],
108 );
109 let generator = CopyMipmapGenerator::new(&render);
110 let texture = device.create_texture(&texture_descriptor);
111 let mut encoder = device.create_command_encoder(&Default::default());
112 generator.generate(&device, &mut encoder, &texture, &texture_descriptor)
113 }
114
115 #[test]
116 fn sanity_check() {
117 init();
118 let size = 511;
120 let mip_level_count = 1 + (size as f32).log2() as u32;
121 let format = wgpu::TextureFormat::R8Unorm;
123 let texture_extent = wgpu::Extent3d {
124 width: size,
125 height: size,
126 depth: 1,
127 };
128 let texture_descriptor = wgpu::TextureDescriptor {
129 size: texture_extent,
130 mip_level_count,
131 format,
132 sample_count: 1,
133 dimension: wgpu::TextureDimension::D2,
134 usage: CopyMipmapGenerator::required_usage(),
135 label: None,
136 };
137 futures::executor::block_on((|| async {
138 let res = generate_test(&texture_descriptor).await;
139 assert!(res.is_ok());
140 })());
141 }
142
143 #[test]
144 fn unsupported_format() {
145 init();
146 let size = 511;
148 let mip_level_count = 1 + (size as f32).log2() as u32;
149 let format = wgpu::TextureFormat::R8Unorm;
151 let texture_extent = wgpu::Extent3d {
152 width: size,
153 height: size,
154 depth: 1,
155 };
156 let texture_descriptor = wgpu::TextureDescriptor {
157 size: texture_extent,
158 mip_level_count,
159 format,
160 sample_count: 1,
161 dimension: wgpu::TextureDimension::D2,
162 usage: wgpu::TextureUsage::empty(),
163 label: None,
164 };
165 futures::executor::block_on((|| async {
166 let res = generate_test(&texture_descriptor).await;
167 assert!(res.is_err());
168 assert!(res.err() == Some(Error::UnsupportedUsage(texture_descriptor.usage)));
169 })());
170 }
171}