WebGPU Voxel Game

Tutorial 3: Pipeline

Changed files
+95 -11
src
+71 -11
src/lib.rs
··· 8 8 #[cfg(target_arch = "wasm32")] 9 9 use wasm_bindgen::prelude::*; 10 10 11 - struct State<'a> { 12 - surface: wgpu::Surface<'a>, 11 + struct State<'srfc> { 12 + surface: wgpu::Surface<'srfc>, 13 13 device: wgpu::Device, 14 14 queue: wgpu::Queue, 15 15 config: wgpu::SurfaceConfiguration, 16 16 size: winit::dpi::PhysicalSize<u32>, 17 + render_pipeline: wgpu::RenderPipeline, 17 18 18 19 // Window must be declared after surface 19 20 // so it gets dropped after it 20 21 // The surface contains unsafe references to the 21 22 // window's resources. 22 23 // src: learn wgpu 23 - window: &'a Window, 24 - 24 + window: &'srfc Window, 25 + 25 26 clear_color: wgpu::Color 26 27 } 27 28 ··· 97 98 desired_maximum_frame_latency: 2, 98 99 }; 99 100 101 + let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor { 102 + label: Some("Shader"), 103 + source: wgpu::ShaderSource::Wgsl(include_str!("shader.wgsl").into()) 104 + }); 105 + 106 + let render_pipeline_layout = 107 + device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { 108 + label: Some("Render Pipeline Layout"), 109 + bind_group_layouts: &[], 110 + push_constant_ranges: &[] 111 + }); 112 + 113 + let render_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { 114 + label: Some("Render Pipeline"), 115 + layout: Some(&render_pipeline_layout), 116 + vertex: wgpu::VertexState { 117 + module: &shader, 118 + entry_point: "vs_main", 119 + buffers: &[], 120 + compilation_options: wgpu::PipelineCompilationOptions::default(), 121 + }, 122 + fragment: Some(wgpu::FragmentState { 123 + module: &shader, 124 + entry_point: "fs_main", 125 + targets: &[Some(wgpu::ColorTargetState { 126 + format: config.format, 127 + blend: Some(wgpu::BlendState::REPLACE), 128 + write_mask: wgpu::ColorWrites::ALL, 129 + })], 130 + compilation_options: wgpu::PipelineCompilationOptions::default(), 131 + }), 132 + primitive: wgpu::PrimitiveState { 133 + topology: wgpu::PrimitiveTopology::TriangleList, 134 + strip_index_format: None, 135 + front_face: wgpu::FrontFace::Ccw, 136 + cull_mode: Some(wgpu::Face::Back), 137 + polygon_mode: wgpu::PolygonMode::Fill, 138 + unclipped_depth: false, 139 + conservative: false, 140 + }, 141 + depth_stencil: None, 142 + multisample: wgpu::MultisampleState { 143 + count: 1, 144 + mask: !0, 145 + alpha_to_coverage_enabled: false 146 + }, 147 + multiview: None, 148 + cache: None, 149 + }); 150 + 100 151 Self { 101 152 window, 102 153 surface, ··· 104 155 queue, 105 156 config, 106 157 size, 107 - clear_color: wgpu::Color::RED 158 + render_pipeline, 159 + clear_color: wgpu::Color { 160 + r: 0.1, 161 + g: 0.2, 162 + b: 0.3, 163 + a: 1.0 164 + } 108 165 } 109 166 } 110 167 ··· 131 188 r: position.x / (self.window.inner_size().width as f64), 132 189 g: 0.2, 133 190 b: position.y / (self.window.inner_size().height as f64), 134 - a: 1.0 191 + a: 0.1 135 192 }; 136 193 return true; 137 194 }, 138 195 _ => {} 139 196 } 140 - 197 + 141 198 false 142 199 } 143 200 ··· 153 210 label: Some("Render Encoder") 154 211 }); 155 212 156 - let render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { 213 + let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { 157 214 label: Some("Render Pass"), 158 215 color_attachments: &[Some(wgpu::RenderPassColorAttachment { 159 216 view: &view, ··· 167 224 occlusion_query_set: None, 168 225 timestamp_writes: None, 169 226 }); 227 + 228 + render_pass.set_pipeline(&self.render_pipeline); 229 + render_pass.draw(0..3, 0..1); 170 230 171 231 // drop render pass before we submit to drop the mut borrow on encoder 172 232 drop(render_pass); ··· 210 270 Some(()) 211 271 }) 212 272 .expect("Couldn't append canvas to document body."); 213 - 273 + 214 274 let _ = window.request_inner_size(PhysicalSize::new(450, 400)); 215 275 } 216 276 ··· 239 299 } 240 300 WindowEvent::RedrawRequested => { 241 301 state.window().request_redraw(); 242 - 302 + 243 303 if !surface_configured { 244 304 return; 245 305 } 246 - 306 + 247 307 state.update(); 248 308 match state.render() { 249 309 Ok(_) => {}
+24
src/shader.wgsl
··· 1 + // Vertex shader 2 + 3 + struct VertexOutput { 4 + @builtin(position) clip_position: vec4<f32>, 5 + }; 6 + 7 + @vertex 8 + fn vs_main( 9 + @builtin(vertex_index) in_vertex_index: u32, 10 + ) -> VertexOutput { 11 + var out: VertexOutput; 12 + let x = f32(1 - i32(in_vertex_index)) * 0.5; 13 + let y = f32(i32(in_vertex_index & 1u) * 2 - 1) * 0.5; 14 + out.clip_position = vec4<f32>(x, y, 0.0, 1.0); 15 + return out; 16 + } 17 + 18 + 19 + // Fragment shader 20 + 21 + @fragment 22 + fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> { 23 + return vec4<f32>(0.3, 0.2, 0.1, 1.0); 24 + }