kms/surface: Simpify surface feedback creation

This commit is contained in:
Victoria Brekenfeld 2025-12-19 19:00:20 +01:00 committed by Victoria Brekenfeld
parent 85d8b8dc06
commit d17a4ead68
4 changed files with 121 additions and 91 deletions

View file

@ -852,35 +852,36 @@ impl KmsGuard<'_> {
if !test_only {
if !surface.is_active() {
let mut planes = drm
.device()
.planes(crtc)
.with_context(|| "Failed to enumerate planes")?;
let driver = drm.device().get_driver().ok();
// QUIRK: Using an overlay plane on a nvidia card breaks the display controller (wtf...)
if driver.as_ref().is_some_and(|driver| {
driver
.name()
.to_string_lossy()
.to_lowercase()
.contains("nvidia")
}) {
planes.overlay = vec![];
}
// QUIRK: Cursor planes on evdi sometimes don't disappear correctly.
// TODO: Debug and figure out, as they can be a nice improvement.
if driver.as_ref().is_some_and(|driver| {
driver
.name()
.to_string_lossy()
.to_lowercase()
.contains("evdi")
}) {
planes.cursor = vec![];
}
let compositor: GbmDrmOutput = {
let mut planes = drm
.device()
.planes(crtc)
.with_context(|| "Failed to enumerate planes")?;
let driver = drm.device().get_driver().ok();
// QUIRK: Using an overlay plane on a nvidia card breaks the display controller (wtf...)
if driver.as_ref().is_some_and(|driver| {
driver
.name()
.to_string_lossy()
.to_lowercase()
.contains("nvidia")
}) {
planes.overlay = vec![];
}
// QUIRK: Cursor planes on evdi sometimes don't disappear correctly.
// TODO: Debug and figure out, as they can be a nice improvement.
if driver.as_ref().is_some_and(|driver| {
driver
.name()
.to_string_lossy()
.to_lowercase()
.contains("evdi")
}) {
planes.cursor = vec![];
}
let mut renderer = self
.api
.single_renderer(&device.inner.render_node)
@ -908,7 +909,7 @@ impl KmsGuard<'_> {
*mode,
&[conn],
&surface.output,
Some(planes),
Some(planes.clone()),
&mut renderer,
&elements,
)
@ -943,16 +944,17 @@ impl KmsGuard<'_> {
.unwrap(),
)
.ok();
let primary_formats = compositor_ref.surface().plane_info().formats.clone();
let overlay_formats = planes
.overlay
.iter()
.flat_map(|p| p.formats.iter().cloned())
.collect::<FormatSet>();
surface.resume(
compositor,
compositor_ref.surface().plane_info().formats.clone(),
compositor_ref
.surface()
.planes()
.overlay
.iter()
.flat_map(|p| p.formats.iter().cloned())
.collect::<FormatSet>(),
primary_formats,
Some(overlay_formats).filter(|f| !f.indexset().is_empty()),
);
surface.output.set_adaptive_sync_support(vrr_support);

View file

@ -120,7 +120,7 @@ pub struct Surface {
active: Arc<AtomicBool>,
pub(super) feedback: HashMap<DrmNode, SurfaceDmabufFeedback>,
pub(super) primary_plane_formats: FormatSet,
overlay_plane_formats: FormatSet,
overlay_plane_formats: Option<FormatSet>,
loop_handle: LoopHandle<'static, State>,
thread_command: Sender<ThreadCommand>,
@ -343,7 +343,7 @@ impl Surface {
active,
feedback: HashMap::new(),
primary_plane_formats: FormatSet::default(),
overlay_plane_formats: FormatSet::default(),
overlay_plane_formats: None,
loop_handle: evlh.clone(),
thread_command: tx,
thread_token,
@ -436,7 +436,7 @@ impl Surface {
&mut self,
compositor: GbmDrmOutput,
primary_plane_formats: FormatSet,
overlay_plane_formats: FormatSet,
overlay_plane_formats: Option<FormatSet>,
) {
self.primary_plane_formats = primary_plane_formats;
self.overlay_plane_formats = overlay_plane_formats;
@ -1528,75 +1528,82 @@ fn get_surface_dmabuf_feedback(
render_node: DrmNode,
target_node: DrmNode,
render_formats: FormatSet,
target_formats: FormatSet,
_target_formats: FormatSet,
primary_plane_formats: FormatSet,
overlay_plane_formats: FormatSet,
overlay_plane_formats: Option<FormatSet>,
) -> SurfaceDmabufFeedback {
let combined_formats = render_formats
.intersection(&target_formats)
.copied()
.collect::<FormatSet>();
// We limit the scan-out trache to formats we can also render from
// so that there is always a fallback render path available in case
// the supplied buffer can not be scanned out directly
let primary_plane_formats = primary_plane_formats
.intersection(&combined_formats)
.copied()
.collect::<FormatSet>();
let overlay_plane_formats = overlay_plane_formats
.intersection(&combined_formats)
.copied()
.collect::<FormatSet>();
let primary_plane_formats = primary_plane_formats
.intersection(&render_formats)
.cloned()
.collect::<FormatSet>();
let overlay_plane_formats = overlay_plane_formats.map(|formats| {
formats
.intersection(&render_formats)
.cloned()
.collect::<FormatSet>()
});
let builder = DmabufFeedbackBuilder::new(render_node.dev_id(), render_formats);
/*
// iris doesn't handle nvidia buffers very well (it hangs).
// so only do this in the future with v6 and clients telling us the gpu
// Sadly no implementation would pick this up as a preferred render tranche,
// where the combined formats would increase our chances of doing a dmabuf copy.
// .. So we should probably not advertise this on the off-chance it actually triggers bugs.
//
let combined_formats = render_formats.intersection(&target_formats).cloned().collect::<FormatSet>();
if target_node != render_node.dev_id() && !combined_formats.is_empty() {
builder = builder.add_preference_tranche(
target_node,
render_node.dev_id(),
None,
combined_formats,
);
};
// We also can't advertise scan out tranches for the actual display device,
// as e.g. the nvidia driver might then send us dmabufs, that makes e.g. the iris hangs on import...
if target_node != render_node.dev_id() && !combined_formats.is_empty() {
builder = builder.add_preference_tranche(
target_node.dev_id(),
Some(zwp_linux_dmabuf_feedback_v1::TrancheFlags::Scanout),
combined_formats,
);
};
// So no fun combinations, we gotta wait for dmabuf-v6
*/
let render_feedback = builder.clone().build().unwrap();
// we would want to do this in other cases as well, but same thing as above applies
let primary_scanout_feedback = if target_node == render_node {
let primary_scanout_feedback = (target_node == render_node).then(|| {
builder
.clone()
.add_preference_tranche(
target_node.dev_id(),
render_node.dev_id(),
Some(zwp_linux_dmabuf_feedback_v1::TrancheFlags::Scanout),
primary_plane_formats.clone(),
primary_plane_formats,
)
.build()
.unwrap()
} else {
builder.clone().build().unwrap()
};
let scanout_feedback = if target_node == render_node {
builder
.add_preference_tranche(
target_node.dev_id(),
Some(zwp_linux_dmabuf_feedback_v1::TrancheFlags::Scanout),
FormatSet::from_iter(
primary_plane_formats
.into_iter()
.chain(overlay_plane_formats),
),
)
.build()
.unwrap()
} else {
builder.build().unwrap()
};
});
let overlay_scanout_feedback = overlay_plane_formats
.filter(|_| target_node == render_node)
.map(|formats| {
builder
.add_preference_tranche(
render_node.dev_id(),
Some(zwp_linux_dmabuf_feedback_v1::TrancheFlags::Scanout),
formats,
)
.build()
.unwrap()
});
SurfaceDmabufFeedback {
render_feedback,
scanout_feedback,
overlay_scanout_feedback,
primary_scanout_feedback,
}
}

View file

@ -688,9 +688,15 @@ impl CosmicSurface {
render_element_states,
&feedback.render_feedback,
if is_fullscreen {
&feedback.primary_scanout_feedback
feedback
.primary_scanout_feedback
.as_ref()
.unwrap_or(&feedback.render_feedback)
} else {
&feedback.scanout_feedback
feedback
.overlay_scanout_feedback
.as_ref()
.unwrap_or(&feedback.render_feedback)
},
)
})

View file

@ -313,8 +313,8 @@ pub enum LockedBackend<'a> {
#[derive(Debug, Clone)]
pub struct SurfaceDmabufFeedback {
pub render_feedback: DmabufFeedback,
pub scanout_feedback: DmabufFeedback,
pub primary_scanout_feedback: DmabufFeedback,
pub overlay_scanout_feedback: Option<DmabufFeedback>,
pub primary_scanout_feedback: Option<DmabufFeedback>,
}
#[derive(Debug)]
@ -1035,7 +1035,10 @@ impl Common {
surface,
render_element_states,
&feedback.render_feedback,
&feedback.primary_scanout_feedback,
feedback
.primary_scanout_feedback
.as_ref()
.unwrap_or(&feedback.render_feedback),
)
},
)
@ -1064,7 +1067,10 @@ impl Common {
surface,
render_element_states,
&feedback.render_feedback,
&feedback.scanout_feedback,
feedback
.overlay_scanout_feedback
.as_ref()
.unwrap_or(&feedback.render_feedback),
)
},
);
@ -1085,7 +1091,10 @@ impl Common {
surface,
render_element_states,
&feedback.render_feedback,
&feedback.scanout_feedback,
feedback
.overlay_scanout_feedback
.as_ref()
.unwrap_or(&feedback.render_feedback),
)
},
);
@ -1192,7 +1201,10 @@ impl Common {
surface,
render_element_states,
&feedback.render_feedback,
&feedback.scanout_feedback,
feedback
.overlay_scanout_feedback
.as_ref()
.unwrap_or(&feedback.render_feedback),
)
},
)
@ -1214,7 +1226,10 @@ impl Common {
surface,
render_element_states,
&feedback.render_feedback,
&feedback.scanout_feedback,
feedback
.overlay_scanout_feedback
.as_ref()
.unwrap_or(&feedback.render_feedback),
)
},
);