Guest User

Untitled

a guest
Sep 5th, 2022
92
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Rust 7.49 KB | Source Code | 0 0
  1. use pollster::FutureExt;
  2.  
  3. use crate::gpu_interface::GPUInterface;
  4.  
  5. pub struct Life {
  6.     compute_pipeline: wgpu::ComputePipeline,
  7.     input_texture: wgpu::Texture,
  8.     output_texture: wgpu::Texture,
  9.     texture_size: wgpu::Extent3d,
  10. }
  11.  
  12. impl Life {
  13.     pub fn new(gpu: &GPUInterface) -> Life {
  14.         let shader = gpu
  15.             .device
  16.             .create_shader_module(&wgpu::ShaderModuleDescriptor {
  17.                 label: Some("Grayscale shader"),
  18.                 source: wgpu::ShaderSource::Wgsl(include_str!("grayscale.wgsl").into()),
  19.             });
  20.  
  21.         let pipeline = gpu
  22.             .device
  23.             .create_compute_pipeline(&wgpu::ComputePipelineDescriptor {
  24.                 label: Some("Grayscale pipeline"),
  25.                 layout: None,
  26.                 module: &shader,
  27.                 entry_point: "grayscale_main",
  28.             });
  29.  
  30.         let input_image = image::load_from_memory(include_bytes!("test1.png"))
  31.             .unwrap()
  32.             .to_rgba8();
  33.         let (width, height) = input_image.dimensions();
  34.  
  35.         let texture_size = wgpu::Extent3d {
  36.             width,
  37.             height,
  38.             depth_or_array_layers: 1,
  39.         };
  40.  
  41.         let input_texture = gpu.device.create_texture(&wgpu::TextureDescriptor {
  42.             label: Some("input texture"),
  43.             size: texture_size,
  44.             mip_level_count: 1,
  45.             sample_count: 1,
  46.             dimension: wgpu::TextureDimension::D2,
  47.             format: wgpu::TextureFormat::Rgba8Unorm,
  48.             usage: wgpu::TextureUsages::TEXTURE_BINDING
  49.                 | wgpu::TextureUsages::COPY_DST
  50.                 | wgpu::TextureUsages::COPY_SRC
  51.                 | wgpu::TextureUsages::STORAGE_BINDING,
  52.         });
  53.  
  54.         let output_texture = gpu.device.create_texture(&wgpu::TextureDescriptor {
  55.             label: Some("output texture"),
  56.             size: texture_size,
  57.             mip_level_count: 1,
  58.             sample_count: 1,
  59.             dimension: wgpu::TextureDimension::D2,
  60.             format: wgpu::TextureFormat::Rgba8Unorm,
  61.             usage: wgpu::TextureUsages::TEXTURE_BINDING
  62.                 | wgpu::TextureUsages::COPY_DST
  63.                 | wgpu::TextureUsages::COPY_SRC
  64.                 | wgpu::TextureUsages::STORAGE_BINDING,
  65.         });
  66.         gpu.queue.write_texture(
  67.             input_texture.as_image_copy(),
  68.             bytemuck::cast_slice(input_image.as_raw()),
  69.             wgpu::ImageDataLayout {
  70.                 offset: 0,
  71.                 bytes_per_row: std::num::NonZeroU32::new(4 * width),
  72.                 rows_per_image: None, // Doesn't need to be specified as we are writing a single image.
  73.             },
  74.             texture_size,
  75.         );
  76.  
  77.         Life {
  78.             compute_pipeline: pipeline,
  79.             input_texture: input_texture,
  80.             output_texture: output_texture,
  81.             texture_size: texture_size,
  82.         }
  83.     }
  84.     pub fn step(&self, gpu: &GPUInterface) {
  85.         let mut encoder = gpu
  86.             .device
  87.             .create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
  88.         let texture_bind_group = gpu.device.create_bind_group(&wgpu::BindGroupDescriptor {
  89.             label: Some("Texture bind group"),
  90.             layout: &self.compute_pipeline.get_bind_group_layout(0),
  91.             entries: &[
  92.                 wgpu::BindGroupEntry {
  93.                     binding: 0,
  94.                     resource: wgpu::BindingResource::TextureView(
  95.                         &self
  96.                             .input_texture
  97.                             .create_view(&wgpu::TextureViewDescriptor::default()),
  98.                     ),
  99.                 },
  100.                 wgpu::BindGroupEntry {
  101.                     binding: 1,
  102.                     resource: wgpu::BindingResource::TextureView(
  103.                         &self
  104.                             .output_texture
  105.                             .create_view(&wgpu::TextureViewDescriptor::default()),
  106.                     ),
  107.                 },
  108.             ],
  109.         });
  110.         // Dispatch
  111.  
  112.         {
  113.             let (dispatch_with, dispatch_height) = Life::compute_work_group_count(
  114.                 (self.texture_size.width, self.texture_size.height),
  115.                 (16, 16),
  116.             );
  117.             let mut compute_pass = encoder.begin_compute_pass(&wgpu::ComputePassDescriptor {
  118.                 label: Some("Grayscale pass"),
  119.             });
  120.             compute_pass.set_pipeline(&self.compute_pipeline);
  121.             compute_pass.set_bind_group(0, &texture_bind_group, &[]);
  122.             compute_pass.dispatch(dispatch_with, dispatch_height, 1);
  123.         }
  124.  
  125.         //SAVE RESULT TO FILE
  126.         //IF anything below this line is refactored into its own function, my output is blank.
  127.         let padded_bytes_per_row = Life::padded_bytes_per_row(self.texture_size.width);
  128.         let unpadded_bytes_per_row = self.texture_size.width as usize * 4;
  129.  
  130.         let output_buffer_size = padded_bytes_per_row as u64
  131.             * self.texture_size.height as u64
  132.             * std::mem::size_of::<u8>() as u64;
  133.         let output_buffer = gpu.device.create_buffer(&wgpu::BufferDescriptor {
  134.             label: None,
  135.             size: output_buffer_size,
  136.             usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::MAP_READ,
  137.             mapped_at_creation: false,
  138.         });
  139.  
  140.         encoder.copy_texture_to_buffer(
  141.             wgpu::ImageCopyTexture {
  142.                 aspect: wgpu::TextureAspect::All,
  143.                 texture: &self.output_texture,
  144.                 mip_level: 0,
  145.                 origin: wgpu::Origin3d::ZERO,
  146.             },
  147.             wgpu::ImageCopyBuffer {
  148.                 buffer: &output_buffer,
  149.                 layout: wgpu::ImageDataLayout {
  150.                     offset: 0,
  151.                     bytes_per_row: std::num::NonZeroU32::new(padded_bytes_per_row as u32),
  152.                     rows_per_image: std::num::NonZeroU32::new(self.texture_size.height),
  153.                 },
  154.             },
  155.             self.texture_size,
  156.         );
  157.         gpu.queue.submit(Some(encoder.finish()));
  158.  
  159.         let buffer_slice = output_buffer.slice(..);
  160.         let mapping = buffer_slice.map_async(wgpu::MapMode::Read);
  161.  
  162.         gpu.device.poll(wgpu::Maintain::Wait);
  163.         mapping.block_on();
  164.  
  165.         let padded_data = buffer_slice.get_mapped_range();
  166.  
  167.         let mut pixels: Vec<u8> =
  168.             vec![0; unpadded_bytes_per_row * self.texture_size.height as usize];
  169.         for (padded, pixels) in padded_data
  170.             .chunks_exact(padded_bytes_per_row)
  171.             .zip(pixels.chunks_exact_mut(unpadded_bytes_per_row))
  172.         {
  173.             pixels.copy_from_slice(&padded[..unpadded_bytes_per_row]);
  174.         }
  175.  
  176.         if let Some(output_image) = image::ImageBuffer::<image::Rgba<u8>, _>::from_raw(
  177.             self.texture_size.width,
  178.             self.texture_size.height,
  179.             &pixels[..],
  180.         ) {
  181.             output_image.save("test2.png");
  182.         }
  183.     }
  184.  
  185.     fn compute_work_group_count(
  186.         (width, height): (u32, u32),
  187.         (workgroup_width, workgroup_height): (u32, u32),
  188.     ) -> (u32, u32) {
  189.         let x = (width + workgroup_width - 1) / workgroup_width;
  190.         let y = (height + workgroup_height - 1) / workgroup_height;
  191.  
  192.         (x, y)
  193.     }
  194.  
  195.     /// Compute the next multiple of 256 for texture retrieval padding.
  196.     fn padded_bytes_per_row(width: u32) -> usize {
  197.         let bytes_per_row = width as usize * 4;
  198.         let padding = (256 - bytes_per_row % 256) % 256;
  199.         bytes_per_row + padding
  200.     }
  201. }
  202.  
Advertisement
Add Comment
Please, Sign In to add comment