mirror of
https://github.com/danbulant/cushy
synced 2026-06-21 23:52:52 +00:00
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:
parent
b4058fc55b
commit
e7ccbac18c
3 changed files with 85 additions and 54 deletions
6
Cargo.lock
generated
6
Cargo.lock
generated
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
129
src/window.rs
129
src/window.rs
|
|
@ -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.
|
||||
|
|
|
|||
Loading…
Reference in a new issue