use std::ops::{Deref, DerefMut}; mod data; mod layout; use super::*; pub use data::*; use layout::*; pub struct ComputePipeline { layout: Layout, pipeline: wgpu::ComputePipeline, bind_group: wgpu::BindGroup, old_view: ComputeView, old_len: usize, } const FIXED_SHADER: &str = include_str!("fixed.wgsl"); const SHADER: &str = include_str!("shader.wgsl"); impl ComputePipeline { pub fn init(device: &wgpu::Device, config: &wgpu::SurfaceConfiguration, len: usize) -> Self { let layout = Layout::init(device, config, len); Self { pipeline: layout.pipeline(device, &Self::shader(device, len)), bind_group: layout.bind_group(device), layout, old_view: ComputeView::default(), old_len: len, } } pub fn update( &mut self, device: &wgpu::Device, encoder: &mut wgpu::CommandEncoder, belt: &mut wgpu::util::StagingBelt, camera: &Camera, size: &Vector2, len: usize, ) { let mut view = ComputeView::from_camera_size(camera, size, false, len); if view != self.old_view { for (i, b) in 1u32.to_le_bytes().iter().enumerate() { view.bytes[i] = *b; } } if len != self.old_len { println!("new len: {}", len); self.old_len = len; self.pipeline = self.pipeline(device, &Self::shader(device, len)); self.work.set(work_vec(size.x, size.y, len)); } let updated = self.work.update(device, encoder, belt) | self.view.update(device, encoder, belt, view.bytes()); if updated { self.bind_group = self.layout.bind_group(device); } self.old_view = view; } pub fn run(&self, encoder: &mut wgpu::CommandEncoder) { let mut pass = encoder.begin_compute_pass(&wgpu::ComputePassDescriptor::default()); pass.set_pipeline(&self.pipeline); pass.set_bind_group(0, &self.bind_group, &[]); pass.dispatch_workgroups(240, 135, 1); } pub fn resize( &mut self, device: &wgpu::Device, encoder: &mut wgpu::CommandEncoder, belt: &mut wgpu::util::StagingBelt, size: Vector2, len: usize, ) { self.work.set(work_vec(size.x, size.y, len)); self.old_len = len; self.output.resize( device, wgpu::Extent3d { width: size.x, height: size.y, depth_or_array_layers: 1, }, ); self.bind_group = self.layout.bind_group(device); } pub fn shader(device: &wgpu::Device, len: usize) -> wgpu::ShaderModule { let string = FIXED_SHADER.to_string() + &SHADER.replace("REPLACE_LEN", &format!("{}", len)); device.create_shader_module(wgpu::ShaderModuleDescriptor { label: Some("compute"), source: wgpu::ShaderSource::Wgsl(string.into()), }) } } impl Deref for ComputePipeline { type Target = Layout; fn deref(&self) -> &Self::Target { &self.layout } } impl DerefMut for ComputePipeline { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.layout } }