Skip to content

Commit

Permalink
Merge pull request #417 from kas-gui/work2
Browse files Browse the repository at this point in the history
WGPU update, improved window creation
  • Loading branch information
dhardy authored Nov 9, 2023
2 parents 78eb7cb + ad9c646 commit 89af4e2
Show file tree
Hide file tree
Showing 12 changed files with 127 additions and 92 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ jobs:
toolchain: [stable]
include:
- os: ubuntu-latest
toolchain: "1.66.0"
toolchain: "1.67.0"
- os: ubuntu-latest
toolchain: beta

Expand Down
4 changes: 2 additions & 2 deletions crates/kas-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ ron = { version = "0.8.0", package = "ron", optional = true }
toml = { version = "0.8.2", package = "toml", optional = true }
num_enum = "0.7.0"
dark-light = { version = "1.0", optional = true }
raw-window-handle = "0.5.0"
raw-window-handle = "0.6.0"
async-global-executor = { version = "2.3.1", optional = true }
cfg-if = "1.0.0"
smol_str = "0.2.0"
Expand All @@ -123,4 +123,4 @@ version = "0.5.0" # used in doc links
version = "0.29.2"
optional = true
default-features = false
features = ["rwh_05"]
features = ["rwh_06"]
3 changes: 3 additions & 0 deletions crates/kas-core/src/draw/draw_shared.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,9 @@ impl<DS: DrawSharedImpl> DrawShared for SharedState<DS> {
pub trait DrawSharedImpl: Any {
type Draw: DrawImpl;

/// Get the maximum 2D texture size
fn max_texture_dimension_2d(&self) -> u32;

/// Set font raster config
fn set_raster_config(&mut self, config: &RasterConfig);

Expand Down
14 changes: 8 additions & 6 deletions crates/kas-core/src/shell/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use crate::draw::{color::Rgba, DrawIface, WindowCommon};
use crate::geom::Size;
use crate::theme::Theme;
use raw_window_handle as raw;
use std::time::Instant;
use thiserror::Error;

/// Possible failures from constructing a [`Shell`](super::Shell)
Expand Down Expand Up @@ -194,12 +195,11 @@ pub trait WindowSurface {
type Shared: kas::draw::DrawSharedImpl;

/// Construct an instance from a window handle
fn new<W: raw::HasRawWindowHandle + raw::HasRawDisplayHandle>(
shared: &mut Self::Shared,
size: Size,
window: W,
) -> Result<Self>
///
/// It is required to call [`WindowSurface::do_resize`] after this.
fn new<W>(shared: &mut Self::Shared, window: W) -> Result<Self>
where
W: raw::HasWindowHandle + raw::HasDisplayHandle,
Self: Sized;

/// Get current surface size
Expand All @@ -220,5 +220,7 @@ pub trait WindowSurface {
fn common_mut(&mut self) -> &mut WindowCommon;

/// Present frame
fn present(&mut self, shared: &mut Self::Shared, clear_color: Rgba);
///
/// Return time at which render finishes
fn present(&mut self, shared: &mut Self::Shared, clear_color: Rgba) -> Instant;
}
14 changes: 8 additions & 6 deletions crates/kas-core/src/shell/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ enum ProxyAction {
#[cfg(test)]
mod test {
use super::*;
use std::time::Instant;

struct Draw;
impl crate::draw::DrawImpl for Draw {
Expand Down Expand Up @@ -152,6 +153,10 @@ mod test {
impl crate::draw::DrawSharedImpl for DrawShared {
type Draw = Draw;

fn max_texture_dimension_2d(&self) -> u32 {
todo!()
}

fn set_raster_config(&mut self, _: &crate::theme::RasterConfig) {
todo!()
}
Expand Down Expand Up @@ -224,12 +229,9 @@ mod test {
impl WindowSurface for Surface {
type Shared = DrawShared;

fn new<W: raw_window_handle::HasRawWindowHandle + raw_window_handle::HasRawDisplayHandle>(
_: &mut Self::Shared,
_: crate::prelude::Size,
_: W,
) -> Result<Self>
fn new<W>(_: &mut Self::Shared, _: W) -> Result<Self>
where
W: raw_window_handle::HasRawWindowHandle + raw_window_handle::HasRawDisplayHandle,
Self: Sized,
{
todo!()
Expand All @@ -254,7 +256,7 @@ mod test {
todo!()
}

fn present(&mut self, _: &mut Self::Shared, _: crate::draw::color::Rgba) {
fn present(&mut self, _: &mut Self::Shared, _: crate::draw::color::Rgba) -> Instant {
todo!()
}
}
Expand Down
2 changes: 0 additions & 2 deletions crates/kas-core/src/shell/shared.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ pub(crate) struct SharedState<Data: AppData, S: WindowSurface, T: Theme<S::Share
pub(super) shell: ShellShared<Data, S, T>,
pub(super) data: Data,
/// Estimated scale factor (from last window constructed or available screens)
pub(super) scale_factor: f64,
options: Options,
}

Expand Down Expand Up @@ -82,7 +81,6 @@ where
window_id: 0,
},
data,
scale_factor: pw.guess_scale_factor(),
options,
})
}
Expand Down
11 changes: 0 additions & 11 deletions crates/kas-core/src/shell/shell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -262,17 +262,6 @@ impl<'a> PlatformWrapper<'a> {
// Otherwise platform is unsupported!
}

/// Guess scale factor of first window
pub(super) fn guess_scale_factor(&self) -> f64 {
if let Some(mon) = self.0.primary_monitor() {
return mon.scale_factor();
}
if let Some(mon) = self.0.available_monitors().next() {
return mon.scale_factor();
}
1.0
}

/// Create a waker
///
/// This waker may be used by a [`Future`](std::future::Future) to revive
Expand Down
111 changes: 65 additions & 46 deletions crates/kas-core/src/shell/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
use super::common::WindowSurface;
use super::shared::{SharedState, ShellShared};
use super::ProxyAction;
use kas::cast::Cast;
use kas::draw::{color::Rgba, AnimationState};
use kas::cast::{Cast, Conv};
use kas::draw::{color::Rgba, AnimationState, DrawSharedImpl};
use kas::event::{config::WindowConfig, ConfigCx, CursorIcon, EventState};
use kas::geom::{Coord, Rect, Size};
use kas::layout::SolveCache;
Expand Down Expand Up @@ -76,19 +76,11 @@ impl<A: AppData, S: WindowSurface, T: Theme<S::Shared>> Window<A, S, T> {
) -> super::Result<winit::window::WindowId> {
let time = Instant::now();

// Wayland only supports windows constructed via logical size
let use_logical_size = shared.shell.platform.is_wayland();

let scale_factor = if use_logical_size {
1.0
} else {
shared.scale_factor as f32
};

let mut theme_window = shared.shell.theme.new_window(scale_factor);
// We cannot reliably determine the scale factor before window creation.
// A factor of 1.0 lets us estimate the size requirements (logical).
let mut theme_window = shared.shell.theme.new_window(1.0);
let dpem = theme_window.size().dpem();

self.ev_state.update_config(scale_factor, dpem);
self.ev_state.update_config(1.0, dpem);
self.ev_state.full_configure(
theme_window.size(),
self.window_id,
Expand All @@ -101,20 +93,18 @@ impl<A: AppData, S: WindowSurface, T: Theme<S::Shared>> Window<A, S, T> {
let mut solve_cache = SolveCache::find_constraints(node, sizer);

// Opening a zero-size window causes a crash, so force at least 1x1:
let ideal = solve_cache.ideal(true).max(Size(1, 1));
let ideal = match use_logical_size {
false => ideal.as_physical(),
true => ideal.as_logical(),
};
let min_size = Size(1, 1);
let max_size = Size::splat(shared.shell.draw.draw.max_texture_dimension_2d().cast());

let ideal = solve_cache
.ideal(true)
.clamp(min_size, max_size)
.as_logical();

let mut builder = WindowBuilder::new().with_inner_size(ideal);
let (restrict_min, restrict_max) = self.widget.restrictions();
if restrict_min {
let min = solve_cache.min(true);
let min = match use_logical_size {
false => min.as_physical(),
true => min.as_logical(),
};
let min = solve_cache.min(true).as_logical();
builder = builder.with_min_inner_size(min);
}
if restrict_max {
Expand All @@ -125,40 +115,63 @@ impl<A: AppData, S: WindowSurface, T: Theme<S::Shared>> Window<A, S, T> {
.with_window_icon(self.widget.icon())
.with_decorations(self.widget.decorations() == kas::Decorations::Server)
.with_transparent(self.widget.transparent())
.with_visible(false)
.build(elwt)?;

// Now that we have a scale factor, we may need to resize:
let scale_factor = window.scale_factor();
shared.scale_factor = scale_factor;
let apply_size;
if scale_factor != 1.0 {
let sf32 = scale_factor as f32;
shared.shell.theme.update_window(&mut theme_window, sf32);
let dpem = theme_window.size().dpem();
self.ev_state.update_config(sf32, dpem);
let node = self.widget.as_node(&shared.data);
let sizer = SizeCx::new(theme_window.size());
solve_cache = SolveCache::find_constraints(node, sizer);

// NOTE: we would use .as_physical(), but we need to ensure rounding
// doesn't result in anything exceeding max_size which can happen
// otherwise (default rounding mode is to nearest, away from zero).
let ideal = solve_cache.ideal(true).max(min_size);
let ub = (f64::conv(max_size.0) / scale_factor).floor();
let w = ub.min(f64::conv(ideal.0) / scale_factor);
let h = ub.min(f64::conv(ideal.1) / scale_factor);
let ideal = winit::dpi::LogicalSize::new(w, h);

if let Some(size) = window.request_inner_size(ideal) {
debug_assert_eq!(size, window.inner_size());
apply_size = true;
} else {
// We will receive WindowEvent::Resized
apply_size = false;
}
} else {
apply_size = true;
}

let size: Size = window.inner_size().cast();
log::info!(
"new: constructed with physical size {:?}, scale factor {}",
size,
scale_factor
);

// Now that we have a scale factor, we may need to resize:
if use_logical_size && scale_factor != 1.0 {
let scale_factor = scale_factor as f32;
shared
.shell
.theme
.update_window(&mut theme_window, scale_factor);
let dpem = theme_window.size().dpem();
self.ev_state.update_config(scale_factor, dpem);
solve_cache.invalidate_rule_cache();
}

#[cfg(all(wayland_platform, feature = "clipboard"))]
use raw_window_handle::{HasRawDisplayHandle, RawDisplayHandle, WaylandDisplayHandle};
use raw_window_handle::{HasDisplayHandle, RawDisplayHandle, WaylandDisplayHandle};
// TODO: this shouldn't unwrap
#[cfg(all(wayland_platform, feature = "clipboard"))]
let wayland_clipboard = match window.raw_display_handle() {
let wayland_clipboard = match window.display_handle().unwrap().as_raw() {
RawDisplayHandle::Wayland(WaylandDisplayHandle { display, .. }) => {
Some(unsafe { smithay_clipboard::Clipboard::new(display) })
Some(unsafe { smithay_clipboard::Clipboard::new(display.as_ptr()) })
}
_ => None,
};

let surface = S::new(&mut shared.shell.draw.draw, size, &window)?;
let mut surface = S::new(&mut shared.shell.draw.draw, &window)?;
if apply_size {
surface.do_resize(&mut shared.shell.draw.draw, size);
}

let winit_id = window.id();

Expand All @@ -176,7 +189,9 @@ impl<A: AppData, S: WindowSurface, T: Theme<S::Shared>> Window<A, S, T> {
queued_frame_time: Some(time),
});

self.apply_size(shared, true);
if apply_size {
self.apply_size(shared, true);
}

log::trace!(target: "kas_perf::wgpu::window", "resume: {}µs", time.elapsed().as_micros());
Ok(winit_id)
Expand All @@ -202,7 +217,6 @@ impl<A: AppData, S: WindowSurface, T: Theme<S::Shared>> Window<A, S, T> {
match event {
WindowEvent::Moved(_) | WindowEvent::Destroyed => false,
WindowEvent::Resized(size) => {
// TODO: maybe enqueue to allow skipping of obsolete resizes
if window
.surface
.do_resize(&mut shared.shell.draw.draw, size.cast())
Expand All @@ -213,14 +227,16 @@ impl<A: AppData, S: WindowSurface, T: Theme<S::Shared>> Window<A, S, T> {
}
WindowEvent::ScaleFactorChanged { scale_factor, .. } => {
// Note: API allows us to set new window size here.
shared.scale_factor = scale_factor;
let scale_factor = scale_factor as f32;
shared
.shell
.theme
.update_window(&mut window.theme_window, scale_factor);
let dpem = window.theme_window.size().dpem();
self.ev_state.update_config(scale_factor, dpem);

// NOTE: we could try resizing here in case the window is too
// small due to non-linear scaling, but it appears unnecessary.
window.solve_cache.invalidate_rule_cache();
false
}
Expand Down Expand Up @@ -418,6 +434,7 @@ impl<A: AppData, S: WindowSurface, T: Theme<S::Shared>> Window<A, S, T> {
}
self.widget.resize_popups(&mut cx, &shared.data);

// Size restrictions may have changed due to content or size (line wrapping)
let (restrict_min, restrict_max) = self.widget.restrictions();
if restrict_min {
let min = window.solve_cache.min(true).as_physical();
Expand All @@ -428,6 +445,7 @@ impl<A: AppData, S: WindowSurface, T: Theme<S::Shared>> Window<A, S, T> {
window.set_max_inner_size(Some(ideal));
};

window.set_visible(true);
window.request_redraw();
log::trace!(
target: "kas_perf::wgpu::window",
Expand Down Expand Up @@ -477,18 +495,19 @@ impl<A: AppData, S: WindowSurface, T: Theme<S::Shared>> Window<A, S, T> {
} else {
shared.shell.theme.clear_color()
};
window
let time3 = window
.surface
.present(&mut shared.shell.draw.draw, clear_color);

let text_dur_micros = take(&mut window.surface.common_mut().dur_text);
let end = Instant::now();
log::trace!(
target: "kas_perf::wgpu::window",
"do_draw: {}µs ({}μs widgets, {}µs text, {}µs render)",
"do_draw: {}μs ({}μs widgets, {}μs text, {}μs render, {}μs present)",
(end - start).as_micros(),
(time2 - start).as_micros(),
text_dur_micros.as_micros(),
(time3 - time2).as_micros(),
(end - time2).as_micros()
);

Expand Down
7 changes: 7 additions & 0 deletions crates/kas-resvg/src/svg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,13 @@ impl_scope! {
State::Rendering(source) |
State::Ready(source, _) => State::Ready(source, pixmap),
};

let own_size: (u32, u32) = self.core.rect.size.cast();
if size != own_size {
if let Some(fut) = self.inner.resize(size) {
cx.push_spawn(self.id(), fut);
}
}
}
}
}
Expand Down
7 changes: 6 additions & 1 deletion crates/kas-wgpu/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ raster = ["kas-text/raster"]
bytemuck = "1.7.0"
futures-lite = "1.12"
log = "0.4"
wgpu = { version = "0.17.0", features = ["spirv"] }
thiserror = "1.0.23"
guillotiere = "0.6.0"
rustc-hash = "1.0"
Expand All @@ -43,5 +42,11 @@ path = "../kas-core"
[dependencies.kas-text]
version = "0.6.0"

[dependencies.wgpu]
version = "0.18.0"
features = ["spirv"]
git = "https://github.com/gfx-rs/wgpu.git"
rev = "1dc5347b141f98392fa012ae3416901faf4249a5"

[build-dependencies]
glob = "0.3"
Loading

0 comments on commit 89af4e2

Please sign in to comment.