output-configuration: Support cosmic-ext v2

This commit is contained in:
Victoria Brekenfeld 2024-11-18 21:30:02 +01:00 committed by Victoria Brekenfeld
parent 80965a61b9
commit 81b9fb179b
9 changed files with 120 additions and 25 deletions

12
Cargo.lock generated
View file

@ -899,7 +899,7 @@ dependencies = [
[[package]] [[package]]
name = "cosmic-protocols" name = "cosmic-protocols"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/pop-os/cosmic-protocols?branch=main#ec1616b90fa6b4568709cfe2c0627b1e8cc887e0" source = "git+https://github.com/pop-os/cosmic-protocols?branch=main#27d70b6eb9c785a2a48341016f32a7b1ac4980ac"
dependencies = [ dependencies = [
"bitflags 2.6.0", "bitflags 2.6.0",
"wayland-backend", "wayland-backend",
@ -1064,7 +1064,7 @@ version = "0.19.0"
source = "git+https://github.com/gfx-rs/wgpu?rev=20fda69#20fda698341efbdc870b8027d6d49f5bf3f36109" source = "git+https://github.com/gfx-rs/wgpu?rev=20fda69#20fda698341efbdc870b8027d6d49f5bf3f36109"
dependencies = [ dependencies = [
"bitflags 2.6.0", "bitflags 2.6.0",
"libloading 0.8.5", "libloading 0.7.4",
"winapi", "winapi",
] ]
@ -1199,7 +1199,7 @@ version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412"
dependencies = [ dependencies = [
"libloading 0.8.5", "libloading 0.7.4",
] ]
[[package]] [[package]]
@ -2162,7 +2162,7 @@ dependencies = [
"bitflags 2.6.0", "bitflags 2.6.0",
"com", "com",
"libc", "libc",
"libloading 0.8.5", "libloading 0.7.4",
"thiserror", "thiserror",
"widestring", "widestring",
"winapi", "winapi",
@ -2828,7 +2828,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"windows-targets 0.48.5", "windows-targets 0.52.6",
] ]
[[package]] [[package]]
@ -5879,7 +5879,7 @@ dependencies = [
"js-sys", "js-sys",
"khronos-egl", "khronos-egl",
"libc", "libc",
"libloading 0.8.5", "libloading 0.7.4",
"log", "log",
"metal", "metal",
"naga", "naga",

View file

@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-3.0-only // SPDX-License-Identifier: GPL-3.0-only
use crate::{ use crate::{
config::{OutputConfig, OutputState}, config::{AdaptiveSync, OutputConfig, OutputState},
shell::Shell, shell::Shell,
utils::prelude::*, utils::prelude::*,
}; };
@ -664,6 +664,10 @@ fn populate_modes(
max_bpc, max_bpc,
scale, scale,
transform, transform,
// Try opportunistic VRR by default,
// if not supported this will be turned off on `resume`,
// when we have the `Surface` to actually check for support.
vrr: AdaptiveSync::Enabled,
..std::mem::take(&mut *output_config) ..std::mem::take(&mut *output_config)
}; };

View file

@ -684,6 +684,9 @@ impl KmsState {
match surface.resume(drm_surface, gbm, cursor_size) { match surface.resume(drm_surface, gbm, cursor_size) {
Ok(_) => { Ok(_) => {
surface.output.set_adaptive_sync_support(
surface.adaptive_sync_support().ok(),
);
if surface.use_adaptive_sync(vrr)? { if surface.use_adaptive_sync(vrr)? {
surface.output.set_adaptive_sync(vrr); surface.output.set_adaptive_sync(vrr);
} else { } else {

View file

@ -405,6 +405,14 @@ impl Surface {
rx.recv().context("Surface thread died")? rx.recv().context("Surface thread died")?
} }
pub fn adaptive_sync_support(&self) -> Result<VrrSupport> {
let (tx, rx) = std::sync::mpsc::sync_channel(1);
let _ = self
.thread_command
.send(ThreadCommand::AdaptiveSyncAvailable(tx));
rx.recv().context("Surface thread died")?
}
pub fn use_adaptive_sync(&mut self, vrr: AdaptiveSync) -> Result<bool> { pub fn use_adaptive_sync(&mut self, vrr: AdaptiveSync) -> Result<bool> {
if vrr != AdaptiveSync::Disabled { if vrr != AdaptiveSync::Disabled {
let (tx, rx) = std::sync::mpsc::sync_channel(1); let (tx, rx) = std::sync::mpsc::sync_channel(1);

View file

@ -1,4 +1,5 @@
use smithay::{ use smithay::{
backend::drm::VrrSupport as Support,
output::{Output, WeakOutput}, output::{Output, WeakOutput},
utils::{Rectangle, Transform}, utils::{Rectangle, Transform},
}; };
@ -21,6 +22,8 @@ pub trait OutputExt {
fn geometry(&self) -> Rectangle<i32, Global>; fn geometry(&self) -> Rectangle<i32, Global>;
fn adaptive_sync(&self) -> AdaptiveSync; fn adaptive_sync(&self) -> AdaptiveSync;
fn set_adaptive_sync(&self, vrr: AdaptiveSync); fn set_adaptive_sync(&self, vrr: AdaptiveSync);
fn adaptive_sync_support(&self) -> Option<Support>;
fn set_adaptive_sync_support(&self, vrr: Option<Support>);
fn mirroring(&self) -> Option<Output>; fn mirroring(&self) -> Option<Output>;
fn set_mirroring(&self, output: Option<Output>); fn set_mirroring(&self, output: Option<Output>);
@ -30,7 +33,7 @@ pub trait OutputExt {
} }
struct Vrr(AtomicU8); struct Vrr(AtomicU8);
struct VrrSupport(AtomicU8);
struct Mirroring(Mutex<Option<WeakOutput>>); struct Mirroring(Mutex<Option<WeakOutput>>);
impl OutputExt for Output { impl OutputExt for Output {
@ -72,6 +75,32 @@ impl OutputExt for Output {
); );
} }
fn adaptive_sync_support(&self) -> Option<Support> {
self.user_data()
.get::<VrrSupport>()
.map(|vrr| match vrr.0.load(Ordering::SeqCst) {
0 => None,
2 => Some(Support::RequiresModeset),
3 => Some(Support::Supported),
_ => Some(Support::NotSupported),
})
.flatten()
}
fn set_adaptive_sync_support(&self, vrr: Option<Support>) {
let user_data = self.user_data();
user_data.insert_if_missing_threadsafe(|| VrrSupport(AtomicU8::new(0)));
user_data.get::<VrrSupport>().unwrap().0.store(
match vrr {
None => 0,
Some(Support::NotSupported) => 1,
Some(Support::RequiresModeset) => 2,
Some(Support::Supported) => 3,
},
Ordering::SeqCst,
);
}
fn mirroring(&self) -> Option<Output> { fn mirroring(&self) -> Option<Output> {
self.user_data().get::<Mirroring>().and_then(|mirroring| { self.user_data().get::<Mirroring>().and_then(|mirroring| {
mirroring mirroring

View file

@ -4,7 +4,7 @@ use smithay::{output::Output, utils::Point};
use tracing::{error, warn}; use tracing::{error, warn};
use crate::{ use crate::{
config::{AdaptiveSync, OutputConfig, OutputState}, config::{OutputConfig, OutputState},
state::State, state::State,
wayland::protocols::output_configuration::{ wayland::protocols::output_configuration::{
delegate_output_configuration, ModeConfiguration, OutputConfiguration, delegate_output_configuration, ModeConfiguration, OutputConfiguration,
@ -120,11 +120,7 @@ impl State {
current_config.position = (position.x as u32, position.y as u32); current_config.position = (position.x as u32, position.y as u32);
} }
if let Some(vrr) = adaptive_sync { if let Some(vrr) = adaptive_sync {
current_config.vrr = if *vrr { current_config.vrr = *vrr;
AdaptiveSync::Force
} else {
AdaptiveSync::Disabled
};
} }
if let Some(mirror) = mirroring { if let Some(mirror) = mirroring {
current_config.enabled = OutputState::Mirroring(mirror.name()); current_config.enabled = OutputState::Mirroring(mirror.name());

View file

@ -270,6 +270,29 @@ where
} }
} }
} }
zcosmic_output_configuration_head_v1::Request::SetAdaptiveSyncExt { state } => {
if let Ok(obj) = obj.upgrade() {
if let Some(data) = obj.data::<PendingOutputConfiguration>() {
let mut pending = data.lock().unwrap();
if pending.adaptive_sync.is_some() {
obj.post_error(
zwlr_output_configuration_head_v1::Error::AlreadySet,
format!("{:?} already had an adaptive_sync state configured", obj),
);
return;
}
pending.adaptive_sync = match state.into_result() {
Ok(zcosmic_output_head_v1::AdaptiveSyncStateExt::Always) => {
Some(AdaptiveSync::Force)
}
Ok(zcosmic_output_head_v1::AdaptiveSyncStateExt::Automatic) => {
Some(AdaptiveSync::Enabled)
}
_ => Some(AdaptiveSync::Disabled),
};
}
}
}
_ => {} _ => {}
} }
} }

View file

@ -481,8 +481,8 @@ where
} }
pending.adaptive_sync = Some(match state.into_result() { pending.adaptive_sync = Some(match state.into_result() {
Ok(state) => match state { Ok(state) => match state {
zwlr_output_head_v1::AdaptiveSyncState::Enabled => true, zwlr_output_head_v1::AdaptiveSyncState::Enabled => AdaptiveSync::Force,
_ => false, _ => AdaptiveSync::Disabled,
}, },
Err(err) => { Err(err) => {
obj.post_error( obj.post_error(

View file

@ -3,9 +3,11 @@
use cosmic_protocols::output_management::v1::server::{ use cosmic_protocols::output_management::v1::server::{
zcosmic_output_configuration_head_v1::ZcosmicOutputConfigurationHeadV1, zcosmic_output_configuration_head_v1::ZcosmicOutputConfigurationHeadV1,
zcosmic_output_configuration_v1::ZcosmicOutputConfigurationV1, zcosmic_output_configuration_v1::ZcosmicOutputConfigurationV1,
zcosmic_output_head_v1::ZcosmicOutputHeadV1, zcosmic_output_manager_v1::ZcosmicOutputManagerV1, zcosmic_output_head_v1::{self, ZcosmicOutputHeadV1},
zcosmic_output_manager_v1::ZcosmicOutputManagerV1,
}; };
use smithay::{ use smithay::{
backend::drm::VrrSupport,
output::{Mode, Output, WeakOutput}, output::{Mode, Output, WeakOutput},
reexports::{ reexports::{
wayland_protocols_wlr::output_management::v1::server::{ wayland_protocols_wlr::output_management::v1::server::{
@ -98,7 +100,7 @@ pub struct PendingOutputConfigurationInner {
position: Option<Point<i32, Logical>>, position: Option<Point<i32, Logical>>,
transform: Option<Transform>, transform: Option<Transform>,
scale: Option<f64>, scale: Option<f64>,
adaptive_sync: Option<bool>, adaptive_sync: Option<AdaptiveSync>,
} }
pub type PendingOutputConfiguration = Mutex<PendingOutputConfigurationInner>; pub type PendingOutputConfiguration = Mutex<PendingOutputConfigurationInner>;
@ -110,7 +112,7 @@ pub enum OutputConfiguration {
position: Option<Point<i32, Logical>>, position: Option<Point<i32, Logical>>,
transform: Option<Transform>, transform: Option<Transform>,
scale: Option<f64>, scale: Option<f64>,
adaptive_sync: Option<bool>, adaptive_sync: Option<AdaptiveSync>,
}, },
Disabled, Disabled,
} }
@ -178,7 +180,7 @@ where
); );
let extension_global = dh.create_global::<D, ZcosmicOutputManagerV1, _>( let extension_global = dh.create_global::<D, ZcosmicOutputManagerV1, _>(
1, 2,
OutputMngrGlobalData { OutputMngrGlobalData {
filter: Box::new(client_filter), filter: Box::new(client_filter),
}, },
@ -434,11 +436,6 @@ where
let scale = output.current_scale().fractional_scale(); let scale = output.current_scale().fractional_scale();
instance.obj.scale(scale); instance.obj.scale(scale);
if let Some(extension_obj) = instance.extension_obj.as_ref() {
extension_obj.scale_1000((scale * 1000.0).round() as i32);
extension_obj.mirroring(output.mirroring().map(|o| o.name()));
}
if instance.obj.version() >= zwlr_output_head_v1::EVT_ADAPTIVE_SYNC_SINCE { if instance.obj.version() >= zwlr_output_head_v1::EVT_ADAPTIVE_SYNC_SINCE {
instance instance
@ -449,6 +446,41 @@ where
zwlr_output_head_v1::AdaptiveSyncState::Enabled zwlr_output_head_v1::AdaptiveSyncState::Enabled
}); });
} }
if let Some(extension_obj) = instance.extension_obj.as_ref() {
extension_obj.scale_1000((scale * 1000.0).round() as i32);
extension_obj.mirroring(output.mirroring().map(|o| o.name()));
if extension_obj.version() >= zcosmic_output_head_v1::EVT_ADAPTIVE_SYNC_EXT_SINCE {
extension_obj.adaptive_sync_ext(match output.adaptive_sync() {
AdaptiveSync::Disabled => {
zcosmic_output_head_v1::AdaptiveSyncStateExt::Disabled
}
AdaptiveSync::Enabled => {
zcosmic_output_head_v1::AdaptiveSyncStateExt::Automatic
}
AdaptiveSync::Force => zcosmic_output_head_v1::AdaptiveSyncStateExt::Always,
});
extension_obj.adaptive_sync_available(
match output
.adaptive_sync_support()
.unwrap_or(VrrSupport::NotSupported)
{
VrrSupport::NotSupported => {
zcosmic_output_head_v1::AdaptiveSyncAvailability::Unsupported
}
VrrSupport::RequiresModeset => {
zcosmic_output_head_v1::AdaptiveSyncAvailability::RequiresModeset
}
VrrSupport::Supported => {
zcosmic_output_head_v1::AdaptiveSyncAvailability::Supported
}
},
);
}
}
} }
if instance.obj.version() >= zwlr_output_head_v1::EVT_MAKE_SINCE { if instance.obj.version() >= zwlr_output_head_v1::EVT_MAKE_SINCE {