use std::num::NonZeroU32; use wgpu::{util::*, *}; use crate::Image; impl Image { /// Get the size as a [`wgpu::Extend3d`]. pub fn wgpu_size(&self) -> Extent3d { Extent3d { width: self.width(), height: self.height(), depth_or_array_layers: 1, } } } impl> Image { /// Upload this image to the gpu, returning a [`wgpu::Texture`]. pub fn send(&self, dev: &Device, q: &Queue, usage: TextureUsages) -> Texture { dev.create_texture_with_data( &q, &TextureDescriptor { label: None, size: self.wgpu_size(), mip_level_count: 1, sample_count: 1, dimension: TextureDimension::D2, format: TextureFormat::Rgba8Unorm, view_formats: &[], usage, }, util::TextureDataOrder::LayerMajor, self.bytes(), ) } } impl Image, 4> { /// Downloads a purportedly [`TextureFormat::Rgba8Unorm`] image from the gpu. /// # Panics /// /// When a "error occurs while trying to async map a buffer". pub fn download( dev: &Device, q: &Queue, texture: &Texture, (width, height): (NonZeroU32, NonZeroU32), ) -> Self { let mut encoder = dev.create_command_encoder(&CommandEncoderDescriptor { label: None }); let texture_size = Extent3d { width: width.get(), height: height.get(), depth_or_array_layers: 1, }; let row = width.get() as usize * 4; let pad = { let padding = (256 - row % 256) % 256; row + padding }; let output_buffer = dev.create_buffer(&BufferDescriptor { label: None, size: pad as u64 * height.get() as u64, usage: BufferUsages::COPY_DST | BufferUsages::MAP_READ, mapped_at_creation: false, }); encoder.copy_texture_to_buffer( wgpu::ImageCopyTexture { aspect: wgpu::TextureAspect::All, texture, mip_level: 0, origin: wgpu::Origin3d::ZERO, }, wgpu::ImageCopyBuffer { buffer: &output_buffer, layout: wgpu::ImageDataLayout { offset: 0, bytes_per_row: Some(pad as u32), rows_per_image: Some(height.get()), }, }, texture_size, ); q.submit(Some(encoder.finish())); let buffer_slice = output_buffer.slice(..); buffer_slice.map_async(wgpu::MapMode::Read, Result::unwrap); dev.poll(wgpu::Maintain::Wait); let mut out = crate::uninit::Image::<_, 4>::new(width, height); for (padded, pixels) in buffer_slice .get_mapped_range() .chunks_exact(pad) .zip(out.buf().chunks_exact_mut(row)) { ::core::mem::MaybeUninit::copy_from_slice(pixels, &padded[..row]); } unsafe { out.assume_init().boxed() } } }