lib.rs 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. use std::iter;
  2. use winit::{
  3. event::*,
  4. event_loop::EventLoop,
  5. keyboard::{KeyCode, PhysicalKey},
  6. window::{Window, WindowBuilder},
  7. };
  8. #[cfg(target_arch = "wasm32")]
  9. use wasm_bindgen::prelude::*;
  10. struct State<'a> {
  11. surface: wgpu::Surface<'a>,
  12. device: wgpu::Device,
  13. queue: wgpu::Queue,
  14. config: wgpu::SurfaceConfiguration,
  15. size: winit::dpi::PhysicalSize<u32>,
  16. // The window must be declared after the surface so
  17. // it gets dropped after it as the surface contains
  18. // unsafe references to the window's resources.
  19. window: &'a Window,
  20. }
  21. impl<'a> State<'a> {
  22. async fn new(window: &'a Window) -> State<'a> {
  23. let size = window.inner_size();
  24. // The instance is a handle to our GPU
  25. // BackendBit::PRIMARY => Vulkan + Metal + DX12 + Browser WebGPU
  26. let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
  27. backends: wgpu::Backends::all(),
  28. ..Default::default()
  29. });
  30. let surface = instance.create_surface(window).unwrap();
  31. let adapter = instance
  32. .request_adapter(&wgpu::RequestAdapterOptions {
  33. power_preference: wgpu::PowerPreference::default(),
  34. compatible_surface: Some(&surface),
  35. force_fallback_adapter: false,
  36. })
  37. .await
  38. .unwrap();
  39. let (device, queue) = adapter
  40. .request_device(
  41. &wgpu::DeviceDescriptor {
  42. label: None,
  43. required_features: wgpu::Features::empty(),
  44. // WebGL doesn't support all of wgpu's features, so if
  45. // we're building for the web we'll have to disable some.
  46. required_limits: if cfg!(target_arch = "wasm32") {
  47. wgpu::Limits::downlevel_webgl2_defaults()
  48. } else {
  49. wgpu::Limits::default()
  50. },
  51. },
  52. // Some(&std::path::Path::new("trace")), // Trace path
  53. None,
  54. )
  55. .await
  56. .unwrap();
  57. let surface_caps = surface.get_capabilities(&adapter);
  58. // Shader code in this tutorial assumes an Srgb surface texture. Using a different
  59. // one will result all the colors comming out darker. If you want to support non
  60. // Srgb surfaces, you'll need to account for that when drawing to the frame.
  61. let surface_format = surface_caps
  62. .formats
  63. .iter()
  64. .copied()
  65. .find(|f| f.is_srgb())
  66. .unwrap_or(surface_caps.formats[0]);
  67. let config = wgpu::SurfaceConfiguration {
  68. usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
  69. format: surface_format,
  70. width: size.width,
  71. height: size.height,
  72. present_mode: surface_caps.present_modes[0],
  73. alpha_mode: surface_caps.alpha_modes[0],
  74. desired_maximum_frame_latency: 2,
  75. view_formats: vec![],
  76. };
  77. surface.configure(&device, &config);
  78. Self {
  79. surface,
  80. device,
  81. queue,
  82. config,
  83. size,
  84. window,
  85. }
  86. }
  87. fn window(&self) -> &Window {
  88. &self.window
  89. }
  90. pub fn resize(&mut self, new_size: winit::dpi::PhysicalSize<u32>) {
  91. if new_size.width > 0 && new_size.height > 0 {
  92. self.size = new_size;
  93. self.config.width = new_size.width;
  94. self.config.height = new_size.height;
  95. self.surface.configure(&self.device, &self.config);
  96. }
  97. }
  98. #[allow(unused_variables)]
  99. fn input(&mut self, event: &WindowEvent) -> bool {
  100. false
  101. }
  102. fn update(&mut self) {}
  103. fn render(&mut self) -> Result<(), wgpu::SurfaceError> {
  104. let output = self.surface.get_current_texture()?;
  105. let view = output
  106. .texture
  107. .create_view(&wgpu::TextureViewDescriptor::default());
  108. let mut encoder = self
  109. .device
  110. .create_command_encoder(&wgpu::CommandEncoderDescriptor {
  111. label: Some("Render Encoder"),
  112. });
  113. {
  114. let _render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
  115. label: Some("Render Pass"),
  116. color_attachments: &[Some(wgpu::RenderPassColorAttachment {
  117. view: &view,
  118. resolve_target: None,
  119. ops: wgpu::Operations {
  120. load: wgpu::LoadOp::Clear(wgpu::Color {
  121. r: 0.1,
  122. g: 0.2,
  123. b: 0.3,
  124. a: 1.0,
  125. }),
  126. store: wgpu::StoreOp::Store,
  127. },
  128. })],
  129. depth_stencil_attachment: None,
  130. occlusion_query_set: None,
  131. timestamp_writes: None,
  132. });
  133. }
  134. self.queue.submit(iter::once(encoder.finish()));
  135. output.present();
  136. Ok(())
  137. }
  138. }
  139. pub async fn run() {
  140. env_logger::init();
  141. let event_loop = EventLoop::new().unwrap();
  142. let window = WindowBuilder::new().build(&event_loop).unwrap();
  143. // State::new uses async code, so we're going to wait for it to finish
  144. let mut state = State::new(&window).await;
  145. event_loop
  146. .run(move |event, control_flow| {
  147. match event {
  148. Event::WindowEvent {
  149. ref event,
  150. window_id,
  151. } if window_id == state.window().id() => {
  152. if !state.input(event) {
  153. // UPDATED!
  154. match event {
  155. WindowEvent::CloseRequested
  156. | WindowEvent::KeyboardInput {
  157. event:
  158. KeyEvent {
  159. state: ElementState::Pressed,
  160. physical_key: PhysicalKey::Code(KeyCode::Escape),
  161. ..
  162. },
  163. ..
  164. } => control_flow.exit(),
  165. WindowEvent::Resized(physical_size) => {
  166. state.resize(*physical_size);
  167. }
  168. WindowEvent::RedrawRequested => {
  169. // This tells winit that we want another frame after this one
  170. state.window().request_redraw();
  171. state.update();
  172. match state.render() {
  173. Ok(_) => {}
  174. // Reconfigure the surface if it's lost or outdated
  175. Err(
  176. wgpu::SurfaceError::Lost | wgpu::SurfaceError::Outdated,
  177. ) => state.resize(state.size),
  178. // The system is out of memory, we should probably quit
  179. Err(wgpu::SurfaceError::OutOfMemory) => {
  180. log::error!("OutOfMemory");
  181. control_flow.exit();
  182. }
  183. // This happens when the a frame takes too long to present
  184. Err(wgpu::SurfaceError::Timeout) => {
  185. log::warn!("Surface timeout")
  186. }
  187. }
  188. }
  189. _ => {}
  190. }
  191. }
  192. }
  193. _ => {}
  194. }
  195. })
  196. .unwrap();
  197. }