From 3d386a77b406ee65d6965ad91b29ea3acb8bcf3a Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Mon, 7 Dec 2020 13:32:57 -0800 Subject: [PATCH] attempt to deal with rounding issue when creating the swap chain (#997) attempt to deal with rounding issue when creating the swap chain on high DPI displays --- crates/bevy_render/src/camera/camera.rs | 2 +- crates/bevy_render/src/camera/projection.rs | 16 ++--- .../render_graph/nodes/window_texture_node.rs | 4 +- crates/bevy_ui/src/flex/mod.rs | 4 +- crates/bevy_wgpu/src/wgpu_type_converter.rs | 4 +- crates/bevy_window/src/event.rs | 4 +- crates/bevy_window/src/window.rs | 62 ++++++++++++------- crates/bevy_winit/src/lib.rs | 28 +++++---- crates/bevy_winit/src/winit_windows.rs | 6 +- examples/2d/contributors.rs | 8 +-- examples/ecs/parallel_query.rs | 12 ++-- 11 files changed, 86 insertions(+), 64 deletions(-) diff --git a/crates/bevy_render/src/camera/camera.rs b/crates/bevy_render/src/camera/camera.rs index 98ddfd64bf..2d75e9abb6 100644 --- a/crates/bevy_render/src/camera/camera.rs +++ b/crates/bevy_render/src/camera/camera.rs @@ -78,7 +78,7 @@ pub fn camera_system( for (entity, mut camera, mut camera_projection) in queries.q0_mut().iter_mut() { if let Some(window) = windows.get(camera.window) { if changed_window_ids.contains(&window.id()) || added_cameras.contains(&entity) { - camera_projection.update(window.width() as usize, window.height() as usize); + camera_projection.update(window.logical_width(), window.logical_height()); camera.projection_matrix = camera_projection.get_projection_matrix(); camera.depth_calculation = camera_projection.depth_calculation(); } diff --git a/crates/bevy_render/src/camera/projection.rs b/crates/bevy_render/src/camera/projection.rs index b213f49b81..7e9e8a4ab6 100644 --- a/crates/bevy_render/src/camera/projection.rs +++ b/crates/bevy_render/src/camera/projection.rs @@ -5,7 +5,7 @@ use serde::{Deserialize, Serialize}; pub trait CameraProjection { fn get_projection_matrix(&self) -> Mat4; - fn update(&mut self, width: usize, height: usize); + fn update(&mut self, width: f32, height: f32); fn depth_calculation(&self) -> DepthCalculation; } @@ -23,8 +23,8 @@ impl CameraProjection for PerspectiveProjection { Mat4::perspective_rh(self.fov, self.aspect_ratio, self.near, self.far) } - fn update(&mut self, width: usize, height: usize) { - self.aspect_ratio = width as f32 / height as f32; + fn update(&mut self, width: f32, height: f32) { + self.aspect_ratio = width / height; } fn depth_calculation(&self) -> DepthCalculation { @@ -75,11 +75,11 @@ impl CameraProjection for OrthographicProjection { ) } - fn update(&mut self, width: usize, height: usize) { + fn update(&mut self, width: f32, height: f32) { match self.window_origin { WindowOrigin::Center => { - let half_width = width as f32 / 2.0; - let half_height = height as f32 / 2.0; + let half_width = width / 2.0; + let half_height = height / 2.0; self.left = -half_width; self.right = half_width; self.top = half_height; @@ -87,8 +87,8 @@ impl CameraProjection for OrthographicProjection { } WindowOrigin::BottomLeft => { self.left = 0.0; - self.right = width as f32; - self.top = height as f32; + self.right = width; + self.top = height; self.bottom = 0.0; } } diff --git a/crates/bevy_render/src/render_graph/nodes/window_texture_node.rs b/crates/bevy_render/src/render_graph/nodes/window_texture_node.rs index 7504faebc8..d287002ab4 100644 --- a/crates/bevy_render/src/render_graph/nodes/window_texture_node.rs +++ b/crates/bevy_render/src/render_graph/nodes/window_texture_node.rs @@ -68,8 +68,8 @@ impl Node for WindowTextureNode { render_resource_context.remove_texture(old_texture); } - self.descriptor.size.width = window.scaled_width(); - self.descriptor.size.height = window.scaled_height(); + self.descriptor.size.width = window.physical_width(); + self.descriptor.size.height = window.physical_height(); let texture_resource = render_resource_context.create_texture(self.descriptor); output.set(WINDOW_TEXTURE, RenderResourceId::Texture(texture_resource)); } diff --git a/crates/bevy_ui/src/flex/mod.rs b/crates/bevy_ui/src/flex/mod.rs index abc9bc6084..0a663b3b6c 100644 --- a/crates/bevy_ui/src/flex/mod.rs +++ b/crates/bevy_ui/src/flex/mod.rs @@ -116,8 +116,8 @@ impl FlexSurface { *node, stretch::style::Style { size: stretch::geometry::Size { - width: stretch::style::Dimension::Points(window.width() as f32), - height: stretch::style::Dimension::Points(window.height() as f32), + width: stretch::style::Dimension::Points(window.logical_width()), + height: stretch::style::Dimension::Points(window.logical_height()), }, ..Default::default() }, diff --git a/crates/bevy_wgpu/src/wgpu_type_converter.rs b/crates/bevy_wgpu/src/wgpu_type_converter.rs index d1e5d4f996..e6e176263e 100644 --- a/crates/bevy_wgpu/src/wgpu_type_converter.rs +++ b/crates/bevy_wgpu/src/wgpu_type_converter.rs @@ -564,8 +564,8 @@ impl WgpuFrom<&Window> for wgpu::SwapChainDescriptor { wgpu::SwapChainDescriptor { usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT, format: TextureFormat::default().wgpu_into(), - width: window.scaled_width(), - height: window.scaled_height(), + width: window.physical_width(), + height: window.physical_height(), present_mode: if window.vsync() { wgpu::PresentMode::Mailbox } else { diff --git a/crates/bevy_window/src/event.rs b/crates/bevy_window/src/event.rs index 287177d58b..ddb77f666c 100644 --- a/crates/bevy_window/src/event.rs +++ b/crates/bevy_window/src/event.rs @@ -5,8 +5,8 @@ use bevy_math::Vec2; #[derive(Debug, Clone)] pub struct WindowResized { pub id: WindowId, - pub width: usize, - pub height: usize, + pub width: f32, + pub height: f32, } /// An event that indicates that a new window should be created. diff --git a/crates/bevy_window/src/window.rs b/crates/bevy_window/src/window.rs index c1d1465788..c7996bdffe 100644 --- a/crates/bevy_window/src/window.rs +++ b/crates/bevy_window/src/window.rs @@ -35,8 +35,8 @@ impl Default for WindowId { #[derive(Debug)] pub struct Window { id: WindowId, - width: u32, - height: u32, + physical_width: u32, + physical_height: u32, title: String, vsync: bool, resizable: bool, @@ -61,8 +61,8 @@ pub enum WindowCommand { title: String, }, SetResolution { - width: u32, - height: u32, + physical_width: u32, + physical_height: u32, }, SetVsync { vsync: bool, @@ -103,8 +103,8 @@ impl Window { pub fn new(id: WindowId, window_descriptor: &WindowDescriptor) -> Self { Window { id, - height: window_descriptor.height, - width: window_descriptor.width, + physical_height: window_descriptor.height, + physical_width: window_descriptor.width, title: window_descriptor.title.clone(), vsync: window_descriptor.vsync, resizable: window_descriptor.resizable, @@ -127,20 +127,32 @@ impl Window { #[inline] pub fn width(&self) -> u32 { - self.width - } - - pub fn scaled_width(&self) -> u32 { - (self.width as f64 * self.scale_factor) as u32 - } - - pub fn scaled_height(&self) -> u32 { - (self.height as f64 * self.scale_factor) as u32 + self.logical_width() as u32 } #[inline] pub fn height(&self) -> u32 { - self.height + self.logical_height() as u32 + } + + #[inline] + pub fn logical_width(&self) -> f32 { + (self.physical_width as f64 / self.scale_factor) as f32 + } + + #[inline] + pub fn logical_height(&self) -> f32 { + (self.physical_height as f64 / self.scale_factor) as f32 + } + + #[inline] + pub fn physical_width(&self) -> u32 { + self.physical_width + } + + #[inline] + pub fn physical_height(&self) -> u32 { + self.physical_height } #[inline] @@ -150,17 +162,19 @@ impl Window { } pub fn set_resolution(&mut self, width: u32, height: u32) { - self.width = width; - self.height = height; - self.command_queue - .push(WindowCommand::SetResolution { width, height }); + self.physical_width = (width as f64 * self.scale_factor) as u32; + self.physical_height = (height as f64 * self.scale_factor) as u32; + self.command_queue.push(WindowCommand::SetResolution { + physical_width: self.physical_width, + physical_height: self.physical_height, + }); } #[allow(missing_docs)] #[inline] - pub fn update_resolution_from_backend(&mut self, width: u32, height: u32) { - self.width = width; - self.height = height; + pub fn update_physical_size_from_backend(&mut self, width: u32, height: u32) { + self.physical_width = width; + self.physical_height = height; } #[allow(missing_docs)] @@ -265,7 +279,7 @@ impl Window { self.mode = mode; self.command_queue.push(WindowCommand::SetWindowMode { mode, - resolution: (self.width, self.height), + resolution: (self.physical_width, self.physical_height), }); } diff --git a/crates/bevy_winit/src/lib.rs b/crates/bevy_winit/src/lib.rs index faaacf6268..3393183993 100644 --- a/crates/bevy_winit/src/lib.rs +++ b/crates/bevy_winit/src/lib.rs @@ -67,9 +67,15 @@ fn change_window(_: &mut World, resources: &mut Resources) { let window = winit_windows.get_window(id).unwrap(); window.set_title(&title); } - bevy_window::WindowCommand::SetResolution { width, height } => { + bevy_window::WindowCommand::SetResolution { + physical_width, + physical_height, + } => { let window = winit_windows.get_window(id).unwrap(); - window.set_inner_size(winit::dpi::LogicalSize::new(width, height)); + window.set_inner_size(winit::dpi::PhysicalSize::new( + physical_width, + physical_height, + )); } bevy_window::WindowCommand::SetVsync { .. } => (), bevy_window::WindowCommand::SetResizable { resizable } => { @@ -197,17 +203,15 @@ pub fn winit_runner(mut app: App) { let winit_windows = app.resources.get_mut::().unwrap(); let mut windows = app.resources.get_mut::().unwrap(); let window_id = winit_windows.get_window_id(winit_window_id).unwrap(); - let winit_window = winit_windows.get_window(window_id).unwrap(); let window = windows.get_mut(window_id).unwrap(); - let size = size.to_logical(winit_window.scale_factor()); - window.update_resolution_from_backend(size.width, size.height); + window.update_physical_size_from_backend(size.width, size.height); let mut resize_events = app.resources.get_mut::>().unwrap(); resize_events.send(WindowResized { id: window_id, - height: window.height() as usize, - width: window.width() as usize, + height: window.logical_height(), + width: window.logical_width(), }); } WindowEvent::CloseRequested => { @@ -305,8 +309,8 @@ pub fn winit_runner(mut app: App) { // FIXME?: On Android window start is top while on PC/Linux/OSX on bottom if cfg!(target_os = "android") { - let window_height = windows.get_primary().unwrap().height(); - location.y = window_height as f32 - location.y; + let window_height = windows.get_primary().unwrap().logical_height(); + location.y = window_height - location.y; } touch_input_events.send(converters::convert_touch_input(touch, location)); } @@ -332,9 +336,11 @@ pub fn winit_runner(mut app: App) { let mut windows = app.resources.get_mut::().unwrap(); let window_id = winit_windows.get_window_id(winit_window_id).unwrap(); let window = windows.get_mut(window_id).unwrap(); - let size = new_inner_size.to_logical(scale_factor); + window.update_physical_size_from_backend( + new_inner_size.width, + new_inner_size.height, + ); window.update_scale_factor_from_backend(scale_factor); - window.update_resolution_from_backend(size.width, size.height); } WindowEvent::Focused(focused) => { let mut focused_events = diff --git a/crates/bevy_winit/src/winit_windows.rs b/crates/bevy_winit/src/winit_windows.rs index 81e245cebf..75240017b0 100644 --- a/crates/bevy_winit/src/winit_windows.rs +++ b/crates/bevy_winit/src/winit_windows.rs @@ -31,8 +31,8 @@ impl WinitWindows { winit::window::Fullscreen::Exclusive(match use_size { true => get_fitting_videomode( &event_loop.primary_monitor().unwrap(), - window.width(), - window.height(), + window.physical_width(), + window.physical_height(), ), false => get_best_videomode(&event_loop.primary_monitor().unwrap()), }), @@ -100,6 +100,8 @@ impl WinitWindows { } } + let inner_size = winit_window.inner_size(); + window.update_physical_size_from_backend(inner_size.width, inner_size.height); window.update_scale_factor_from_backend(winit_window.scale_factor()); self.windows.insert(winit_window.id(), winit_window); diff --git a/examples/2d/contributors.rs b/examples/2d/contributors.rs index 00c210a98c..6c1a2b80ed 100644 --- a/examples/2d/contributors.rs +++ b/examples/2d/contributors.rs @@ -237,11 +237,11 @@ fn collision_system( let win = wins.get_primary().unwrap(); - let ceiling = (win.height() / 2) as f32; - let ground = -((win.height() / 2) as f32); + let ceiling = win.logical_height() / 2.; + let ground = -(win.logical_height() / 2.); - let wall_left = -((win.width() / 2) as f32); - let wall_right = (win.width() / 2) as f32; + let wall_left = -(win.logical_width() / 2.); + let wall_right = win.logical_width() / 2.; for (mut v, mut t) in q.iter_mut() { let left = t.translation.x - SPRITE_SIZE / 2.0; diff --git a/examples/ecs/parallel_query.rs b/examples/ecs/parallel_query.rs index fdfa1b9e4f..3e36c16648 100644 --- a/examples/ecs/parallel_query.rs +++ b/examples/ecs/parallel_query.rs @@ -48,12 +48,12 @@ fn bounce_system( mut sprites: Query<(&Transform, &mut Velocity)>, ) { let window = windows.get_primary().expect("No primary window."); - let width = window.width(); - let height = window.height(); - let left = width as f32 / -2.0; - let right = width as f32 / 2.0; - let bottom = height as f32 / -2.0; - let top = height as f32 / 2.0; + let width = window.logical_width(); + let height = window.logical_height(); + let left = width / -2.0; + let right = width / 2.0; + let bottom = height / -2.0; + let top = height / 2.0; sprites // Batch size of 32 is chosen to limit the overhead of // ParallelIterator, since negating a vector is very inexpensive.