kms: Allow diverging primary plane formats under certain conditions

This commit is contained in:
Victoria Brekenfeld 2025-01-02 21:32:47 +01:00 committed by Victoria Brekenfeld
parent b5cd62fd7a
commit 6be5009b37
5 changed files with 169 additions and 43 deletions

View file

@ -108,8 +108,9 @@ pub struct Surface {
known_nodes: HashSet<DrmNode>,
active: Arc<AtomicBool>,
feedback: HashMap<DrmNode, SurfaceDmabufFeedback>,
plane_formats: FormatSet,
pub(super) feedback: HashMap<DrmNode, SurfaceDmabufFeedback>,
pub(super) primary_plane_formats: FormatSet,
overlay_plane_formats: FormatSet,
loop_handle: LoopHandle<'static, State>,
thread_command: Sender<ThreadCommand>,
@ -239,7 +240,7 @@ pub enum ThreadCommand {
ScheduleRender,
AdaptiveSyncAvailable(SyncSender<Result<VrrSupport>>),
UseAdaptiveSync(AdaptiveSync),
AllowOverlayScanout(bool, SyncSender<()>),
AllowFrameFlags(bool, FrameFlags, SyncSender<()>),
End,
DpmsOff,
}
@ -309,6 +310,7 @@ impl Surface {
.surfaces
.get_mut(&crtc)
.unwrap();
state
.common
.send_dmabuf_feedback(&output_clone, &states, |source_node| {
@ -332,7 +334,8 @@ impl Surface {
target_node,
render_formats,
target_formats,
surface.plane_formats.clone(),
surface.primary_plane_formats.clone(),
surface.overlay_plane_formats.clone(),
)
})
.clone(),
@ -350,7 +353,8 @@ impl Surface {
known_nodes: HashSet::new(),
active,
feedback: HashMap::new(),
plane_formats: FormatSet::default(),
primary_plane_formats: FormatSet::default(),
overlay_plane_formats: FormatSet::default(),
loop_handle: evlh.clone(),
thread_command: tx,
thread_token,
@ -423,11 +427,11 @@ impl Surface {
Ok(true)
}
pub fn allow_overlay_scanout(&mut self, flag: bool) {
pub fn allow_frame_flags(&mut self, flag: bool, flags: FrameFlags) {
let (tx, rx) = std::sync::mpsc::sync_channel(1);
let _ = self
.thread_command
.send(ThreadCommand::AllowOverlayScanout(flag, tx));
.send(ThreadCommand::AllowFrameFlags(flag, flags, tx));
let _ = rx.recv();
}
@ -439,21 +443,18 @@ impl Surface {
pub fn resume(&mut self, compositor: GbmDrmOutput) -> Result<()> {
let (tx, rx) = std::sync::mpsc::sync_channel(1);
self.plane_formats = compositor.with_compositor(|c| {
c.surface()
.plane_info()
.formats
.iter()
.copied()
.chain(
(self.primary_plane_formats, self.overlay_plane_formats) =
compositor.with_compositor(|c| {
(
c.surface().plane_info().formats.clone(),
c.surface()
.planes()
.overlay
.iter()
.flat_map(|p| p.formats.iter().cloned()),
.flat_map(|p| p.formats.iter().cloned())
.collect::<FormatSet>(),
)
.collect::<FormatSet>()
});
});
let _ = self.thread_command.send(ThreadCommand::Resume {
compositor,
@ -615,20 +616,18 @@ fn surface_thread(
};
}
}
Event::Msg(ThreadCommand::AllowOverlayScanout(flag, tx)) => {
if !crate::utils::env::bool_var("COSMIC_DISABLE_DIRECT_SCANOUT").unwrap_or(false)
&& !crate::utils::env::bool_var("COSMIC_DISABLE_OVERLAY_SCANOUT")
.unwrap_or(false)
{
if flag {
state
.frame_flags
.insert(FrameFlags::ALLOW_OVERLAY_PLANE_SCANOUT);
} else {
state
.frame_flags
.remove(FrameFlags::ALLOW_OVERLAY_PLANE_SCANOUT);
}
Event::Msg(ThreadCommand::AllowFrameFlags(flag, mut flags, tx)) => {
if crate::utils::env::bool_var("COSMIC_DISABLE_DIRECT_SCANOUT").unwrap_or(false) {
flags.remove(FrameFlags::ALLOW_SCANOUT);
}
if crate::utils::env::bool_var("COSMIC_DISABLE_OVERLAY_SCANOUT").unwrap_or(false) {
flags.remove(FrameFlags::ALLOW_OVERLAY_PLANE_SCANOUT);
}
if flag {
state.frame_flags.insert(flags);
} else {
state.frame_flags.remove(flags);
}
let _ = tx.send(());
}
@ -1484,7 +1483,8 @@ fn get_surface_dmabuf_feedback(
target_node: DrmNode,
render_formats: FormatSet,
target_formats: FormatSet,
plane_formats: FormatSet,
primary_plane_formats: FormatSet,
overlay_plane_formats: FormatSet,
) -> SurfaceDmabufFeedback {
let combined_formats = render_formats
.intersection(&target_formats)
@ -1494,7 +1494,11 @@ fn get_surface_dmabuf_feedback(
// 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 planes_formats = plane_formats
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>();
@ -1514,12 +1518,29 @@ fn get_surface_dmabuf_feedback(
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 {
builder
.clone()
.add_preference_tranche(
target_node.dev_id(),
Some(zwp_linux_dmabuf_feedback_v1::TrancheFlags::Scanout),
primary_plane_formats.clone(),
)
.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),
planes_formats,
FormatSet::from_iter(
primary_plane_formats
.into_iter()
.chain(overlay_plane_formats.into_iter()),
),
)
.build()
.unwrap()
@ -1530,5 +1551,6 @@ fn get_surface_dmabuf_feedback(
SurfaceDmabufFeedback {
render_feedback,
scanout_feedback,
primary_scanout_feedback,
}
}