Scope redraw requests and avoid redundant animation fallback wakeups
Instrument redraw sources, per-output request coalescing, and animation fallback scheduling. Route local visual changes to their affected outputs while preserving deferred grab and gesture updates. Schedule fallback recovery using each orphaned animation output's refresh interval, suppress it while a normal frame chain exists, and retain requested final frames after scheduling failures. Add mixed-refresh, cursor footprint, frame-chain, and disconnect regressions and document measurement limits.
This commit is contained in:
1 parent
28e03a2624
commit
6f2951c6b0
27 files changed
+965
-139
No files matched your search
@@ -99,7 +99,7 @@ impl CompositorHandler for Ferese {
|
||||
}
|
||||
layer_shell::handle_commit(self, surface);
|
||||
xdg_shell::handle_commit(&mut self.popups, &mut self.space, surface);
|
||||
crate::backends::direct::render_all(self);
|
||||
crate::backends::direct::render_surface(self, surface);
|
||||
}
|
||||
|
||||
fn destroyed(&mut self, surface: &WlSurface) {
|
||||
@@ -110,14 +110,14 @@ impl CompositorHandler for Ferese {
|
||||
self.focus_lock_surface();
|
||||
}
|
||||
self.backdrop_generation = self.backdrop_generation.wrapping_add(1);
|
||||
crate::backends::direct::render_all(self);
|
||||
crate::backends::direct::render_surface(self, surface);
|
||||
if self.idle_inhibitors.remove(surface).is_some() {
|
||||
self.refresh_idle_inhibition();
|
||||
}
|
||||
if matches!(&self.cursor_status, smithay::input::pointer::CursorImageStatus::Surface(cursor) if cursor == surface)
|
||||
{
|
||||
self.cursor_status = smithay::input::pointer::CursorImageStatus::default_named();
|
||||
crate::backends::direct::render_all(self);
|
||||
crate::backends::direct::render_cursor(self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,16 +10,17 @@ impl InputMethodHandler for Ferese {
|
||||
if let Err(error) = self.popups.track_popup(PopupKind::InputMethod(surface.clone())) {
|
||||
tracing::warn!(?error, "failed to track input method popup");
|
||||
}
|
||||
crate::backends::direct::render_all(self);
|
||||
crate::backends::direct::render_surface(self, surface.wl_surface());
|
||||
}
|
||||
|
||||
fn dismiss_popup(&mut self, _surface: PopupSurface) {
|
||||
fn dismiss_popup(&mut self, surface: PopupSurface) {
|
||||
let outputs = self.surface_outputs(surface.wl_surface());
|
||||
self.popups.cleanup();
|
||||
crate::backends::direct::render_all(self);
|
||||
crate::backends::direct::render_on(self, &outputs);
|
||||
}
|
||||
|
||||
fn popup_repositioned(&mut self, _surface: PopupSurface) {
|
||||
crate::backends::direct::render_all(self);
|
||||
fn popup_repositioned(&mut self, surface: PopupSurface) {
|
||||
crate::backends::direct::render_surface(self, surface.wl_surface());
|
||||
}
|
||||
|
||||
fn parent_geometry(&self, parent: &WlSurface) -> Rectangle<i32, Logical> {
|
||||
|
||||
@@ -32,8 +32,7 @@ impl WlrLayerShellHandler for Ferese {
|
||||
|
||||
tracing::debug!(%namespace, output = %output.name(), "mapped layer surface");
|
||||
super::set_surface_tree_output(layer.wl_surface(), &output);
|
||||
self.relayout();
|
||||
crate::backends::direct::render_all(self);
|
||||
self.relayout_on(&[output]);
|
||||
}
|
||||
|
||||
fn new_popup(&mut self, parent: LayerSurface, popup: PopupSurface) {
|
||||
@@ -59,17 +58,22 @@ impl WlrLayerShellHandler for Ferese {
|
||||
return;
|
||||
};
|
||||
let restore_focus = layer_has_keyboard_focus(self, &layer);
|
||||
let outputs = self.space.outputs().cloned().collect::<Vec<_>>();
|
||||
let outputs = self
|
||||
.space
|
||||
.outputs()
|
||||
.filter(|output| layer_map_for_output(output).layer_geometry(&layer).is_some())
|
||||
.cloned()
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
for output in outputs {
|
||||
layer_map_for_output(&output).unmap_layer(&layer);
|
||||
for output in &outputs {
|
||||
layer_map_for_output(output).unmap_layer(&layer);
|
||||
}
|
||||
|
||||
self.relayout();
|
||||
self.relayout_on(&outputs);
|
||||
if restore_focus {
|
||||
self.restore_keyboard_focus();
|
||||
}
|
||||
crate::backends::direct::render_all(self);
|
||||
crate::backends::direct::render_on(self, &outputs);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,10 +81,15 @@ pub fn handle_commit(state: &mut Ferese, surface: &WlSurface) {
|
||||
let Some(layer) = state.space.layer_for_surface(surface, WindowSurfaceType::TOPLEVEL) else {
|
||||
return;
|
||||
};
|
||||
let outputs = state.space.outputs().cloned().collect::<Vec<_>>();
|
||||
let outputs = state
|
||||
.space
|
||||
.outputs()
|
||||
.filter(|output| layer_map_for_output(output).layer_geometry(&layer).is_some())
|
||||
.cloned()
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
for output in outputs {
|
||||
let mut map = layer_map_for_output(&output);
|
||||
for output in &outputs {
|
||||
let mut map = layer_map_for_output(output);
|
||||
if map.layer_geometry(&layer).is_some() {
|
||||
map.arrange();
|
||||
layer.layer_surface().send_pending_configure();
|
||||
@@ -103,7 +112,7 @@ pub fn handle_commit(state: &mut Ferese, surface: &WlSurface) {
|
||||
state.restore_keyboard_focus();
|
||||
}
|
||||
|
||||
state.relayout();
|
||||
state.relayout_on(&outputs);
|
||||
if let Err(error) = state.display_handle.flush_clients() {
|
||||
tracing::debug!(%error, "failed to flush layer-surface configure");
|
||||
}
|
||||
|
||||
@@ -132,6 +132,38 @@ impl KeyboardShortcutsInhibitHandler for Ferese {
|
||||
}
|
||||
|
||||
impl Ferese {
|
||||
pub(crate) fn surface_outputs(&self, surface: &WlSurface) -> Vec<smithay::output::Output> {
|
||||
use smithay::desktop::{WindowSurfaceType, find_popup_root_surface};
|
||||
use smithay::wayland::compositor::get_parent;
|
||||
let mut root = surface.clone();
|
||||
while let Some(parent) = get_parent(&root) {
|
||||
root = parent;
|
||||
}
|
||||
|
||||
if let Some(popup) = self.popups.find_popup(&root)
|
||||
&& let Ok(parent) = find_popup_root_surface(&popup)
|
||||
{
|
||||
root = parent;
|
||||
}
|
||||
|
||||
let window = self.windows.id_for_surface(&root);
|
||||
self.space
|
||||
.outputs()
|
||||
.filter(|output| {
|
||||
window.is_some_and(|id| self.window_belongs_to_output(id, output))
|
||||
|| layer_map_for_output(output)
|
||||
.layer_for_surface(&root, WindowSurfaceType::ALL)
|
||||
.is_some()
|
||||
|| self
|
||||
.session_lock
|
||||
.surfaces
|
||||
.get(output)
|
||||
.is_some_and(|lock| lock.wl_surface() == &root)
|
||||
})
|
||||
.cloned()
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub(crate) fn update_surface_preferences(&self, surface: &WlSurface) {
|
||||
use smithay::desktop::{WindowSurfaceType, find_popup_root_surface};
|
||||
use smithay::wayland::compositor::get_parent;
|
||||
|
||||
@@ -282,12 +282,12 @@ impl Ferese {
|
||||
frame: frame.clone(),
|
||||
buffer,
|
||||
},
|
||||
output,
|
||||
output: output.clone(),
|
||||
region: data.region,
|
||||
overlay_cursor: data.overlay_cursor,
|
||||
with_damage,
|
||||
});
|
||||
crate::backends::direct::render_all(self);
|
||||
crate::backends::direct::render_on(self, &[output]);
|
||||
}
|
||||
|
||||
pub(crate) fn process_screencopies<R>(
|
||||
|
||||
@@ -36,14 +36,18 @@ impl XdgShellHandler for Ferese {
|
||||
fn title_changed(&mut self, surface: ToplevelSurface) {
|
||||
if self.windows.refresh_metadata(surface.wl_surface()) {
|
||||
self.send_shell_snapshots();
|
||||
self.cursor_redraw_pending = true;
|
||||
for output in self.surface_outputs(surface.wl_surface()) {
|
||||
self.defer_output_redraw(output);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn app_id_changed(&mut self, surface: ToplevelSurface) {
|
||||
if self.windows.refresh_metadata(surface.wl_surface()) {
|
||||
self.send_shell_snapshots();
|
||||
self.cursor_redraw_pending = true;
|
||||
for output in self.surface_outputs(surface.wl_surface()) {
|
||||
self.defer_output_redraw(output);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user