use crate::sprites::AtlasSegments;
use super::blit::Blit;
const LABEL: Option<&str> = Some("BLIT");
impl Blit {
pub fn generate_mipmaps(
&self,
encoder: &mut wgpu::CommandEncoder,
texture: &wgpu::Texture,
device: &wgpu::Device,
) {
assert_ne!(texture.dimension(), wgpu::TextureDimension::D3);
#[cfg(not(target_family = "wasm"))]
for layer in 0..texture.size().depth_or_array_layers {
self.generate_2d_mipmap(encoder, texture, device, layer);
}
#[cfg(target_family = "wasm")]
self.webgl_generate_2d_array_mipmap(encoder, texture, device);
}
#[allow(unused)]
fn webgl_generate_2d_array_mipmap(
&self,
encoder: &mut wgpu::CommandEncoder,
texture: &wgpu::Texture,
device: &wgpu::Device,
) {
let tmp_size = wgpu::Extent3d {
depth_or_array_layers: 1,
..texture.size()
};
let tmp_texture = device.create_texture(&wgpu::TextureDescriptor {
label: LABEL,
size: tmp_size,
mip_level_count: texture.mip_level_count(),
sample_count: 1,
dimension: wgpu::TextureDimension::D2,
format: texture.format(),
usage: wgpu::TextureUsages::COPY_SRC
| wgpu::TextureUsages::COPY_DST
| wgpu::TextureUsages::RENDER_ATTACHMENT
| wgpu::TextureUsages::TEXTURE_BINDING,
view_formats: &[],
});
for layer in 0..texture.size().depth_or_array_layers {
encoder.copy_texture_to_texture(
wgpu::TexelCopyTextureInfo {
mip_level: 0,
origin: wgpu::Origin3d {
x: 0,
y: 0,
z: layer,
},
..texture.as_image_copy()
},
tmp_texture.as_image_copy(),
tmp_size,
);
self.generate_2d_mipmap(encoder, &tmp_texture, device, 0);
for mip_level in 1..texture.mip_level_count() {
encoder.copy_texture_to_texture(
wgpu::TexelCopyTextureInfo {
mip_level,
..tmp_texture.as_image_copy()
},
wgpu::TexelCopyTextureInfo {
mip_level,
origin: wgpu::Origin3d {
x: 0,
y: 0,
z: layer,
},
..texture.as_image_copy()
},
tmp_size.mip_level_size(mip_level, wgpu::TextureDimension::D2),
);
}
}
}
fn generate_2d_mipmap(
&self,
encoder: &mut wgpu::CommandEncoder,
texture: &wgpu::Texture,
device: &wgpu::Device,
layer: u32,
) {
for to_mip_level in 1..texture.mip_level_count() {
let from = wgpu::TexelCopyTextureInfo {
texture,
mip_level: to_mip_level - 1,
origin: wgpu::Origin3d {
z: layer,
..wgpu::Origin3d::default()
},
aspect: wgpu::TextureAspect::All,
};
let to = wgpu::TexelCopyTextureInfo {
texture,
mip_level: to_mip_level,
origin: wgpu::Origin3d {
z: layer,
..wgpu::Origin3d::default()
},
aspect: wgpu::TextureAspect::All,
};
self.blit(from, to, encoder, device);
}
}
pub fn upload_mipmapped(
&self,
image: &image::RgbaImage,
device: &wgpu::Device,
queue: &wgpu::Queue,
) -> wgpu::Texture {
let width = image.width();
let height = image.height();
let size = wgpu::Extent3d {
width,
height,
depth_or_array_layers: 1,
};
let texture = device.create_texture(&wgpu::TextureDescriptor {
label: LABEL,
size: wgpu::Extent3d {
width,
height,
depth_or_array_layers: 1,
},
mip_level_count: size.max_mips(wgpu::TextureDimension::D2),
sample_count: 1,
dimension: wgpu::TextureDimension::D2,
format: wgpu::TextureFormat::Rgba8Unorm,
usage: wgpu::TextureUsages::TEXTURE_BINDING
| wgpu::TextureUsages::COPY_SRC
| wgpu::TextureUsages::COPY_DST
| wgpu::TextureUsages::RENDER_ATTACHMENT,
view_formats: &[],
});
queue.write_texture(
texture.as_image_copy(),
image.as_raw(),
wgpu::TexelCopyBufferLayout {
offset: 0,
bytes_per_row: Some(4 * width),
rows_per_image: Some(height),
},
wgpu::Extent3d {
width,
height,
depth_or_array_layers: 1,
},
);
let mut encoder =
device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: LABEL });
self.generate_mipmaps(&mut encoder, &texture, device);
queue.submit([encoder.finish()]);
texture
}
pub fn upload_mipmapped_atlas<T: AtlasSegments>(
&self,
atlas: &image::RgbaImage,
device: &wgpu::Device,
queue: &wgpu::Queue,
) -> Vec<wgpu::Texture> {
T::ALL_ORDERED
.iter()
.map(|segment| T::sub_view(*segment, atlas).to_image())
.map(|image| self.upload_mipmapped(&image, device, queue))
.collect()
}
}