Support immediately resizing without refreshing

On some platforms, notably Wayland, the window immediately responds to
resize requests. This means that if the window resizes itself during the
prepare operation, the current graphics context is no longer the correct
size for the window. Before this change, Kludgine was working around
this by noticing the discrepency and forcing an extra refresh. This
workaround is still in place in Kludgine, but now Cushy supports
restarting redrawing upon resize.
This commit is contained in:
Jonathan Johnson 2024-09-16 08:22:30 -07:00
parent b4058fc55b
commit e7ccbac18c
No known key found for this signature in database
GPG key ID: A66D6A34D6620579
3 changed files with 85 additions and 54 deletions

6
Cargo.lock generated
View file

@ -124,8 +124,7 @@ checksum = "4e1496f8fb1fbf272686b8d37f523dab3e4a7443300055e74cdaa449f3114356"
[[package]]
name = "appit"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75ed795976c3816aeceb52f1971d3e27f5403d58b16531edea7fe97f63e75f08"
source = "git+https://github.com/khonsulabs/appit#c985e024fc090e5764ff41b06d9dcc76ed5aedef"
dependencies = [
"winit",
]
@ -1312,8 +1311,7 @@ checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc"
[[package]]
name = "kludgine"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32ee58ce44762ccebb879d0df90c736336f6230e633702c7a24643dff1fca25c"
source = "git+https://github.com/khonsulabs/kludgine#eccacdaffe4a60d1887a201a68656f0058a12088"
dependencies = [
"ahash",
"alot",

View file

@ -23,7 +23,9 @@ tokio-multi-thread = ["tokio", "tokio/rt-multi-thread"]
serde = ["dep:serde", "figures/serde"]
[dependencies]
kludgine = { version = "0.11.0", features = ["app"] }
kludgine = { git = "https://github.com/khonsulabs/kludgine", features = [
"app",
] }
figures = { version = "0.4.0" }
alot = "0.3"
interner = "0.2.1"

View file

@ -32,7 +32,7 @@ use kludgine::app::winit::keyboard::{
Key, KeyLocation, ModifiersState, NamedKey, NativeKeyCode, PhysicalKey, SmolStr,
};
use kludgine::app::winit::window::{self, Cursor, Fullscreen, Icon, WindowButtons, WindowLevel};
use kludgine::app::{winit, WindowAttributes, WindowBehavior as _};
use kludgine::app::{winit, Resized, WindowAttributes, WindowBehavior as _};
use kludgine::cosmic_text::{fontdb, Family, FamilyOwned};
use kludgine::drawing::Drawing;
use kludgine::shapes::Shape;
@ -1771,7 +1771,9 @@ where
};
this.synchronize_platform_window(&mut window);
this.prepare(window, graphics);
// Perform an initial layout.
let _result = this.prepare(window, graphics);
this
}
@ -1795,7 +1797,11 @@ where
.new_frame(self.redraw_status.invalidations().drain());
}
fn prepare<W>(&mut self, mut window: W, graphics: &mut kludgine::Graphics<'_>)
fn prepare<W>(
&mut self,
mut window: W,
graphics: &mut kludgine::Graphics<'_>,
) -> Result<(), Resized>
where
W: PlatformWindowImplementation,
{
@ -1884,6 +1890,8 @@ where
if let Some(new_size) = new_size {
self.inner_size.set_and_read(new_size);
self.outer_size.set(layout_context.window().outer_size());
self.root.invalidate();
return Err(Resized);
}
self.root.set_layout(Rect::from(render_size.into_signed()));
@ -1904,6 +1912,7 @@ where
} else {
layout_context.redraw();
}
Ok(())
}
fn close_requested<W>(&mut self, window: W, kludgine: &mut Kludgine) -> bool
@ -2487,8 +2496,8 @@ where
&mut self,
window: kludgine::app::Window<'_, WindowCommand>,
graphics: &mut kludgine::Graphics<'_>,
) {
self.prepare(window, graphics);
) -> Result<(), Resized> {
self.prepare(window, graphics)
}
fn present_mode(&self) -> wgpu::PresentMode {
@ -3654,14 +3663,25 @@ pub struct CushyWindow {
impl CushyWindow {
/// Prepares all necessary resources and operations necessary to render the
/// next frame.
pub fn prepare<W>(&mut self, window: W, device: &wgpu::Device, queue: &wgpu::Queue)
///
/// # Errors
///
/// If during the preparation of rendering, the window is resized,
/// `Err(Resized)` is returned and Cushy will immediately resize the
/// graphics context and begin rendering again.
pub fn prepare<W>(
&mut self,
window: W,
device: &wgpu::Device,
queue: &wgpu::Queue,
) -> Result<(), Resized>
where
W: PlatformWindowImplementation,
{
self.window.prepare(
window,
&mut kludgine::Graphics::new(&mut self.kludgine, device, queue),
);
)
}
/// Renders this window in a wgpu render pass created from `pass`.
@ -3884,7 +3904,13 @@ pub struct VirtualWindow {
impl VirtualWindow {
/// Prepares all necessary resources and operations necessary to render the
/// next frame.
pub fn prepare(&mut self, device: &wgpu::Device, queue: &wgpu::Queue) {
///
/// # Errors
///
/// If during the preparation of rendering, the window is resized,
/// `Err(Resized)` is returned and Cushy will immediately resize the
/// graphics context and begin rendering again.
pub fn prepare(&mut self, device: &wgpu::Device, queue: &wgpu::Queue) -> Result<(), Resized> {
let now = Instant::now();
self.state.elapsed = self
.last_rendered_at
@ -3892,7 +3918,7 @@ impl VirtualWindow {
.unwrap_or_default();
self.last_rendered_at = Some(now);
self.state.dynamic.redraw_target.set(RedrawTarget::Never);
self.cushy.prepare(&mut self.state, device, queue);
self.cushy.prepare(&mut self.state, device, queue)
}
/// Renders this window in a wgpu render pass created from `pass`.
@ -4466,50 +4492,55 @@ where
}
fn redraw(&mut self) {
let mut render_size = self.window.size().ceil();
if self.window.state.size != render_size {
let current_scale = self.window.dpi_scale();
self.window
.resize(self.window.state.size, current_scale, &self.queue);
render_size = self.window.state.size;
}
let bytes_per_row = copy_buffer_aligned_bytes_per_row(render_size.width.get() * 4);
let size = u64::from(bytes_per_row) * u64::from(render_size.height.get());
self.recreate_buffers_if_needed(render_size, size, bytes_per_row);
loop {
let mut render_size = self.window.size().ceil();
if self.window.state.size != render_size {
let current_scale = self.window.dpi_scale();
self.window
.resize(self.window.state.size, current_scale, &self.queue);
render_size = self.window.state.size;
}
let bytes_per_row = copy_buffer_aligned_bytes_per_row(render_size.width.get() * 4);
let size = u64::from(bytes_per_row) * u64::from(render_size.height.get());
self.recreate_buffers_if_needed(render_size, size, bytes_per_row);
let capture = self.capture.as_ref().assert("always initialized above");
let capture = self.capture.as_ref().assert("always initialized above");
if self.cursor_visible {
let mut gfx = self.window.graphics(&self.device, &self.queue);
let mut frame = self.cursor_graphic.new_frame(&mut gfx);
frame.draw_shape(
Shape::filled_circle(Px::new(4), Color::WHITE, Origin::Center)
.translate_by(self.cursor.get()),
if self.cursor_visible {
let mut gfx = self.window.graphics(&self.device, &self.queue);
let mut frame = self.cursor_graphic.new_frame(&mut gfx);
frame.draw_shape(
Shape::filled_circle(Px::new(4), Color::WHITE, Origin::Center)
.translate_by(self.cursor.get()),
);
drop(frame);
}
if let Err(Resized) = self.window.prepare(&self.device, &self.queue) {
continue;
}
self.window.render_with(
&wgpu::RenderPassDescriptor {
label: None,
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view: capture.multisample.view(),
resolve_target: Some(capture.texture.view()),
ops: wgpu::Operations {
load: wgpu::LoadOp::Clear(Color::CLEAR_BLACK.into()),
store: wgpu::StoreOp::Store,
},
})],
depth_stencil_attachment: None,
timestamp_writes: None,
occlusion_query_set: None,
},
&self.device,
&self.queue,
self.cursor_visible.then_some(&self.cursor_graphic),
);
drop(frame);
return;
}
self.window.prepare(&self.device, &self.queue);
self.window.render_with(
&wgpu::RenderPassDescriptor {
label: None,
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view: capture.multisample.view(),
resolve_target: Some(capture.texture.view()),
ops: wgpu::Operations {
load: wgpu::LoadOp::Clear(Color::CLEAR_BLACK.into()),
store: wgpu::StoreOp::Store,
},
})],
depth_stencil_attachment: None,
timestamp_writes: None,
occlusion_query_set: None,
},
&self.device,
&self.queue,
self.cursor_visible.then_some(&self.cursor_graphic),
);
}
/// Redraws the contents.