diff --git a/code/beginner/tutorial9-models/src/main.rs b/code/beginner/tutorial9-models/src/main.rs index 7e787164..2464ff1d 100644 --- a/code/beginner/tutorial9-models/src/main.rs +++ b/code/beginner/tutorial9-models/src/main.rs @@ -158,6 +158,11 @@ impl Instance { } struct State { + surface: wgpu::Surface, + device: wgpu::Device, + queue: wgpu::Queue, + sc_desc: wgpu::SwapChainDescriptor, + swap_chain: wgpu::SwapChain, render_pipeline: wgpu::RenderPipeline, obj_model: model::Model, camera: Camera, @@ -169,13 +174,41 @@ struct State { instance_buffer: wgpu::Buffer, depth_texture: wgpu::Texture, depth_texture_view: wgpu::TextureView, + size: winit::dpi::PhysicalSize, } impl State { - fn new( - sc_desc: &wgpu::SwapChainDescriptor, - device: &wgpu::Device, - ) -> (Self, Option>) { + async fn new(window: &Window) -> Self { + let size = window.inner_size(); + + let surface = wgpu::Surface::create(window); + + let adapter = wgpu::Adapter::request( + &wgpu::RequestAdapterOptions { + power_preference: wgpu::PowerPreference::Default, + compatible_surface: Some(&surface), + }, + wgpu::BackendBit::PRIMARY, // Vulkan + Metal + DX12 + Browser WebGPU + ).await.unwrap(); + + let (device, queue) = adapter.request_device(&wgpu::DeviceDescriptor { + extensions: wgpu::Extensions { + anisotropic_filtering: false, + }, + limits: Default::default(), + }).await; + + + let sc_desc = wgpu::SwapChainDescriptor { + usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT, + format: wgpu::TextureFormat::Bgra8UnormSrgb, + width: size.width, + height: size.height, + present_mode: wgpu::PresentMode::Fifo, + }; + + let swap_chain = device.create_swap_chain(&surface, &sc_desc); + let texture_bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { bindings: &[ @@ -300,7 +333,7 @@ impl State { "code/beginner/tutorial9-models/src/res/cube.obj", ) .unwrap(); - + queue.submit(&cmds); let vs_src = include_str!("shader.vert"); let fs_src = include_str!("shader.frag"); let vs_spirv = glsl_to_spirv::compile(vs_src, glsl_to_spirv::ShaderType::Vertex).unwrap(); @@ -360,7 +393,12 @@ impl State { }, }); - let state = Self { + Self { + surface, + device, + queue, + sc_desc, + swap_chain, render_pipeline, obj_model, camera, @@ -372,34 +410,31 @@ impl State { instance_buffer, depth_texture, depth_texture_view, - }; - (state, Some(cmds)) + size, + } } - fn resize( - &mut self, - sc_desc: &wgpu::SwapChainDescriptor, - device: &wgpu::Device, - ) -> Option { - self.depth_texture = texture::Texture::create_depth_texture(device, sc_desc).texture; + async fn resize(&mut self, new_size: winit::dpi::PhysicalSize) { + self.depth_texture = texture::Texture::create_depth_texture(&self.device, &self.sc_desc).texture; self.depth_texture_view = self.depth_texture.create_default_view(); - self.camera.aspect = sc_desc.width as f32 / sc_desc.height as f32; - - None + self.camera.aspect = self.sc_desc.width as f32 / self.sc_desc.height as f32; + self.size = new_size; + self.sc_desc.width = new_size.width; + self.sc_desc.height = new_size.height; + self.swap_chain = self.device.create_swap_chain(&self.surface, &self.sc_desc); } - fn input(&mut self, event: &WindowEvent) -> bool { self.camera_controller.process_events(event) } - fn update(&mut self, device: &wgpu::Device) -> Option { + async fn update(&mut self) { self.camera_controller.update_camera(&mut self.camera); self.uniforms.update_view_proj(&self.camera); let mut encoder = - device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None }); + self.device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None }); - let staging_buffer = device.create_buffer_with_data( + let staging_buffer = self.device.create_buffer_with_data( bytemuck::cast_slice(&[self.uniforms]), wgpu::BufferUsage::COPY_SRC, ); @@ -412,16 +447,14 @@ impl State { std::mem::size_of::() as wgpu::BufferAddress, ); - Some(encoder.finish()) + self.queue.submit(&[encoder.finish()]); } - fn render( - &mut self, - frame: &wgpu::SwapChainOutput, - device: &wgpu::Device, - ) -> wgpu::CommandBuffer { + async fn render(&mut self) { + let frame = self.swap_chain.get_next_texture() + .expect("Timeout getting texture"); let mut encoder = - device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None }); + self.device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None }); { let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { @@ -456,105 +489,10 @@ impl State { ); } - encoder.finish() + self.queue.submit(&[encoder.finish()]); } } -async fn run_async(event_loop: EventLoop<()>, window: Window) { - let size = window.inner_size(); - let surface = wgpu::Surface::create(&window); - let adapter = wgpu::Adapter::request( - &wgpu::RequestAdapterOptions { - power_preference: wgpu::PowerPreference::Default, - compatible_surface: Some(&surface), - }, - wgpu::BackendBit::PRIMARY, - ) - .await - .unwrap(); - let (device, queue) = adapter - .request_device(&wgpu::DeviceDescriptor { - extensions: wgpu::Extensions { - anisotropic_filtering: false, - }, - limits: wgpu::Limits::default(), - }) - .await; - let mut sc_desc = wgpu::SwapChainDescriptor { - usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT, - format: if cfg!(target_arch = "wasm32") { - wgpu::TextureFormat::Bgra8Unorm - } else { - wgpu::TextureFormat::Bgra8UnormSrgb - }, - width: size.width, - height: size.height, - present_mode: wgpu::PresentMode::Mailbox, - }; - let mut swap_chain = device.create_swap_chain(&surface, &sc_desc); - let (mut state, init_cmds_buf) = State::new(&sc_desc, &device); - - if let Some(cmds_buf) = init_cmds_buf { - queue.submit(&cmds_buf); - } - event_loop.run(move |event, _, control_flow| { - *control_flow = ControlFlow::Poll; - match event { - Event::MainEventsCleared => window.request_redraw(), - Event::WindowEvent { - ref event, - window_id, - } if window_id == window.id() => { - if !state.input(event) { - match event { - WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit, - WindowEvent::KeyboardInput { input, .. } => match input { - KeyboardInput { - state: ElementState::Pressed, - virtual_keycode: Some(VirtualKeyCode::Escape), - .. - } => { - *control_flow = ControlFlow::Exit; - } - _ => {} - }, - WindowEvent::Resized(physical_size) => { - sc_desc.width = physical_size.width; - sc_desc.height = physical_size.height; - swap_chain = device.create_swap_chain(&surface, &sc_desc); - - let cmd_buf = state.resize(&sc_desc, &device); - if let Some(cmd_buf) = cmd_buf { - queue.submit(&[cmd_buf]); - } - } - WindowEvent::ScaleFactorChanged { new_inner_size, .. } => { - sc_desc.width = new_inner_size.width; - sc_desc.height = new_inner_size.height; - swap_chain = device.create_swap_chain(&surface, &sc_desc); - let cmd_buf = state.resize(&sc_desc, &device); - if let Some(cmd_buf) = cmd_buf { - queue.submit(&[cmd_buf]); - } - } - _ => {} - } - } - } - Event::RedrawRequested(_) => { - if let Some(cmd_buf) = state.update(&device) { - queue.submit(&[cmd_buf]); - } - let frame = swap_chain - .get_next_texture() - .expect("Timeout when acquiring next swap chain texture"); - let command_buf = state.render(&frame, &device); - queue.submit(&[command_buf]); - } - _ => {} - } - }); -} fn main() { let event_loop = EventLoop::new(); let title = "tutorial9-models"; @@ -562,7 +500,46 @@ fn main() { .with_title(title) .build(&event_loop) .unwrap(); - futures::executor::block_on(run_async(event_loop, window)); + use futures::executor::block_on; + let mut state = block_on(State::new(&window)); + event_loop.run(move |event, _, control_flow| { + *control_flow = ControlFlow::Poll; + match event { + Event::MainEventsCleared => window.request_redraw(), + Event::WindowEvent { + ref event, + window_id, + } if window_id == window.id() => { + if !state.input(event) { + match event { + WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit, + WindowEvent::KeyboardInput { input, .. } => match input { + KeyboardInput { + state: ElementState::Pressed, + virtual_keycode: Some(VirtualKeyCode::Escape), + .. + } => { + *control_flow = ControlFlow::Exit; + } + _ => {} + }, + WindowEvent::Resized(physical_size) => { + block_on(state.resize(*physical_size)); + } + WindowEvent::ScaleFactorChanged { new_inner_size, .. } => { + block_on(state.resize(**new_inner_size)); + } + _ => {} + } + } + } + Event::RedrawRequested(_) => { + block_on(state.update()); + block_on(state.render()); + } + _ => {} + } + }); } #[inline] pub fn matrix4f_cast_slice(a: &[Vec>]) -> &[u8] {