From 09207e9403696ca93a9514631a74e3975014aecc Mon Sep 17 00:00:00 2001 From: Benjamin Hansen Date: Sat, 14 Jan 2023 13:32:51 -0700 Subject: [PATCH] changed State to own window --- .../tutorial2-surface/src/challenge.rs | 24 ++++++++++++---- code/beginner/tutorial2-surface/src/lib.rs | 24 ++++++++++++---- .../tutorial3-pipeline/src/challenge.rs | 24 ++++++++++++---- code/beginner/tutorial3-pipeline/src/lib.rs | 24 ++++++++++++---- .../tutorial4-buffer/src/challenge.rs | 24 ++++++++++++---- code/beginner/tutorial4-buffer/src/lib.rs | 24 ++++++++++++---- .../tutorial5-textures/src/challenge.rs | 24 ++++++++++++---- code/beginner/tutorial5-textures/src/lib.rs | 24 ++++++++++++---- .../tutorial6-uniforms/src/challenge.rs | 24 ++++++++++++---- code/beginner/tutorial6-uniforms/src/lib.rs | 24 ++++++++++++---- .../tutorial7-instancing/src/challenge.rs | 24 ++++++++++++---- code/beginner/tutorial7-instancing/src/lib.rs | 24 ++++++++++++---- .../beginner/tutorial8-depth/src/challenge.rs | 25 +++++++++++++---- code/beginner/tutorial8-depth/src/lib.rs | 24 ++++++++++++---- code/beginner/tutorial9-models/src/lib.rs | 24 ++++++++++++---- .../tutorial10-lighting/src/lib.rs | 24 ++++++++++++---- .../tutorial11-normals/src/lib.rs | 24 ++++++++++++---- .../intermediate/tutorial12-camera/src/lib.rs | 24 ++++++++++++---- .../tutorial13-terrain/src/lib.rs | 26 ++++++++++++----- code/showcase/compute/src/main.rs | 24 ++++++++++++---- code/showcase/framework/src/lib.rs | 10 +++++-- code/showcase/mouse-picking/src/lib.rs | 24 ++++++++++++---- code/showcase/pong/src/lib.rs | 6 ++-- code/showcase/pong/src/render/mod.rs | 8 +++++- code/showcase/threading/src/lib.rs | 24 ++++++++++++---- docs/beginner/tutorial2-surface/README.md | 28 +++++++++++++------ docs/beginner/tutorial6-uniforms/README.md | 6 ++-- docs/beginner/tutorial7-instancing/README.md | 2 +- docs/beginner/tutorial8-depth/README.md | 2 +- docs/intermediate/tutorial12-camera/README.md | 8 +++--- 30 files changed, 444 insertions(+), 157 deletions(-) diff --git a/code/beginner/tutorial2-surface/src/challenge.rs b/code/beginner/tutorial2-surface/src/challenge.rs index 75560661e..83ec1e438 100644 --- a/code/beginner/tutorial2-surface/src/challenge.rs +++ b/code/beginner/tutorial2-surface/src/challenge.rs @@ -17,16 +17,23 @@ struct State { config: wgpu::SurfaceConfiguration, size: winit::dpi::PhysicalSize, clear_color: wgpu::Color, + window: Window, } impl State { - async fn new(window: &Window) -> Self { + async fn new(window: Window) -> Self { let size = window.inner_size(); // The instance is a handle to our GPU // BackendBit::PRIMARY => Vulkan + Metal + DX12 + Browser WebGPU let instance = wgpu::Instance::new(wgpu::Backends::all()); - let surface = unsafe { instance.create_surface(window) }; + + // # Safety + // + // The surface needs to live as long as the window that created it. + // State owns the window so this should be safe. + let surface = unsafe { instance.create_surface(&window) }; + let adapter = instance .request_adapter(&wgpu::RequestAdapterOptions { power_preference: wgpu::PowerPreference::default(), @@ -75,9 +82,14 @@ impl State { config, clear_color, size, + window, } } + fn window(&self) -> &Window { + &self.window + } + pub fn resize(&mut self, new_size: winit::dpi::PhysicalSize) { if new_size.width > 0 && new_size.height > 0 { self.size = new_size; @@ -148,14 +160,14 @@ async fn run() { let window = WindowBuilder::new().build(&event_loop).unwrap(); // State::new uses async code, so we're going to wait for it to finish - let mut state = State::new(&window).await; + let mut state = State::new(window).await; event_loop.run(move |event, _, control_flow| { match event { Event::WindowEvent { ref event, window_id, - } if window_id == window.id() => { + } if window_id == state.window().id() => { if !state.input(event) { match event { WindowEvent::CloseRequested @@ -179,7 +191,7 @@ async fn run() { } } } - Event::RedrawRequested(window_id) if window_id == window.id() => { + Event::RedrawRequested(window_id) if window_id == state.window().id() => { state.update(); match state.render() { Ok(_) => {} @@ -192,7 +204,7 @@ async fn run() { } } Event::MainEventsCleared => { - window.request_redraw(); + state.window().request_redraw(); } _ => {} } diff --git a/code/beginner/tutorial2-surface/src/lib.rs b/code/beginner/tutorial2-surface/src/lib.rs index 6e1b20601..fad6941fb 100644 --- a/code/beginner/tutorial2-surface/src/lib.rs +++ b/code/beginner/tutorial2-surface/src/lib.rs @@ -15,16 +15,23 @@ struct State { queue: wgpu::Queue, config: wgpu::SurfaceConfiguration, size: winit::dpi::PhysicalSize, + window: Window, } impl State { - async fn new(window: &Window) -> Self { + async fn new(window: Window) -> Self { let size = window.inner_size(); // The instance is a handle to our GPU // BackendBit::PRIMARY => Vulkan + Metal + DX12 + Browser WebGPU let instance = wgpu::Instance::new(wgpu::Backends::all()); - let surface = unsafe { instance.create_surface(window) }; + + // # Safety + // + // The surface needs to live as long as the window that created it. + // State owns the window so this should be safe. + let surface = unsafe { instance.create_surface(&window) }; + let adapter = instance .request_adapter(&wgpu::RequestAdapterOptions { power_preference: wgpu::PowerPreference::default(), @@ -69,9 +76,14 @@ impl State { queue, config, size, + window, } } + fn window(&self) -> &Window { + &self.window + } + pub fn resize(&mut self, new_size: winit::dpi::PhysicalSize) { if new_size.width > 0 && new_size.height > 0 { self.size = new_size; @@ -161,14 +173,14 @@ pub async fn run() { } // State::new uses async code, so we're going to wait for it to finish - let mut state = State::new(&window).await; + let mut state = State::new(window).await; event_loop.run(move |event, _, control_flow| { match event { Event::WindowEvent { ref event, window_id, - } if window_id == window.id() => { + } if window_id == state.window().id() => { if !state.input(event) { // UPDATED! match event { @@ -193,7 +205,7 @@ pub async fn run() { } } } - Event::RedrawRequested(window_id) if window_id == window.id() => { + Event::RedrawRequested(window_id) if window_id == state.window().id() => { state.update(); match state.render() { Ok(_) => {} @@ -208,7 +220,7 @@ pub async fn run() { Event::RedrawEventsCleared => { // RedrawRequested will only trigger once, unless we manually // request it. - window.request_redraw(); + state.window().request_redraw(); } _ => {} } diff --git a/code/beginner/tutorial3-pipeline/src/challenge.rs b/code/beginner/tutorial3-pipeline/src/challenge.rs index 6c6c134f7..082863243 100644 --- a/code/beginner/tutorial3-pipeline/src/challenge.rs +++ b/code/beginner/tutorial3-pipeline/src/challenge.rs @@ -15,16 +15,23 @@ struct State { render_pipeline: wgpu::RenderPipeline, challenge_render_pipeline: wgpu::RenderPipeline, use_color: bool, + window: Window, } impl State { - async fn new(window: &Window) -> Self { + async fn new(window: Window) -> Self { let size = window.inner_size(); // The instance is a handle to our GPU // BackendBit::PRIMARY => Vulkan + Metal + DX12 + Browser WebGPU let instance = wgpu::Instance::new(wgpu::Backends::all()); - let surface = unsafe { instance.create_surface(window) }; + + // # Safety + // + // The surface needs to live as long as the window that created it. + // State owns the window so this should be safe. + let surface = unsafe { instance.create_surface(&window) }; + let adapter = instance .request_adapter(&wgpu::RequestAdapterOptions { power_preference: wgpu::PowerPreference::default(), @@ -172,9 +179,14 @@ impl State { challenge_render_pipeline, use_color, size, + window, } } + fn window(&self) -> &Window { + &self.window + } + pub fn resize(&mut self, new_size: winit::dpi::PhysicalSize) { if new_size.width > 0 && new_size.height > 0 { self.size = new_size; @@ -260,14 +272,14 @@ async fn run() { let window = WindowBuilder::new().build(&event_loop).unwrap(); // State::new uses async code, so we're going to wait for it to finish - let mut state = State::new(&window).await; + let mut state = State::new(window).await; event_loop.run(move |event, _, control_flow| { match event { Event::WindowEvent { ref event, window_id, - } if window_id == window.id() => { + } if window_id == state.window().id() => { if !state.input(event) { match event { WindowEvent::CloseRequested @@ -291,7 +303,7 @@ async fn run() { } } } - Event::RedrawRequested(window_id) if window_id == window.id() => { + Event::RedrawRequested(window_id) if window_id == state.window().id() => { state.update(); match state.render() { Ok(_) => {} @@ -306,7 +318,7 @@ async fn run() { Event::MainEventsCleared => { // RedrawRequested will only trigger once, unless we manually // request it. - window.request_redraw(); + state.window().request_redraw(); } _ => {} } diff --git a/code/beginner/tutorial3-pipeline/src/lib.rs b/code/beginner/tutorial3-pipeline/src/lib.rs index 8cb217887..97c5aeb9a 100644 --- a/code/beginner/tutorial3-pipeline/src/lib.rs +++ b/code/beginner/tutorial3-pipeline/src/lib.rs @@ -17,16 +17,23 @@ struct State { size: winit::dpi::PhysicalSize, // NEW! render_pipeline: wgpu::RenderPipeline, + window: Window, } impl State { - async fn new(window: &Window) -> Self { + async fn new(window: Window) -> Self { let size = window.inner_size(); // The instance is a handle to our GPU // BackendBit::PRIMARY => Vulkan + Metal + DX12 + Browser WebGPU let instance = wgpu::Instance::new(wgpu::Backends::all()); - let surface = unsafe { instance.create_surface(window) }; + + // # Safety + // + // The surface needs to live as long as the window that created it. + // State owns the window so this should be safe. + let surface = unsafe { instance.create_surface(&window) }; + let adapter = instance .request_adapter(&wgpu::RequestAdapterOptions { power_preference: wgpu::PowerPreference::default(), @@ -127,9 +134,14 @@ impl State { size, config, render_pipeline, + window, } } + pub fn window(&self) -> &Window { + &self.window + } + pub fn resize(&mut self, new_size: winit::dpi::PhysicalSize) { if new_size.width > 0 && new_size.height > 0 { self.size = new_size; @@ -222,14 +234,14 @@ pub async fn run() { } // State::new uses async code, so we're going to wait for it to finish - let mut state = State::new(&window).await; + let mut state = State::new(window).await; event_loop.run(move |event, _, control_flow| { match event { Event::WindowEvent { ref event, window_id, - } if window_id == window.id() => { + } if window_id == state.window().id() => { if !state.input(event) { match event { WindowEvent::CloseRequested @@ -253,7 +265,7 @@ pub async fn run() { } } } - Event::RedrawRequested(window_id) if window_id == window.id() => { + Event::RedrawRequested(window_id) if window_id == state.window().id() => { state.update(); match state.render() { Ok(_) => {} @@ -268,7 +280,7 @@ pub async fn run() { Event::MainEventsCleared => { // RedrawRequested will only trigger once, unless we manually // request it. - window.request_redraw(); + state.window().request_redraw(); } _ => {} } diff --git a/code/beginner/tutorial4-buffer/src/challenge.rs b/code/beginner/tutorial4-buffer/src/challenge.rs index dcc6b10e5..f540cd687 100644 --- a/code/beginner/tutorial4-buffer/src/challenge.rs +++ b/code/beginner/tutorial4-buffer/src/challenge.rs @@ -78,16 +78,23 @@ struct State { use_complex: bool, size: winit::dpi::PhysicalSize, + window: Window, } impl State { - async fn new(window: &Window) -> Self { + async fn new(window: Window) -> Self { let size = window.inner_size(); // The instance is a handle to our GPU // BackendBit::PRIMARY => Vulkan + Metal + DX12 + Browser WebGPU let instance = wgpu::Instance::new(wgpu::Backends::all()); - let surface = unsafe { instance.create_surface(window) }; + + // # Safety + // + // The surface needs to live as long as the window that created it. + // State owns the window so this should be safe. + let surface = unsafe { instance.create_surface(&window) }; + let adapter = instance .request_adapter(&wgpu::RequestAdapterOptions { power_preference: wgpu::PowerPreference::default(), @@ -240,9 +247,14 @@ impl State { num_challenge_indices, use_complex, size, + window, } } + pub fn window(&self) -> &Window { + &self.window + } + pub fn resize(&mut self, new_size: winit::dpi::PhysicalSize) { if new_size.width > 0 && new_size.height > 0 { self.size = new_size; @@ -337,14 +349,14 @@ async fn run() { let window = WindowBuilder::new().build(&event_loop).unwrap(); // State::new uses async code, so we're going to wait for it to finish - let mut state = State::new(&window).await; + let mut state = State::new(window).await; event_loop.run(move |event, _, control_flow| { match event { Event::WindowEvent { ref event, window_id, - } if window_id == window.id() => { + } if window_id == state.window().id() => { if !state.input(event) { match event { WindowEvent::CloseRequested @@ -368,7 +380,7 @@ async fn run() { } } } - Event::RedrawRequested(window_id) if window_id == window.id() => { + Event::RedrawRequested(window_id) if window_id == state.window().id() => { state.update(); match state.render() { Ok(_) => {} @@ -383,7 +395,7 @@ async fn run() { Event::MainEventsCleared => { // RedrawRequested will only trigger once, unless we manually // request it. - window.request_redraw(); + state.window().request_redraw(); } _ => {} } diff --git a/code/beginner/tutorial4-buffer/src/lib.rs b/code/beginner/tutorial4-buffer/src/lib.rs index 18efc6707..d3fa5df14 100644 --- a/code/beginner/tutorial4-buffer/src/lib.rs +++ b/code/beginner/tutorial4-buffer/src/lib.rs @@ -74,16 +74,23 @@ struct State { vertex_buffer: wgpu::Buffer, index_buffer: wgpu::Buffer, num_indices: u32, + window: Window, } impl State { - async fn new(window: &Window) -> Self { + async fn new(window: Window) -> Self { let size = window.inner_size(); // The instance is a handle to our GPU // BackendBit::PRIMARY => Vulkan + Metal + DX12 + Browser WebGPU let instance = wgpu::Instance::new(wgpu::Backends::all()); - let surface = unsafe { instance.create_surface(window) }; + + // # Safety + // + // The surface needs to live as long as the window that created it. + // State owns the window so this should be safe. + let surface = unsafe { instance.create_surface(&window) }; + let adapter = instance .request_adapter(&wgpu::RequestAdapterOptions { power_preference: wgpu::PowerPreference::default(), @@ -199,9 +206,14 @@ impl State { vertex_buffer, index_buffer, num_indices, + window, } } + pub fn window(&self) -> &Window { + &self.window + } + pub fn resize(&mut self, new_size: winit::dpi::PhysicalSize) { if new_size.width > 0 && new_size.height > 0 { self.size = new_size; @@ -296,14 +308,14 @@ pub async fn run() { } // State::new uses async code, so we're going to wait for it to finish - let mut state = State::new(&window).await; + let mut state = State::new(window).await; event_loop.run(move |event, _, control_flow| { match event { Event::WindowEvent { ref event, window_id, - } if window_id == window.id() => { + } if window_id == state.window().id() => { if !state.input(event) { match event { WindowEvent::CloseRequested @@ -327,7 +339,7 @@ pub async fn run() { } } } - Event::RedrawRequested(window_id) if window_id == window.id() => { + Event::RedrawRequested(window_id) if window_id == state.window().id() => { state.update(); match state.render() { Ok(_) => {} @@ -342,7 +354,7 @@ pub async fn run() { Event::MainEventsCleared => { // RedrawRequested will only trigger once, unless we manually // request it. - window.request_redraw(); + state.window().request_redraw(); } _ => {} } diff --git a/code/beginner/tutorial5-textures/src/challenge.rs b/code/beginner/tutorial5-textures/src/challenge.rs index ef957ebb5..fceea15bd 100644 --- a/code/beginner/tutorial5-textures/src/challenge.rs +++ b/code/beginner/tutorial5-textures/src/challenge.rs @@ -80,16 +80,23 @@ struct State { cartoon_texture: texture::Texture, cartoon_bind_group: wgpu::BindGroup, is_space_pressed: bool, + window: Window, } impl State { - async fn new(window: &Window) -> Self { + async fn new(window: Window) -> Self { let size = window.inner_size(); // The instance is a handle to our GPU // BackendBit::PRIMARY => Vulkan + Metal + DX12 + Browser WebGPU let instance = wgpu::Instance::new(wgpu::Backends::all()); - let surface = unsafe { instance.create_surface(window) }; + + // # Safety + // + // The surface needs to live as long as the window that created it. + // State owns the window so this should be safe. + let surface = unsafe { instance.create_surface(&window) }; + let adapter = instance .request_adapter(&wgpu::RequestAdapterOptions { power_preference: wgpu::PowerPreference::default(), @@ -271,9 +278,14 @@ impl State { cartoon_bind_group, size, is_space_pressed: false, + window, } } + pub fn window(&self) -> &Window { + &self.window + } + pub fn resize(&mut self, new_size: winit::dpi::PhysicalSize) { if new_size.width > 0 && new_size.height > 0 { self.size = new_size; @@ -364,14 +376,14 @@ async fn run() { let window = WindowBuilder::new().build(&event_loop).unwrap(); // State::new uses async code, so we're going to wait for it to finish - let mut state = State::new(&window).await; + let mut state = State::new(window).await; event_loop.run(move |event, _, control_flow| { match event { Event::WindowEvent { ref event, window_id, - } if window_id == window.id() => { + } if window_id == state.window().id() => { if !state.input(event) { match event { WindowEvent::CloseRequested @@ -395,7 +407,7 @@ async fn run() { } } } - Event::RedrawRequested(window_id) if window_id == window.id() => { + Event::RedrawRequested(window_id) if window_id == state.window().id() => { state.update(); match state.render() { Ok(_) => {} @@ -410,7 +422,7 @@ async fn run() { Event::MainEventsCleared => { // RedrawRequested will only trigger once, unless we manually // request it. - window.request_redraw(); + state.window().request_redraw(); } _ => {} } diff --git a/code/beginner/tutorial5-textures/src/lib.rs b/code/beginner/tutorial5-textures/src/lib.rs index 3e39e5084..f61fd9fef 100644 --- a/code/beginner/tutorial5-textures/src/lib.rs +++ b/code/beginner/tutorial5-textures/src/lib.rs @@ -80,16 +80,23 @@ struct State { #[allow(dead_code)] diffuse_texture: texture::Texture, diffuse_bind_group: wgpu::BindGroup, + window: Window, } impl State { - async fn new(window: &Window) -> Self { + async fn new(window: Window) -> Self { let size = window.inner_size(); // The instance is a handle to our GPU // BackendBit::PRIMARY => Vulkan + Metal + DX12 + Browser WebGPU let instance = wgpu::Instance::new(wgpu::Backends::all()); - let surface = unsafe { instance.create_surface(window) }; + + // # Safety + // + // The surface needs to live as long as the window that created it. + // State owns the window so this should be safe. + let surface = unsafe { instance.create_surface(&window) }; + let adapter = instance .request_adapter(&wgpu::RequestAdapterOptions { power_preference: wgpu::PowerPreference::default(), @@ -248,9 +255,14 @@ impl State { num_indices, diffuse_texture, diffuse_bind_group, + window, } } + pub fn window(&self) -> &Window { + &self.window + } + pub fn resize(&mut self, new_size: winit::dpi::PhysicalSize) { if new_size.width > 0 && new_size.height > 0 { self.size = new_size; @@ -346,14 +358,14 @@ pub async fn run() { } // State::new uses async code, so we're going to wait for it to finish - let mut state = State::new(&window).await; + let mut state = State::new(window).await; event_loop.run(move |event, _, control_flow| { match event { Event::WindowEvent { ref event, window_id, - } if window_id == window.id() => { + } if window_id == state.window().id() => { if !state.input(event) { match event { WindowEvent::CloseRequested @@ -377,7 +389,7 @@ pub async fn run() { } } } - Event::RedrawRequested(window_id) if window_id == window.id() => { + Event::RedrawRequested(window_id) if window_id == state.window().id() => { state.update(); match state.render() { Ok(_) => {} @@ -392,7 +404,7 @@ pub async fn run() { Event::MainEventsCleared => { // RedrawRequested will only trigger once, unless we manually // request it. - window.request_redraw(); + state.window().request_redraw(); } _ => {} } diff --git a/code/beginner/tutorial6-uniforms/src/challenge.rs b/code/beginner/tutorial6-uniforms/src/challenge.rs index 8b6cf2c33..de1656a36 100644 --- a/code/beginner/tutorial6-uniforms/src/challenge.rs +++ b/code/beginner/tutorial6-uniforms/src/challenge.rs @@ -230,16 +230,23 @@ struct State { camera_buffer: wgpu::Buffer, camera_bind_group: wgpu::BindGroup, size: winit::dpi::PhysicalSize, + window: Window, } impl State { - async fn new(window: &Window) -> Self { + async fn new(window: Window) -> Self { let size = window.inner_size(); // The instance is a handle to our GPU // BackendBit::PRIMARY => Vulkan + Metal + DX12 + Browser WebGPU let instance = wgpu::Instance::new(wgpu::Backends::all()); - let surface = unsafe { instance.create_surface(window) }; + + // # Safety + // + // The surface needs to live as long as the window that created it. + // State owns the window so this should be safe. + let surface = unsafe { instance.create_surface(&window) }; + let adapter = instance .request_adapter(&wgpu::RequestAdapterOptions { power_preference: wgpu::PowerPreference::default(), @@ -448,9 +455,14 @@ impl State { camera_bind_group, camera_uniform, size, + window, } } + pub fn window(&self) -> &Window { + &self.window + } + fn resize(&mut self, new_size: winit::dpi::PhysicalSize) { if new_size.width > 0 && new_size.height > 0 { self.size = new_size; @@ -535,14 +547,14 @@ async fn run() { let window = WindowBuilder::new().build(&event_loop).unwrap(); // State::new uses async code, so we're going to wait for it to finish - let mut state = State::new(&window).await; + let mut state = State::new(window).await; event_loop.run(move |event, _, control_flow| { match event { Event::WindowEvent { ref event, window_id, - } if window_id == window.id() => { + } if window_id == state.window().id() => { if !state.input(event) { match event { WindowEvent::CloseRequested @@ -566,7 +578,7 @@ async fn run() { } } } - Event::RedrawRequested(window_id) if window_id == window.id() => { + Event::RedrawRequested(window_id) if window_id == state.window().id() => { state.update(); match state.render() { Ok(_) => {} @@ -581,7 +593,7 @@ async fn run() { Event::MainEventsCleared => { // RedrawRequested will only trigger once, unless we manually // request it. - window.request_redraw(); + state.window().request_redraw(); } _ => {} } diff --git a/code/beginner/tutorial6-uniforms/src/lib.rs b/code/beginner/tutorial6-uniforms/src/lib.rs index f0fd334fa..8b2bc0212 100644 --- a/code/beginner/tutorial6-uniforms/src/lib.rs +++ b/code/beginner/tutorial6-uniforms/src/lib.rs @@ -230,16 +230,23 @@ struct State { camera_uniform: CameraUniform, camera_buffer: wgpu::Buffer, camera_bind_group: wgpu::BindGroup, + window: Window, } impl State { - async fn new(window: &Window) -> Self { + async fn new(window: Window) -> Self { let size = window.inner_size(); // The instance is a handle to our GPU // BackendBit::PRIMARY => Vulkan + Metal + DX12 + Browser WebGPU let instance = wgpu::Instance::new(wgpu::Backends::all()); - let surface = unsafe { instance.create_surface(window) }; + + // # Safety + // + // The surface needs to live as long as the window that created it. + // State owns the window so this should be safe. + let surface = unsafe { instance.create_surface(&window) }; + let adapter = instance .request_adapter(&wgpu::RequestAdapterOptions { power_preference: wgpu::PowerPreference::default(), @@ -447,9 +454,14 @@ impl State { camera_buffer, camera_bind_group, camera_uniform, + window, } } + pub fn window(&self) -> &Window { + &self.window + } + fn resize(&mut self, new_size: winit::dpi::PhysicalSize) { if new_size.width > 0 && new_size.height > 0 { self.size = new_size; @@ -555,14 +567,14 @@ pub async fn run() { } // State::new uses async code, so we're going to wait for it to finish - let mut state = State::new(&window).await; + let mut state = State::new(window).await; event_loop.run(move |event, _, control_flow| { match event { Event::WindowEvent { ref event, window_id, - } if window_id == window.id() => { + } if window_id == state.window().id() => { if !state.input(event) { match event { WindowEvent::CloseRequested @@ -586,7 +598,7 @@ pub async fn run() { } } } - Event::RedrawRequested(window_id) if window_id == window.id() => { + Event::RedrawRequested(window_id) if window_id == state.window().id() => { state.update(); match state.render() { Ok(_) => {} @@ -601,7 +613,7 @@ pub async fn run() { Event::MainEventsCleared => { // RedrawRequested will only trigger once, unless we manually // request it. - window.request_redraw(); + state.window().request_redraw(); } _ => {} } diff --git a/code/beginner/tutorial7-instancing/src/challenge.rs b/code/beginner/tutorial7-instancing/src/challenge.rs index 7a4772907..55f3232b8 100644 --- a/code/beginner/tutorial7-instancing/src/challenge.rs +++ b/code/beginner/tutorial7-instancing/src/challenge.rs @@ -284,16 +284,23 @@ struct State { size: winit::dpi::PhysicalSize, instances: Vec, instance_buffer: wgpu::Buffer, + window: Window, } impl State { - async fn new(window: &Window) -> Self { + async fn new(window: Window) -> Self { let size = window.inner_size(); // The instance is a handle to our GPU // BackendBit::PRIMARY => Vulkan + Metal + DX12 + Browser WebGPU let instance = wgpu::Instance::new(wgpu::Backends::all()); - let surface = unsafe { instance.create_surface(window) }; + + // # Safety + // + // The surface needs to live as long as the window that created it. + // State owns the window so this should be safe. + let surface = unsafe { instance.create_surface(&window) }; + let adapter = instance .request_adapter(&wgpu::RequestAdapterOptions { power_preference: wgpu::PowerPreference::default(), @@ -535,9 +542,14 @@ impl State { size, instances, instance_buffer, + window, } } + pub fn window(&self) -> &Window { + &self.window + } + fn resize(&mut self, new_size: winit::dpi::PhysicalSize) { if new_size.width > 0 && new_size.height > 0 { self.size = new_size; @@ -636,14 +648,14 @@ async fn run() { let window = WindowBuilder::new().build(&event_loop).unwrap(); // State::new uses async code, so we're going to wait for it to finish - let mut state = State::new(&window).await; + let mut state = State::new(window).await; event_loop.run(move |event, _, control_flow| { match event { Event::WindowEvent { ref event, window_id, - } if window_id == window.id() => { + } if window_id == state.window().id() => { if !state.input(event) { match event { WindowEvent::CloseRequested @@ -667,7 +679,7 @@ async fn run() { } } } - Event::RedrawRequested(window_id) if window_id == window.id() => { + Event::RedrawRequested(window_id) if window_id == state.window().id() => { state.update(); match state.render() { Ok(_) => {} @@ -682,7 +694,7 @@ async fn run() { Event::MainEventsCleared => { // RedrawRequested will only trigger once, unless we manually // request it. - window.request_redraw(); + state.window().request_redraw(); } _ => {} } diff --git a/code/beginner/tutorial7-instancing/src/lib.rs b/code/beginner/tutorial7-instancing/src/lib.rs index e527aa13b..7562fcaf1 100644 --- a/code/beginner/tutorial7-instancing/src/lib.rs +++ b/code/beginner/tutorial7-instancing/src/lib.rs @@ -291,16 +291,23 @@ struct State { instances: Vec, #[allow(dead_code)] instance_buffer: wgpu::Buffer, + window: Window, } impl State { - async fn new(window: &Window) -> Self { + async fn new(window: Window) -> Self { let size = window.inner_size(); // The instance is a handle to our GPU // BackendBit::PRIMARY => Vulkan + Metal + DX12 + Browser WebGPU let instance = wgpu::Instance::new(wgpu::Backends::all()); - let surface = unsafe { instance.create_surface(window) }; + + // # Safety + // + // The surface needs to live as long as the window that created it. + // State owns the window so this should be safe. + let surface = unsafe { instance.create_surface(&window) }; + let adapter = instance .request_adapter(&wgpu::RequestAdapterOptions { power_preference: wgpu::PowerPreference::default(), @@ -540,12 +547,17 @@ impl State { camera_buffer, camera_bind_group, camera_uniform, + window, // NEW! instances, instance_buffer, } } + pub fn window(&self) -> &Window { + &self.window + } + fn resize(&mut self, new_size: winit::dpi::PhysicalSize) { if new_size.width > 0 && new_size.height > 0 { self.size = new_size; @@ -653,14 +665,14 @@ pub async fn run() { } // State::new uses async code, so we're going to wait for it to finish - let mut state = State::new(&window).await; + let mut state = State::new(window).await; event_loop.run(move |event, _, control_flow| { match event { Event::WindowEvent { ref event, window_id, - } if window_id == window.id() => { + } if window_id == state.window().id() => { if !state.input(event) { match event { WindowEvent::CloseRequested @@ -684,7 +696,7 @@ pub async fn run() { } } } - Event::RedrawRequested(window_id) if window_id == window.id() => { + Event::RedrawRequested(window_id) if window_id == state.window().id() => { state.update(); match state.render() { Ok(_) => {} @@ -699,7 +711,7 @@ pub async fn run() { Event::MainEventsCleared => { // RedrawRequested will only trigger once, unless we manually // request it. - window.request_redraw(); + state.window().request_redraw(); } _ => {} } diff --git a/code/beginner/tutorial8-depth/src/challenge.rs b/code/beginner/tutorial8-depth/src/challenge.rs index 60e0e60df..2a61d7b98 100644 --- a/code/beginner/tutorial8-depth/src/challenge.rs +++ b/code/beginner/tutorial8-depth/src/challenge.rs @@ -472,16 +472,23 @@ struct State { #[allow(dead_code)] instance_buffer: wgpu::Buffer, depth_pass: DepthPass, + window: Window, } impl State { - async fn new(window: &Window) -> Self { + async fn new(window: Window) -> Self { let size = window.inner_size(); // The instance is a handle to our GPU // BackendBit::PRIMARY => Vulkan + Metal + DX12 + Browser WebGPU let instance = wgpu::Instance::new(wgpu::Backends::all()); - let surface = unsafe { instance.create_surface(window) }; + + // # Safety + // + // The surface needs to live as long as the window that created it. + // State owns the window so this should be safe. + let surface = unsafe { instance.create_surface(&window) }; + let adapter = instance .request_adapter(&wgpu::RequestAdapterOptions { power_preference: wgpu::PowerPreference::default(), @@ -732,12 +739,18 @@ impl State { camera_buffer, camera_bind_group, camera_uniform, + window, size, instances, instance_buffer, depth_pass, } } + + pub fn window(&self) -> &Window { + &self.window + } + pub fn resize(&mut self, new_size: winit::dpi::PhysicalSize) { if new_size.width > 0 && new_size.height > 0 { self.size = new_size; @@ -831,14 +844,14 @@ async fn run() { let window = WindowBuilder::new().build(&event_loop).unwrap(); // State::new uses async code, so we're going to wait for it to finish - let mut state = State::new(&window).await; + let mut state = State::new(window).await; event_loop.run(move |event, _, control_flow| { match event { Event::WindowEvent { ref event, window_id, - } if window_id == window.id() => { + } if window_id == state.window().id() => { if !state.input(event) { match event { WindowEvent::CloseRequested @@ -862,7 +875,7 @@ async fn run() { } } } - Event::RedrawRequested(window_id) if window_id == window.id() => { + Event::RedrawRequested(window_id) if window_id == state.window().id() => { state.update(); match state.render() { Ok(_) => {} @@ -877,7 +890,7 @@ async fn run() { Event::MainEventsCleared => { // RedrawRequested will only trigger once, unless we manually // request it. - window.request_redraw(); + state.window().request_redraw(); } _ => {} } diff --git a/code/beginner/tutorial8-depth/src/lib.rs b/code/beginner/tutorial8-depth/src/lib.rs index 1a9d839b4..d2315db02 100644 --- a/code/beginner/tutorial8-depth/src/lib.rs +++ b/code/beginner/tutorial8-depth/src/lib.rs @@ -301,16 +301,23 @@ struct State { instance_buffer: wgpu::Buffer, // NEW! depth_texture: texture::Texture, + window: Window, } impl State { - async fn new(window: &Window) -> Self { + async fn new(window: Window) -> Self { let size = window.inner_size(); // The instance is a handle to our GPU // BackendBit::PRIMARY => Vulkan + Metal + DX12 + Browser WebGPU let instance = wgpu::Instance::new(wgpu::Backends::all()); - let surface = unsafe { instance.create_surface(window) }; + + // # Safety + // + // The surface needs to live as long as the window that created it. + // State owns the window so this should be safe. + let surface = unsafe { instance.create_surface(&window) }; + let adapter = instance .request_adapter(&wgpu::RequestAdapterOptions { power_preference: wgpu::PowerPreference::default(), @@ -562,9 +569,14 @@ impl State { instances, instance_buffer, depth_texture, + window, } } + pub fn window(&self) -> &Window { + &self.window + } + fn resize(&mut self, new_size: winit::dpi::PhysicalSize) { if new_size.width > 0 && new_size.height > 0 { self.size = new_size; @@ -680,14 +692,14 @@ pub async fn run() { } // State::new uses async code, so we're going to wait for it to finish - let mut state = State::new(&window).await; + let mut state = State::new(window).await; event_loop.run(move |event, _, control_flow| { match event { Event::WindowEvent { ref event, window_id, - } if window_id == window.id() => { + } if window_id == state.window().id() => { if !state.input(event) { match event { WindowEvent::CloseRequested @@ -711,7 +723,7 @@ pub async fn run() { } } } - Event::RedrawRequested(window_id) if window_id == window.id() => { + Event::RedrawRequested(window_id) if window_id == state.window().id() => { state.update(); match state.render() { Ok(_) => {} @@ -726,7 +738,7 @@ pub async fn run() { Event::MainEventsCleared => { // RedrawRequested will only trigger once, unless we manually // request it. - window.request_redraw(); + state.window().request_redraw(); } _ => {} } diff --git a/code/beginner/tutorial9-models/src/lib.rs b/code/beginner/tutorial9-models/src/lib.rs index b345a8737..01c68b01f 100644 --- a/code/beginner/tutorial9-models/src/lib.rs +++ b/code/beginner/tutorial9-models/src/lib.rs @@ -240,17 +240,24 @@ struct State { #[allow(dead_code)] instance_buffer: wgpu::Buffer, depth_texture: texture::Texture, + window: Window, } impl State { - async fn new(window: &Window) -> Self { + async fn new(window: Window) -> Self { let size = window.inner_size(); // The instance is a handle to our GPU // BackendBit::PRIMARY => Vulkan + Metal + DX12 + Browser WebGPU log::warn!("WGPU setup"); let instance = wgpu::Instance::new(wgpu::Backends::all()); - let surface = unsafe { instance.create_surface(window) }; + + // # Safety + // + // The surface needs to live as long as the window that created it. + // State owns the window so this should be safe. + let surface = unsafe { instance.create_surface(&window) }; + let adapter = instance .request_adapter(&wgpu::RequestAdapterOptions { power_preference: wgpu::PowerPreference::default(), @@ -477,9 +484,14 @@ impl State { instances, instance_buffer, depth_texture, + window, } } + pub fn window(&self) -> &Window { + &self.window + } + fn resize(&mut self, new_size: winit::dpi::PhysicalSize) { if new_size.width > 0 && new_size.height > 0 { self.camera.aspect = self.config.width as f32 / self.config.height as f32; @@ -598,16 +610,16 @@ pub async fn run() { } // State::new uses async code, so we're going to wait for it to finish - let mut state = State::new(&window).await; + let mut state = State::new(window).await; event_loop.run(move |event, _, control_flow| { *control_flow = ControlFlow::Poll; match event { - Event::MainEventsCleared => window.request_redraw(), + Event::MainEventsCleared => state.window().request_redraw(), Event::WindowEvent { ref event, window_id, - } if window_id == window.id() => { + } if window_id == state.window().id() => { if !state.input(event) { match event { WindowEvent::CloseRequested @@ -630,7 +642,7 @@ pub async fn run() { } } } - Event::RedrawRequested(window_id) if window_id == window.id() => { + Event::RedrawRequested(window_id) if window_id == state.window().id() => { state.update(); match state.render() { Ok(_) => {} diff --git a/code/intermediate/tutorial10-lighting/src/lib.rs b/code/intermediate/tutorial10-lighting/src/lib.rs index 4ffca3562..a9a1a18e0 100644 --- a/code/intermediate/tutorial10-lighting/src/lib.rs +++ b/code/intermediate/tutorial10-lighting/src/lib.rs @@ -256,6 +256,7 @@ struct LightUniform { } struct State { + window: Window, surface: wgpu::Surface, device: wgpu::Device, queue: wgpu::Queue, @@ -339,13 +340,19 @@ fn create_render_pipeline( } impl State { - async fn new(window: &Window) -> Self { + async fn new(window: Window) -> Self { let size = window.inner_size(); // The instance is a handle to our GPU // BackendBit::PRIMARY => Vulkan + Metal + DX12 + Browser WebGPU let instance = wgpu::Instance::new(wgpu::Backends::all()); - let surface = unsafe { instance.create_surface(window) }; + + // # Safety + // + // The surface needs to live as long as the window that created it. + // State owns the window so this should be safe. + let surface = unsafe { instance.create_surface(&window) }; + let adapter = instance .request_adapter(&wgpu::RequestAdapterOptions { power_preference: wgpu::PowerPreference::default(), @@ -594,9 +601,14 @@ impl State { light_buffer, light_bind_group, light_render_pipeline, + window, } } + pub fn window(&self) -> &Window { + &self.window + } + fn resize(&mut self, new_size: winit::dpi::PhysicalSize) { if new_size.width > 0 && new_size.height > 0 { self.camera.aspect = self.config.width as f32 / self.config.height as f32; @@ -738,16 +750,16 @@ pub async fn run() { } // State::new uses async code, so we're going to wait for it to finish - let mut state = State::new(&window).await; + let mut state = State::new(window).await; event_loop.run(move |event, _, control_flow| { *control_flow = ControlFlow::Poll; match event { - Event::MainEventsCleared => window.request_redraw(), + Event::MainEventsCleared => state.window().request_redraw(), Event::WindowEvent { ref event, window_id, - } if window_id == window.id() => { + } if window_id == state.window().id() => { if !state.input(event) { match event { WindowEvent::CloseRequested @@ -770,7 +782,7 @@ pub async fn run() { } } } - Event::RedrawRequested(window_id) if window_id == window.id() => { + Event::RedrawRequested(window_id) if window_id == state.window().id() => { state.update(); match state.render() { Ok(_) => {} diff --git a/code/intermediate/tutorial11-normals/src/lib.rs b/code/intermediate/tutorial11-normals/src/lib.rs index 0090947be..8540a7548 100644 --- a/code/intermediate/tutorial11-normals/src/lib.rs +++ b/code/intermediate/tutorial11-normals/src/lib.rs @@ -254,6 +254,7 @@ struct LightUniform { } struct State { + window: Window, surface: wgpu::Surface, device: wgpu::Device, queue: wgpu::Queue, @@ -339,13 +340,19 @@ fn create_render_pipeline( } impl State { - async fn new(window: &Window) -> Self { + async fn new(window: Window) -> Self { let size = window.inner_size(); // The instance is a handle to our GPU // BackendBit::PRIMARY => Vulkan + Metal + DX12 + Browser WebGPU let instance = wgpu::Instance::new(wgpu::Backends::all()); - let surface = unsafe { instance.create_surface(window) }; + + // # Safety + // + // The surface needs to live as long as the window that created it. + // State owns the window so this should be safe. + let surface = unsafe { instance.create_surface(&window) }; + let adapter = instance .request_adapter(&wgpu::RequestAdapterOptions { power_preference: wgpu::PowerPreference::default(), @@ -624,6 +631,7 @@ impl State { }; Self { + window, surface, device, queue, @@ -648,6 +656,10 @@ impl State { } } + pub fn window(&self) -> &Window { + &self.window + } + fn resize(&mut self, new_size: winit::dpi::PhysicalSize) { if new_size.width > 0 && new_size.height > 0 { self.camera.aspect = self.config.width as f32 / self.config.height as f32; @@ -786,16 +798,16 @@ pub async fn run() { } // State::new uses async code, so we're going to wait for it to finish - let mut state = State::new(&window).await; + let mut state = State::new(window).await; event_loop.run(move |event, _, control_flow| { *control_flow = ControlFlow::Poll; match event { - Event::MainEventsCleared => window.request_redraw(), + Event::MainEventsCleared => state.window().request_redraw(), Event::WindowEvent { ref event, window_id, - } if window_id == window.id() => { + } if window_id == state.window().id() => { if !state.input(event) { match event { WindowEvent::CloseRequested @@ -818,7 +830,7 @@ pub async fn run() { } } } - Event::RedrawRequested(window_id) if window_id == window.id() => { + Event::RedrawRequested(window_id) if window_id == state.window().id() => { state.update(); match state.render() { Ok(_) => {} diff --git a/code/intermediate/tutorial12-camera/src/lib.rs b/code/intermediate/tutorial12-camera/src/lib.rs index 81026f519..a0effea02 100644 --- a/code/intermediate/tutorial12-camera/src/lib.rs +++ b/code/intermediate/tutorial12-camera/src/lib.rs @@ -131,6 +131,7 @@ struct LightUniform { } struct State { + window: Window, surface: wgpu::Surface, device: wgpu::Device, queue: wgpu::Queue, @@ -219,13 +220,19 @@ fn create_render_pipeline( } impl State { - async fn new(window: &Window) -> Self { + async fn new(window: Window) -> Self { let size = window.inner_size(); // The instance is a handle to our GPU // BackendBit::PRIMARY => Vulkan + Metal + DX12 + Browser WebGPU let instance = wgpu::Instance::new(wgpu::Backends::all()); - let surface = unsafe { instance.create_surface(window) }; + + // # Safety + // + // The surface needs to live as long as the window that created it. + // State owns the window so this should be safe. + let surface = unsafe { instance.create_surface(&window) }; + let adapter = instance .request_adapter(&wgpu::RequestAdapterOptions { power_preference: wgpu::PowerPreference::default(), @@ -494,6 +501,7 @@ impl State { }; Self { + window, surface, device, queue, @@ -521,6 +529,10 @@ impl State { } } + pub fn window(&self) -> &Window { + &self.window + } + fn resize(&mut self, new_size: winit::dpi::PhysicalSize) { // UPDATED! if new_size.width > 0 && new_size.height > 0 { @@ -684,12 +696,12 @@ pub async fn run() { .expect("Couldn't append canvas to document body."); } - let mut state = State::new(&window).await; // NEW! + let mut state = State::new(window).await; // NEW! let mut last_render_time = instant::Instant::now(); event_loop.run(move |event, _, control_flow| { *control_flow = ControlFlow::Poll; match event { - Event::MainEventsCleared => window.request_redraw(), + Event::MainEventsCleared => state.window().request_redraw(), // NEW! Event::DeviceEvent { event: DeviceEvent::MouseMotion{ delta, }, @@ -701,7 +713,7 @@ pub async fn run() { Event::WindowEvent { ref event, window_id, - } if window_id == window.id() && !state.input(event) => { + } if window_id == state.window().id() && !state.input(event) => { match event { #[cfg(not(target_arch="wasm32"))] WindowEvent::CloseRequested @@ -724,7 +736,7 @@ pub async fn run() { } } // UPDATED! - Event::RedrawRequested(window_id) if window_id == window.id() => { + Event::RedrawRequested(window_id) if window_id == state.window().id() => { let now = instant::Instant::now(); let dt = now - last_render_time; last_render_time = now; diff --git a/code/intermediate/tutorial13-terrain/src/lib.rs b/code/intermediate/tutorial13-terrain/src/lib.rs index 144c5c192..cbb0f55f0 100644 --- a/code/intermediate/tutorial13-terrain/src/lib.rs +++ b/code/intermediate/tutorial13-terrain/src/lib.rs @@ -132,6 +132,7 @@ struct LightUniform { } struct State { + window: Window, surface: wgpu::Surface, device: wgpu::Device, queue: wgpu::Queue, @@ -221,13 +222,19 @@ fn create_render_pipeline( } impl State { - async fn new(window: &Window) -> Self { + async fn new(window: Window) -> Self { let size = window.inner_size(); // The instance is a handle to our GPU // BackendBit::PRIMARY => Vulkan + Metal + DX12 + Browser WebGPU let instance = wgpu::Instance::new(wgpu::Backends::all()); - let surface = unsafe { instance.create_surface(window) }; + + // # Safety + // + // The surface needs to live as long as the window that created it. + // State owns the window so this should be safe. + let surface = unsafe { instance.create_surface(&window) }; + let adapter = instance .request_adapter(&wgpu::RequestAdapterOptions { power_preference: wgpu::PowerPreference::default(), @@ -526,6 +533,7 @@ impl State { // terrain.gen_chunk(&device, &queue, &terrain_hack_pipeline, (-(chunk_size.x as f32), 0.0, 0.0).into()); Self { + window, surface, device, queue, @@ -556,6 +564,10 @@ impl State { } } + pub fn window(&self) -> &Window { + &self.window + } + fn resize(&mut self, new_size: winit::dpi::PhysicalSize) { // UPDATED! if new_size.width > 0 && new_size.height > 0 { @@ -722,13 +734,13 @@ pub async fn run() { .expect("Couldn't append canvas to document body."); } - let mut state = State::new(&window).await; // NEW! - window.set_visible(true); + let mut state = State::new(window).await; // NEW! + state.window().set_visible(true); let mut last_render_time = instant::Instant::now(); event_loop.run(move |event, _, control_flow| { *control_flow = ControlFlow::Poll; match event { - Event::MainEventsCleared => window.request_redraw(), + Event::MainEventsCleared => state.window().request_redraw(), // NEW! Event::DeviceEvent { event: DeviceEvent::MouseMotion{ delta, }, @@ -740,7 +752,7 @@ pub async fn run() { Event::WindowEvent { ref event, window_id, - } if window_id == window.id() && !state.input(event) => { + } if window_id == state.window().id() && !state.input(event) => { match event { #[cfg(not(target_arch="wasm32"))] WindowEvent::CloseRequested @@ -763,7 +775,7 @@ pub async fn run() { } } // UPDATED! - Event::RedrawRequested(window_id) if window_id == window.id() => { + Event::RedrawRequested(window_id) if window_id == state.window().id() => { let now = instant::Instant::now(); let dt = now - last_render_time; last_render_time = now; diff --git a/code/showcase/compute/src/main.rs b/code/showcase/compute/src/main.rs index 61779210f..95f4e35cd 100644 --- a/code/showcase/compute/src/main.rs +++ b/code/showcase/compute/src/main.rs @@ -155,16 +155,23 @@ struct State { debug_material: model::Material, last_mouse_pos: PhysicalPosition, mouse_pressed: bool, + window: Window, } impl State { - async fn new(window: &Window) -> Self { + async fn new(window: Window) -> Self { let size = window.inner_size(); // The instance is a handle to our GPU // BackendBit::PRIMARY => Vulkan + Metal + DX12 + Browser WebGPU let instance = wgpu::Instance::new(wgpu::Backends::all()); - let surface = unsafe { instance.create_surface(window) }; + + // # Safety + // + // The surface needs to live as long as the window that created it. + // State owns the window so this should be safe. + let surface = unsafe { instance.create_surface(&window) }; + let adapter = instance .request_adapter(&wgpu::RequestAdapterOptions { power_preference: wgpu::PowerPreference::default(), @@ -438,6 +445,7 @@ impl State { }; Self { + window, surface, device, queue, @@ -465,6 +473,10 @@ impl State { } } + pub fn window(&self) -> &Window { + &self.window + } + fn resize(&mut self, new_size: winit::dpi::PhysicalSize) { if new_size.width > 0 && new_size.height > 0 { self.projection.resize(new_size.width, new_size.height); @@ -614,16 +626,16 @@ async fn run() { .with_title(title) .build(&event_loop) .unwrap(); - let mut state = State::new(&window).await; // NEW! + let mut state = State::new(window).await; // NEW! let mut last_render_time = std::time::Instant::now(); event_loop.run(move |event, _, control_flow| { *control_flow = ControlFlow::Poll; match event { - Event::MainEventsCleared => window.request_redraw(), + Event::MainEventsCleared => state.window().request_redraw(), Event::WindowEvent { ref event, window_id, - } if window_id == window.id() => { + } if window_id == state.window().id() => { if !state.input(event) { match event { WindowEvent::CloseRequested @@ -646,7 +658,7 @@ async fn run() { } } } - Event::RedrawRequested(window_id) if window_id == window.id() => { + Event::RedrawRequested(window_id) if window_id == state.window().id() => { let now = std::time::Instant::now(); let dt = now - last_render_time; last_render_time = now; diff --git a/code/showcase/framework/src/lib.rs b/code/showcase/framework/src/lib.rs index 049cbee19..213208bee 100644 --- a/code/showcase/framework/src/lib.rs +++ b/code/showcase/framework/src/lib.rs @@ -80,6 +80,10 @@ impl Display { }) } + pub fn window(&self) -> &Window { + &self.window + } + pub fn resize(&mut self, width: u32, height: u32) { self.config.width = width; self.config.height = height; @@ -222,7 +226,7 @@ pub async fn run() -> Result<(), Error> { Event::Resumed => is_resumed = true, Event::Suspended => is_resumed = false, Event::RedrawRequested(wid) => { - if wid == display.window.id() { + if wid == display.window().id() { let now = Instant::now(); let dt = now - last_update; last_update = now; @@ -234,7 +238,7 @@ pub async fn run() -> Result<(), Error> { } Event::MainEventsCleared => { if is_focused && is_resumed && !is_redraw_requested { - display.window.request_redraw(); + display.window().request_redraw(); is_redraw_requested = true; } else { // Freeze time while the demo is not in the foreground @@ -244,7 +248,7 @@ pub async fn run() -> Result<(), Error> { Event::WindowEvent { event, window_id, .. } => { - if window_id == display.window.id() { + if window_id == display.window().id() { match event { WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit, WindowEvent::Focused(f) => is_focused = f, diff --git a/code/showcase/mouse-picking/src/lib.rs b/code/showcase/mouse-picking/src/lib.rs index cdb0bd6e5..b26acb820 100644 --- a/code/showcase/mouse-picking/src/lib.rs +++ b/code/showcase/mouse-picking/src/lib.rs @@ -132,6 +132,7 @@ struct LightUniform { } struct State { + window: Window, surface: wgpu::Surface, device: wgpu::Device, queue: wgpu::Queue, @@ -224,13 +225,19 @@ fn create_render_pipeline( } impl State { - async fn new(window: &Window) -> Self { + async fn new(window: Window) -> Self { let size = window.inner_size(); // The instance is a handle to our GPU // BackendBit::PRIMARY => Vulkan + Metal + DX12 + Browser WebGPU let instance = wgpu::Instance::new(wgpu::Backends::all()); - let surface = unsafe { instance.create_surface(window) }; + + // # Safety + // + // The surface needs to live as long as the window that created it. + // State owns the window so this should be safe. + let surface = unsafe { instance.create_surface(&window) }; + let adapter = instance .request_adapter(&wgpu::RequestAdapterOptions { power_preference: wgpu::PowerPreference::default(), @@ -503,6 +510,7 @@ impl State { let mouse_matrix = cgmath::Matrix4::identity(); Self { + window, surface, device, queue, @@ -534,6 +542,10 @@ impl State { } } + pub fn window(&self) -> &Window { + &self.window + } + fn resize(&mut self, new_size: winit::dpi::PhysicalSize) { // UPDATED! if new_size.width > 0 && new_size.height > 0 { @@ -726,12 +738,12 @@ pub async fn run() { .expect("Couldn't append canvas to document body."); } - let mut state = State::new(&window).await; // NEW! + let mut state = State::new(window).await; // NEW! let mut last_render_time = instant::Instant::now(); event_loop.run(move |event, _, control_flow| { *control_flow = ControlFlow::Poll; match event { - Event::MainEventsCleared => window.request_redraw(), + Event::MainEventsCleared => state.window().request_redraw(), // NEW! Event::DeviceEvent { event: DeviceEvent::MouseMotion{ delta, }, @@ -743,7 +755,7 @@ pub async fn run() { Event::WindowEvent { ref event, window_id, - } if window_id == window.id() && !state.input(event) => { + } if window_id == state.window().id() && !state.input(event) => { match event { #[cfg(not(target_arch="wasm32"))] WindowEvent::CloseRequested @@ -766,7 +778,7 @@ pub async fn run() { } } // UPDATED! - Event::RedrawRequested(window_id) if window_id == window.id() => { + Event::RedrawRequested(window_id) if window_id == state.window().id() => { let now = instant::Instant::now(); let dt = now - last_render_time; last_render_time = now; diff --git a/code/showcase/pong/src/lib.rs b/code/showcase/pong/src/lib.rs index 98f3da82d..d735c3132 100644 --- a/code/showcase/pong/src/lib.rs +++ b/code/showcase/pong/src/lib.rs @@ -153,7 +153,7 @@ pub fn start() { menu_system.start(&mut state); - window.set_visible(true); + state.window().set_visible(true); log::info!("Event Loop..."); @@ -198,7 +198,7 @@ pub fn start() { render.resize(size); events.push(state::Event::Resize(size.width as f32, size.height as f32)); } - Event::RedrawRequested(window_id) if window_id == window.id() => { + Event::RedrawRequested(window_id) if window_id == state.window().id() => { for event in &events { match event { state::Event::FocusChanged | state::Event::ButtonPressed => { @@ -255,7 +255,7 @@ pub fn start() { render.render_state(&state); if state.game_state != state::GameState::Quiting { - window.request_redraw(); + state.window().request_redraw(); } } _ => {} diff --git a/code/showcase/pong/src/render/mod.rs b/code/showcase/pong/src/render/mod.rs index 22c8207f4..06c80d269 100644 --- a/code/showcase/pong/src/render/mod.rs +++ b/code/showcase/pong/src/render/mod.rs @@ -41,7 +41,13 @@ impl Render { // The instance is a handle to our GPU // BackendBit::PRIMARY => Vulkan + Metal + DX12 + Browser WebGPU let instance = wgpu::Instance::new(wgpu::Backends::all()); - let surface = unsafe { instance.create_surface(window) }; + + // # Safety + // + // The surface needs to live as long as the window that created it. + // State owns the window so this should be safe. + let surface = unsafe { instance.create_surface(&window) }; + let adapter = instance .request_adapter(&wgpu::RequestAdapterOptions { power_preference: wgpu::PowerPreference::default(), diff --git a/code/showcase/threading/src/lib.rs b/code/showcase/threading/src/lib.rs index 062dbb692..8f91e0fec 100644 --- a/code/showcase/threading/src/lib.rs +++ b/code/showcase/threading/src/lib.rs @@ -131,6 +131,7 @@ struct LightUniform { } struct State { + window: Window, surface: wgpu::Surface, device: wgpu::Device, queue: wgpu::Queue, @@ -218,13 +219,19 @@ fn create_render_pipeline( } impl State { - async fn new(window: &Window) -> Self { + async fn new(window: Window) -> Self { let size = window.inner_size(); // The instance is a handle to our GPU // BackendBit::PRIMARY => Vulkan + Metal + DX12 + Browser WebGPU let instance = wgpu::Instance::new(wgpu::Backends::all()); - let surface = unsafe { instance.create_surface(window) }; + + // # Safety + // + // The surface needs to live as long as the window that created it. + // State owns the window so this should be safe. + let surface = unsafe { instance.create_surface(&window) }; + let adapter = instance .request_adapter(&wgpu::RequestAdapterOptions { power_preference: wgpu::PowerPreference::default(), @@ -506,6 +513,7 @@ impl State { }; Self { + window, surface, device, queue, @@ -532,6 +540,10 @@ impl State { } } + pub fn window(&self) -> &Window { + &self.window + } + fn resize(&mut self, new_size: winit::dpi::PhysicalSize) { if new_size.width > 0 && new_size.height > 0 { self.projection.resize(new_size.width, new_size.height); @@ -692,12 +704,12 @@ pub async fn run() { .expect("Couldn't append canvas to document body."); } - let mut state = State::new(&window).await; // NEW! + let mut state = State::new(window).await; // NEW! let mut last_render_time = instant::Instant::now(); event_loop.run(move |event, _, control_flow| { *control_flow = ControlFlow::Poll; match event { - Event::MainEventsCleared => window.request_redraw(), + Event::MainEventsCleared => state.window().request_redraw(), // NEW! Event::DeviceEvent { event: DeviceEvent::MouseMotion{ delta, }, @@ -709,7 +721,7 @@ pub async fn run() { Event::WindowEvent { ref event, window_id, - } if window_id == window.id() && !state.input(event) => { + } if window_id == state.window().id() && !state.input(event) => { match event { #[cfg(not(target_arch="wasm32"))] WindowEvent::CloseRequested @@ -731,7 +743,7 @@ pub async fn run() { _ => {} } } - Event::RedrawRequested(window_id) if window_id == window.id() => { + Event::RedrawRequested(window_id) if window_id == state.window().id() => { let now = instant::Instant::now(); let dt = now - last_render_time; last_render_time = now; diff --git a/docs/beginner/tutorial2-surface/README.md b/docs/beginner/tutorial2-surface/README.md index b10b3e2ca..2daa72cab 100644 --- a/docs/beginner/tutorial2-surface/README.md +++ b/docs/beginner/tutorial2-surface/README.md @@ -13,14 +13,19 @@ struct State { queue: wgpu::Queue, config: wgpu::SurfaceConfiguration, size: winit::dpi::PhysicalSize, + window: Window, } impl State { // Creating some of the wgpu types requires async code - async fn new(window: &Window) -> Self { + async fn new(window: Window) -> Self { todo!() } + pub fn window(&self) -> &Window { + &self.window + } + fn resize(&mut self, new_size: winit::dpi::PhysicalSize) { todo!() } @@ -47,13 +52,19 @@ The code for this is pretty straightforward, but let's break it down a bit. ```rust impl State { // ... - async fn new(window: &Window) -> Self { + async fn new(window: Window) -> Self { let size = window.inner_size(); // The instance is a handle to our GPU // Backends::all => Vulkan + Metal + DX12 + Browser WebGPU let instance = wgpu::Instance::new(wgpu::Backends::all()); - let surface = unsafe { instance.create_surface(window) }; + + // # Safety + // + // The surface needs to live as long as the window that created it. + // State owns the window so this should be safe. + let surface = unsafe { instance.create_surface(&window) }; + let adapter = instance.request_adapter( &wgpu::RequestAdapterOptions { power_preference: wgpu::PowerPreference::default(), @@ -177,6 +188,7 @@ Now that we've configured our surface properly we can add these new fields at th ```rust Self { + window, surface, device, queue, @@ -194,7 +206,7 @@ Since our `State::new()` method is async we need to change `run()` to be async a pub async fn run() { // Window setup... - let mut state = State::new(&window).await; + let mut state = State::new(window).await; // Event loop... } @@ -269,7 +281,7 @@ We call this method in `run()` in the event loop for the following events. match event { // ... - } if window_id == window.id() => if !state.input(event) { + } if window_id == state.window().id() => if !state.input(event) { match event { // ... @@ -306,7 +318,7 @@ event_loop.run(move |event, _, control_flow| { Event::WindowEvent { ref event, window_id, - } if window_id == window.id() => if !state.input(event) { // UPDATED! + } if window_id == state.window().id() => if !state.input(event) { // UPDATED! match event { WindowEvent::CloseRequested | WindowEvent::KeyboardInput { @@ -413,7 +425,7 @@ We need to update the event loop again to call this method. We'll also call `upd event_loop.run(move |event, _, control_flow| { match event { // ... - Event::RedrawRequested(window_id) if window_id == window.id() => { + Event::RedrawRequested(window_id) if window_id == state.window().id() => { state.update(); match state.render() { Ok(_) => {} @@ -428,7 +440,7 @@ event_loop.run(move |event, _, control_flow| { Event::MainEventsCleared => { // RedrawRequested will only trigger once, unless we manually // request it. - window.request_redraw(); + state.window().request_redraw(); } // ... } diff --git a/docs/beginner/tutorial6-uniforms/README.md b/docs/beginner/tutorial6-uniforms/README.md index 7ec9d2962..8444b7b3a 100644 --- a/docs/beginner/tutorial6-uniforms/README.md +++ b/docs/beginner/tutorial6-uniforms/README.md @@ -64,7 +64,7 @@ struct State { // ... } -async fn new(window: &Window) -> Self { +async fn new(window: Window) -> Self { // let diffuse_bind_group ... let camera = Camera { @@ -203,7 +203,7 @@ struct State { camera_bind_group: wgpu::BindGroup, } -async fn new(window: &Window) -> Self { +async fn new(window: Window) -> Self { // ... Self { // ... @@ -375,7 +375,7 @@ struct State { } // ... impl State { - async fn new(window: &Window) -> Self { + async fn new(window: Window) -> Self { // ... let camera_controller = CameraController::new(0.2); // ... diff --git a/docs/beginner/tutorial7-instancing/README.md b/docs/beginner/tutorial7-instancing/README.md index 94d2ff5eb..8f0a8434c 100644 --- a/docs/beginner/tutorial7-instancing/README.md +++ b/docs/beginner/tutorial7-instancing/README.md @@ -98,7 +98,7 @@ Now we can create the actual instances. ```rust impl State { - async fn new(window: &Window) -> Self { + async fn new(window: Window) -> Self { // ... let instances = (0..NUM_INSTANCES_PER_ROW).flat_map(|z| { (0..NUM_INSTANCES_PER_ROW).map(move |x| { diff --git a/docs/beginner/tutorial8-depth/README.md b/docs/beginner/tutorial8-depth/README.md index b9bf90857..c6c9c4b44 100644 --- a/docs/beginner/tutorial8-depth/README.md +++ b/docs/beginner/tutorial8-depth/README.md @@ -123,7 +123,7 @@ struct State { // ... } -async fn new(window: &Window) -> Self { +async fn new(window: Window) -> Self { // ... Self { diff --git a/docs/intermediate/tutorial12-camera/README.md b/docs/intermediate/tutorial12-camera/README.md index 6e6a99f03..12e63aea9 100644 --- a/docs/intermediate/tutorial12-camera/README.md +++ b/docs/intermediate/tutorial12-camera/README.md @@ -294,7 +294,7 @@ We need to update `new()` as well. ```rust impl State { - async fn new(window: &Window) -> Self { + async fn new(window: Window) -> Self { // ... // UPDATED! @@ -384,7 +384,7 @@ fn main() { Event::WindowEvent { ref event, window_id, - } if window_id == window.id() && !state.input(event) => { + } if window_id == state.window().id() && !state.input(event) => { match event { #[cfg(not(target_arch="wasm32"))] WindowEvent::CloseRequested @@ -437,14 +437,14 @@ We still need to calculate `dt`. Let's do that in the `main` function. ```rust fn main() { // ... - let mut state = State::new(&window).await; + let mut state = State::new(window).await; let mut last_render_time = instant::Instant::now(); // NEW! event_loop.run(move |event, _, control_flow| { *control_flow = ControlFlow::Poll; match event { // ... // UPDATED! - Event::RedrawRequested(window_id) if window_id == window.id() => { + Event::RedrawRequested(window_id) if window_id == state.window().id() => { let now = instant::Instant::now(); let dt = now - last_render_time; last_render_time = now;