Avoid capture busy-waiting and redundant config and DMA-BUF checks
This commit is contained in:
1 parent
979afbd213
commit
392e9cfeb0
6 files changed
+246
-48
No files matched your search
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user