improv: clear image_cache on refresh
This commit is contained in:
parent
80b8eb47d7
commit
31827ed240
2 changed files with 80 additions and 29 deletions
|
|
@ -460,9 +460,7 @@ pub struct CursorStateInner {
|
||||||
|
|
||||||
cursors: HashMap<CursorIcon, Cursor>,
|
cursors: HashMap<CursorIcon, Cursor>,
|
||||||
current_image: Option<Image>,
|
current_image: Option<Image>,
|
||||||
/// Rasterized cursor frames keyed by `(shape, pixel size, frame index)` so
|
image_cache: Vec<CachedFrame>,
|
||||||
/// each SVG frame is rasterized (and uploaded) at most once per size.
|
|
||||||
image_cache: Vec<((CursorIcon, u32, usize), Image, MemoryRenderBuffer)>,
|
|
||||||
|
|
||||||
hidden: bool,
|
hidden: bool,
|
||||||
idle_timer: Option<RegistrationToken>,
|
idle_timer: Option<RegistrationToken>,
|
||||||
|
|
@ -476,6 +474,15 @@ pub struct CursorStateInner {
|
||||||
magnification: f32,
|
magnification: f32,
|
||||||
anim_from: f32,
|
anim_from: f32,
|
||||||
anim_start: Option<Instant>,
|
anim_start: Option<Instant>,
|
||||||
|
rest_started: Option<Instant>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A rasterized cursor frame, keyed by `(shape, pixel size, frame index)`.
|
||||||
|
struct CachedFrame {
|
||||||
|
key: (CursorIcon, u32, usize),
|
||||||
|
image: Image,
|
||||||
|
buffer: MemoryRenderBuffer,
|
||||||
|
unmagnified: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// One sampled pointer position on the recent motion path.
|
/// One sampled pointer position on the recent motion path.
|
||||||
|
|
@ -485,6 +492,9 @@ struct PathSample {
|
||||||
time: Instant,
|
time: Instant,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// How long everything must stay unmagnified before the enlarged frames go.
|
||||||
|
const MAGNIFIED_FRAME_GRACE: Duration = Duration::from_secs(10);
|
||||||
|
|
||||||
/// How far back the motion path is considered when looking for a shake.
|
/// How far back the motion path is considered when looking for a shake.
|
||||||
const SHAKE_INTERVAL: Duration = Duration::from_millis(1000);
|
const SHAKE_INTERVAL: Duration = Duration::from_millis(1000);
|
||||||
/// Path-length / bounding-box-diagonal ratio required to count as a shake.
|
/// Path-length / bounding-box-diagonal ratio required to count as a shake.
|
||||||
|
|
@ -529,6 +539,21 @@ impl CursorStateInner {
|
||||||
self.cursor_size
|
self.cursor_size
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Drop the rasterizations only a magnified cursor needed, once nothing has
|
||||||
|
/// magnified it for [`MAGNIFIED_FRAME_GRACE`].
|
||||||
|
pub fn drop_magnified_frames(&mut self, now: Instant, zoomed: bool) {
|
||||||
|
if zoomed || self.is_magnifying() {
|
||||||
|
self.rest_started = None;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let rest_started = *self.rest_started.get_or_insert(now);
|
||||||
|
if now.duration_since(rest_started) < MAGNIFIED_FRAME_GRACE {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.image_cache.retain(|frame| frame.unmagnified);
|
||||||
|
}
|
||||||
|
|
||||||
/// Feed one relative-motion event into the shake detector.
|
/// Feed one relative-motion event into the shake detector.
|
||||||
pub fn detect_shake(&mut self, delta: Point<f64, Logical>, now: Instant) {
|
pub fn detect_shake(&mut self, delta: Point<f64, Logical>, now: Instant) {
|
||||||
// Drop samples that have aged out of the time window.
|
// Drop samples that have aged out of the time window.
|
||||||
|
|
@ -680,6 +705,7 @@ impl Default for CursorStateInner {
|
||||||
magnification: 1.0,
|
magnification: 1.0,
|
||||||
anim_from: 1.0,
|
anim_from: 1.0,
|
||||||
anim_start: None,
|
anim_start: None,
|
||||||
|
rest_started: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -748,34 +774,36 @@ pub fn draw_cursor<R>(
|
||||||
let key = (current_cursor, size_px, frame_idx);
|
let key = (current_cursor, size_px, frame_idx);
|
||||||
|
|
||||||
// Rasterize and upload this (shape, size, frame) only if not cached.
|
// Rasterize and upload this (shape, size, frame) only if not cached.
|
||||||
if !state
|
let index = match state.image_cache.iter().position(|frame| frame.key == key) {
|
||||||
.image_cache
|
Some(index) => index,
|
||||||
.iter()
|
None => {
|
||||||
.any(|(cached, _, _)| *cached == key)
|
let image = {
|
||||||
{
|
let cursor = state.get_named_cursor(current_cursor);
|
||||||
let frame = {
|
cursor.render_frame(size_px, frame_idx)
|
||||||
let cursor = state.get_named_cursor(current_cursor);
|
};
|
||||||
cursor.render_frame(size_px, frame_idx)
|
let actual_scale = (image.size / state.size()).max(1);
|
||||||
};
|
let buffer = MemoryRenderBuffer::from_slice(
|
||||||
let actual_scale = (frame.size / state.size()).max(1);
|
&image.pixels_rgba,
|
||||||
let buffer = MemoryRenderBuffer::from_slice(
|
Fourcc::Argb8888,
|
||||||
&frame.pixels_rgba,
|
(image.width as i32, image.height as i32),
|
||||||
Fourcc::Argb8888,
|
actual_scale as i32,
|
||||||
(frame.width as i32, frame.height as i32),
|
Transform::Normal,
|
||||||
actual_scale as i32,
|
None,
|
||||||
Transform::Normal,
|
);
|
||||||
None,
|
state.image_cache.push(CachedFrame {
|
||||||
);
|
key,
|
||||||
state.image_cache.push((key, frame, buffer));
|
image,
|
||||||
}
|
buffer,
|
||||||
|
unmagnified: size_px == unmagnified_px,
|
||||||
|
});
|
||||||
|
state.image_cache.len() - 1
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let (frame, pointer_image) = {
|
let (frame, pointer_image) = {
|
||||||
let (_, frame, buffer) = state
|
let entry = &mut state.image_cache[index];
|
||||||
.image_cache
|
entry.unmagnified |= size_px == unmagnified_px;
|
||||||
.iter()
|
(entry.image.clone(), entry.buffer.clone())
|
||||||
.find(|(cached, _, _)| *cached == key)
|
|
||||||
.unwrap();
|
|
||||||
(frame.clone(), buffer.clone())
|
|
||||||
};
|
};
|
||||||
let actual_scale = (frame.size / state.size()).max(1);
|
let actual_scale = (frame.size / state.size()).max(1);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1614,6 +1614,29 @@ impl Common {
|
||||||
a11y_keyboard_monitor.refresh();
|
a11y_keyboard_monitor.refresh();
|
||||||
}
|
}
|
||||||
self.image_copy_capture_state.cleanup();
|
self.image_copy_capture_state.cleanup();
|
||||||
|
self.cleanup_cursor_images();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Release the enlarged cursor frames a finished shake or zoom left behind.
|
||||||
|
fn cleanup_cursor_images(&mut self) {
|
||||||
|
let shell = self.shell.read();
|
||||||
|
let zoomed = shell.zoom_state.as_ref().is_some_and(|zoom_state| {
|
||||||
|
shell
|
||||||
|
.outputs()
|
||||||
|
.any(|output| zoom_state.animating_level(output) > 1.0)
|
||||||
|
});
|
||||||
|
let now = Instant::now();
|
||||||
|
for seat in shell.seats.iter() {
|
||||||
|
if let Some(cursor_state) = seat
|
||||||
|
.user_data()
|
||||||
|
.get::<crate::backend::render::cursor::CursorState>()
|
||||||
|
{
|
||||||
|
cursor_state
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.drop_magnified_frames(now, zoomed);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn refresh_idle_inhibit(&mut self) {
|
pub fn refresh_idle_inhibit(&mut self) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue