fast image operations
Diffstat (limited to 'src/wgpu_convert.rs')
| -rw-r--r-- | src/wgpu_convert.rs | 105 |
1 files changed, 105 insertions, 0 deletions
diff --git a/src/wgpu_convert.rs b/src/wgpu_convert.rs new file mode 100644 index 0000000..c95346f --- /dev/null +++ b/src/wgpu_convert.rs @@ -0,0 +1,105 @@ +use std::num::NonZeroU32; + +use wgpu::{util::*, *}; + +use crate::Image; + +impl<T, const N: usize> Image<T, N> { + /// 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<T: AsRef<[u8]>> Image<T, 4> { + /// 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<Box<[u8]>, 4> { + /// Downlodas 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::write_slice(pixels, &padded[..row]); + } + + unsafe { out.assume_init().boxed() } + } +} |