Avoid capture busy-waiting and redundant config and DMA-BUF checks

This commit is contained in:
Samuel Onoja committed 2026-10-25 15:37:52 +01:00
1 parent 979afbd213
commit 392e9cfeb0
6 files changed
+246 -48

No files matched your search

+20 -11
View File
@@ -159,6 +159,7 @@ fn candidate_geometry(
&& has_storage()
}
#[derive(Clone)]
struct OutputView<'a> {
global: DmabufGlobal,
feedback: &'a OutputFeedback,
@@ -187,16 +188,19 @@ fn select<'a>(
}
pub(crate) fn refresh(state: &mut Ferese) {
if state.dmabuf_feedback.requested().next().is_none() {
return;
}
let mut preferred = HashMap::new();
if let Some(backend) = state.direct_backend.as_ref() {
for (surface, global) in state.dmabuf_feedback.requested() {
let id = Id::from(surface);
let outputs = backend
.devices
.values()
.flat_map(|device| device.outputs.values().map(move |output| (device, output)))
.filter(|(_, output)| state.output_id(&output.output).is_some());
let views = outputs.map(|(device, output)| {
// Eligibility belongs to an output, so compute it once for all subscribers.
let outputs = backend
.devices
.values()
.flat_map(|device| device.outputs.values().map(move |output| (device, output)))
.filter(|(_, output)| state.output_id(&output.output).is_some());
let views: Vec<_> = outputs
.map(|(device, output)| {
let eligible = (backend.can_render()
&& device.drm.is_active()
&& output.power.can_render()
@@ -233,9 +237,14 @@ pub(crate) fn refresh(state: &mut Ferese) {
feedback: &output.dmabuf_feedback,
eligible,
}
});
if let Some(feedback) = select(global, &id, views) {
preferred.insert(surface.clone(), feedback.clone());
})
.collect();
if views.iter().any(|view| view.eligible.is_some()) {
for (surface, global) in state.dmabuf_feedback.requested() {
let id = Id::from(surface);
if let Some(feedback) = select(global, &id, views.iter().cloned()) {
preferred.insert(surface.clone(), feedback.clone());
}
}
}
}
+11 -5
View File
@@ -1,7 +1,6 @@
//! Allocation hints retain the import global's renderer as a composition fallback.
use std::collections::HashMap;
use smithay::reexports::wayland_server::Resource;
use smithay::reexports::wayland_server::protocol::wl_surface::WlSurface;
use smithay::wayland::compositor::with_states;
use smithay::wayland::dmabuf::{DmabufFeedback, DmabufGlobal, SurfaceDmabufFeedbackState};
@@ -9,6 +8,7 @@ use smithay::wayland::dmabuf::{DmabufFeedback, DmabufGlobal, SurfaceDmabufFeedba
struct Surface {
global: DmabufGlobal,
fallback: DmabufFeedback,
current: DmabufFeedback,
}
#[derive(Default)]
@@ -33,6 +33,7 @@ impl FeedbackManager {
Surface {
global,
fallback: fallback.clone(),
current: fallback.clone(),
},
);
Some(fallback)
@@ -45,17 +46,21 @@ impl FeedbackManager {
}
pub fn refresh(&mut self, preferred: &HashMap<WlSurface, DmabufFeedback>) {
self.surfaces.retain(|surface, _| surface.is_alive());
for (surface, record) in &self.surfaces {
for (surface, record) in &mut self.surfaces {
let feedback = if self.globals.contains_key(&record.global) {
preferred.get(surface).unwrap_or(&record.fallback)
} else {
&record.fallback
};
// Smithay owns subscriptions, protocol messages and equality suppression.
if &record.current == feedback {
continue;
}
// Avoid locking surface state on every dispatch when its allocation
// hints are unchanged. Smithay still owns subscriptions and messages.
with_states(surface, |states| {
if let Some(state) = SurfaceDmabufFeedbackState::from_states(states) {
state.set_feedback(feedback);
record.current = feedback.clone();
}
});
}
@@ -65,7 +70,7 @@ impl FeedbackManager {
self.globals.remove(&global);
for (surface, record) in self
.surfaces
.iter()
.iter_mut()
.filter(|(_, record)| record.global == global)
{
// V4 requires a main-device tranche. Retain last-known render
@@ -74,6 +79,7 @@ impl FeedbackManager {
with_states(surface, |states| {
if let Some(state) = SurfaceDmabufFeedbackState::from_states(states) {
state.set_feedback(&record.fallback);
record.current = record.fallback.clone();
}
});
}
+6 -3
View File
@@ -161,7 +161,7 @@ fn subscriptions_update_deduplicate_and_retire_device_preferences() {
state.display_handle.flush_clients().unwrap();
assert!(
messages(&mut wire).is_empty(),
"Smithay suppresses unchanged feedback"
"unchanged feedback must not be published again"
);
request(&mut wire, 8, 3, &[10, 2], None);
@@ -227,6 +227,9 @@ fn subscriptions_update_deduplicate_and_retire_device_preferences() {
);
drop(wire);
dispatch(&mut events, &mut state);
state.dmabuf_feedback.refresh(&HashMap::new());
assert_eq!(state.dmabuf_feedback.requested().count(), 0);
assert_eq!(
state.dmabuf_feedback.requested().count(),
0,
"surface destruction must remove subscriptions without a refresh scan"
);
}