learn_wgpu/
lib.rs

1// src/lib.rs
2use winit::{
3	event::*,
4	event_loop::{ ControlFlow, EventLoop },
5	window::{ WindowBuilder, Window },
6}; 
7
8struct State {
9	
10	instance: wgpu::Instance,
11	adapter: wgpu::Adapter,
12	surface: wgpu::Surface,
13	device: wgpu::Device,
14	queue: wgpu::Queue,
15	config: wgpu::SurfaceConfiguration,
16	size: winit::dpi::PhysicalSize<u32>,
17	clear_color: wgpu::Color,
18	render_pipeline: wgpu::RenderPipeline,
19	
20}
21
22impl State {
23	
24	async fn new(window: &Window) -> Self {
25		
26		let size = window.inner_size();
27		let instance = wgpu::Instance::new(wgpu::Backends::all());
28		let surface = unsafe { instance.create_surface(window) };
29		let adapter = instance.request_adapter(
30			
31			&wgpu::RequestAdapterOptions {
32				
33				power_preference: wgpu::PowerPreference::default(),
34				compatible_surface: Some(&surface),
35				force_fallback_adapter: false,
36				
37			},			
38		).await.unwrap();		
39		
40		let (device, queue) = adapter.request_device(
41			
42			&wgpu::DeviceDescriptor {
43				
44				label: None,
45				features: wgpu::Features::empty(),
46				limits: wgpu::Limits::default(),
47				
48			},
49			None,
50		).await.unwrap();
51		
52		let config = wgpu::SurfaceConfiguration {
53			
54			usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
55			format: surface.get_supported_formats(&adapter)[0],
56			width: size.width,
57			height: size.height,
58			present_mode: wgpu::PresentMode::Fifo,
59			
60		};		
61		surface.configure(&device, &config);
62		
63		let clear_color = wgpu::Color::BLACK;
64		
65		let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
66			
67			label: Some("Shader"),
68			source: wgpu::ShaderSource::Wgsl(include_str!("shader.wgsl").into()),
69			
70		});
71		
72		let render_pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
73			
74			label: Some("Render Pipeline Laypout"),
75			bind_group_layouts: &[],
76			push_constant_ranges: &[],
77			
78		});
79		
80		let render_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
81			
82			label: Some("Render Pipeline"),
83			layout: Some(&render_pipeline_layout),
84			vertex: wgpu::VertexState {
85				
86				module: &shader,
87				entry_point: "vs_main",
88				buffers: &[],
89				
90			},
91			fragment: Some(wgpu::FragmentState {
92				
93				module: &shader,
94				entry_point: "fs_main",
95				targets: &[Some(wgpu::ColorTargetState {
96					
97					format: config.format,
98					blend: Some(wgpu::BlendState::REPLACE),
99					write_mask: wgpu::ColorWrites::ALL,
100					
101				})],
102				
103			}),
104			primitive: wgpu::PrimitiveState {
105				
106				topology: wgpu::PrimitiveTopology::TriangleList,
107				strip_index_format: None,
108				front_face: wgpu::FrontFace::Ccw,
109				cull_mode: Some(wgpu::Face::Back),
110				polygon_mode: wgpu::PolygonMode::Fill,
111				unclipped_depth: false,
112				conservative: false,
113				
114			},
115			depth_stencil: None,
116			multisample: wgpu::MultisampleState {
117				
118				count: 1,
119				mask: !0,
120				alpha_to_coverage_enabled: false,
121				
122			},
123			multiview: None,
124			
125		});
126		
127		Self {
128			
129			instance,
130			adapter,
131			surface,
132			device,
133			queue,
134			config,
135			size,
136			clear_color,
137			render_pipeline,
138			
139		}
140	}
141	
142	fn resize(&mut self, new_size: winit::dpi::PhysicalSize<u32>) {
143		
144		if new_size.width > 0 && new_size.height > 0 {
145			
146			self.size = new_size;
147			self.config.width = new_size.width;
148			self.config.height = new_size.height;
149			self.surface.configure(&self.device, &self.config);
150			
151		}		
152	}	
153	
154	fn input(&mut self, event: &WindowEvent) -> bool {
155		
156		match event {
157			
158			WindowEvent::CursorMoved { position, .. } => {
159				
160				self.clear_color = wgpu::Color {
161					
162					r: position.x as f64 / self.size.width as f64,
163					g: position.y as f64 / self.size.height as f64,
164					b: 1.0,
165					a: 1.0,
166					
167				};
168				true
169				
170			}
171			_ => false,
172		}		
173	}
174	
175	fn update(&mut self) {
176		
177		
178		
179	}
180	
181	fn render(&mut self) -> Result<(), wgpu::SurfaceError> {
182		
183		let output = self.surface.get_current_texture()?;
184		let view = output.texture.create_view(&wgpu::TextureViewDescriptor::default());
185		let mut encoder = self.device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
186			
187			label: Some("Render Encoder"),
188			
189		});
190		
191		{
192			let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
193				
194				label: Some("Render Pass"),
195				color_attachments: &[Some(wgpu::RenderPassColorAttachment {
196					
197					view: &view,
198					resolve_target: None,
199					ops: wgpu::Operations {
200						
201						load: wgpu::LoadOp::Clear(self.clear_color),
202						store: true,
203												
204					},
205				})],				
206				depth_stencil_attachment: None,
207				
208			});
209			
210			render_pass.set_pipeline(&self.render_pipeline);
211			render_pass.draw(0..3, 0..1);
212		}
213		
214		self.queue.submit(std::iter::once(encoder.finish()));
215		output.present();
216		
217		Ok(())		
218	}
219}
220
221pub async fn run() {
222	
223	env_logger::init();
224	let event_loop = EventLoop::new();
225	let window = WindowBuilder::new().build(&event_loop).unwrap();
226	
227	let mut state = State::new(&window).await;	
228	
229	event_loop.run(move |event, _, control_flow| {
230		
231		match event {
232			
233			Event::WindowEvent {
234				
235				ref event,
236				window_id,
237				
238			} if window_id == window.id() => if !state.input(event) {
239				
240				match event {
241					
242					WindowEvent::CloseRequested | WindowEvent::KeyboardInput {
243						
244						input: KeyboardInput {
245							
246							state: ElementState::Pressed,
247							virtual_keycode: Some(VirtualKeyCode::Escape),
248							..
249							
250						},
251					..
252						
253					} => *control_flow = ControlFlow::Exit,
254					WindowEvent::Resized(physical_size) => {
255						
256						state.resize(*physical_size);
257						
258					},
259					WindowEvent::ScaleFactorChanged { new_inner_size, .. } => {
260						
261						state.resize(**new_inner_size);
262						
263					},
264					_ => {},
265					
266				}
267			}
268			Event::RedrawRequested(window_id) if window_id == window.id() => {
269				
270				state.update();
271				match state.render() {
272					
273					Ok(_) => {}
274					Err(wgpu::SurfaceError::Lost) => state.resize(state.size),
275					Err(wgpu::SurfaceError::OutOfMemory) => *control_flow = ControlFlow::Exit,
276					Err(wgpu::SurfaceError::Timeout) => log::warn!("Surface timeout"),
277					Err(e) => eprintln!("{e:?}"),					
278					
279				}
280				
281			},
282			Event::MainEventsCleared => {
283				
284				window.request_redraw();
285				
286			}
287			_ => {}			
288		}		
289	});
290}