| 74 | |
| 75 | impl ImpulseField { |
| 76 | pub fn new(device: &wgpu::Device) -> Self { |
| 77 | let bg_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { |
| 78 | label: Some("impulse_field_bg_layout"), |
| 79 | entries: &[ |
| 80 | // 0: src (previous-frame sampled texture) |
| 81 | wgpu::BindGroupLayoutEntry { |
| 82 | binding: 0, visibility: wgpu::ShaderStages::COMPUTE, |
| 83 | ty: wgpu::BindingType::Texture { |
| 84 | sample_type: wgpu::TextureSampleType::Float { filterable: false }, |
| 85 | view_dimension: wgpu::TextureViewDimension::D2, |
| 86 | multisampled: false, |
| 87 | }, |
| 88 | count: None, |
| 89 | }, |
| 90 | // 1: dst (write-only storage) |
| 91 | wgpu::BindGroupLayoutEntry { |
| 92 | binding: 1, visibility: wgpu::ShaderStages::COMPUTE, |
| 93 | ty: wgpu::BindingType::StorageTexture { |
| 94 | access: wgpu::StorageTextureAccess::WriteOnly, |
| 95 | format: wgpu::TextureFormat::R32Float, |
| 96 | view_dimension: wgpu::TextureViewDimension::D2, |
| 97 | }, |
| 98 | count: None, |
| 99 | }, |
| 100 | // 2: info UBO (splats + bounds + decay) |
| 101 | wgpu::BindGroupLayoutEntry { |
| 102 | binding: 2, visibility: wgpu::ShaderStages::COMPUTE, |
| 103 | ty: wgpu::BindingType::Buffer { |
| 104 | ty: wgpu::BufferBindingType::Uniform, |
| 105 | has_dynamic_offset: false, |
| 106 | min_binding_size: None, |
| 107 | }, |
| 108 | count: None, |
| 109 | }, |
| 110 | ], |
| 111 | }); |
| 112 | |
| 113 | let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { |
| 114 | label: Some("impulse_field_pipeline_layout"), |
| 115 | bind_group_layouts: &[Some(&bg_layout)], |
| 116 | immediate_size: 0, |
| 117 | }); |
| 118 | |
| 119 | let shader_src = library().fetch("impulse_field.wgsl") |
| 120 | .expect("impulse_field.wgsl must be present in shader_library") |
| 121 | .to_string(); |
| 122 | let module = device.create_shader_module(wgpu::ShaderModuleDescriptor { |
| 123 | label: Some("impulse_field"), |
| 124 | source: wgpu::ShaderSource::Wgsl(shader_src.into()), |
| 125 | }); |
| 126 | let pipeline = device.create_compute_pipeline(&wgpu::ComputePipelineDescriptor { |
| 127 | label: Some("impulse_field_pipeline"), |
| 128 | layout: Some(&pipeline_layout), |
| 129 | module: &module, |
| 130 | entry_point: Some("cs_main"), |
| 131 | compilation_options: Default::default(), |
| 132 | cache: None, |
| 133 | }); |