From 81b9fb179bd7a882e3fd7bc3c10affc293d1f42c Mon Sep 17 00:00:00 2001 From: Victoria Brekenfeld Date: Mon, 18 Nov 2024 21:30:02 +0100 Subject: [PATCH] output-configuration: Support cosmic-ext v2 --- Cargo.lock | 12 ++--- src/backend/kms/device.rs | 6 ++- src/backend/kms/mod.rs | 3 ++ src/backend/kms/surface/mod.rs | 8 +++ src/utils/prelude.rs | 31 +++++++++++- src/wayland/handlers/output_configuration.rs | 8 +-- .../output_configuration/handlers/cosmic.rs | 23 +++++++++ .../output_configuration/handlers/wlr.rs | 4 +- .../protocols/output_configuration/mod.rs | 50 +++++++++++++++---- 9 files changed, 120 insertions(+), 25 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d759d8ce..4a38c8aa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -899,7 +899,7 @@ dependencies = [ [[package]] name = "cosmic-protocols" 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 = [ "bitflags 2.6.0", "wayland-backend", @@ -1064,7 +1064,7 @@ version = "0.19.0" source = "git+https://github.com/gfx-rs/wgpu?rev=20fda69#20fda698341efbdc870b8027d6d49f5bf3f36109" dependencies = [ "bitflags 2.6.0", - "libloading 0.8.5", + "libloading 0.7.4", "winapi", ] @@ -1199,7 +1199,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" dependencies = [ - "libloading 0.8.5", + "libloading 0.7.4", ] [[package]] @@ -2162,7 +2162,7 @@ dependencies = [ "bitflags 2.6.0", "com", "libc", - "libloading 0.8.5", + "libloading 0.7.4", "thiserror", "widestring", "winapi", @@ -2828,7 +2828,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" dependencies = [ "cfg-if", - "windows-targets 0.48.5", + "windows-targets 0.52.6", ] [[package]] @@ -5879,7 +5879,7 @@ dependencies = [ "js-sys", "khronos-egl", "libc", - "libloading 0.8.5", + "libloading 0.7.4", "log", "metal", "naga", diff --git a/src/backend/kms/device.rs b/src/backend/kms/device.rs index 1da09203..be22b7f9 100644 --- a/src/backend/kms/device.rs +++ b/src/backend/kms/device.rs @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-only use crate::{ - config::{OutputConfig, OutputState}, + config::{AdaptiveSync, OutputConfig, OutputState}, shell::Shell, utils::prelude::*, }; @@ -664,6 +664,10 @@ fn populate_modes( max_bpc, scale, 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) }; diff --git a/src/backend/kms/mod.rs b/src/backend/kms/mod.rs index 8edbd71d..b1e54710 100644 --- a/src/backend/kms/mod.rs +++ b/src/backend/kms/mod.rs @@ -684,6 +684,9 @@ impl KmsState { match surface.resume(drm_surface, gbm, cursor_size) { Ok(_) => { + surface.output.set_adaptive_sync_support( + surface.adaptive_sync_support().ok(), + ); if surface.use_adaptive_sync(vrr)? { surface.output.set_adaptive_sync(vrr); } else { diff --git a/src/backend/kms/surface/mod.rs b/src/backend/kms/surface/mod.rs index ce7a449b..e7893dee 100644 --- a/src/backend/kms/surface/mod.rs +++ b/src/backend/kms/surface/mod.rs @@ -405,6 +405,14 @@ impl Surface { rx.recv().context("Surface thread died")? } + pub fn adaptive_sync_support(&self) -> Result { + 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 { if vrr != AdaptiveSync::Disabled { let (tx, rx) = std::sync::mpsc::sync_channel(1); diff --git a/src/utils/prelude.rs b/src/utils/prelude.rs index 1984033f..6fc68ed5 100644 --- a/src/utils/prelude.rs +++ b/src/utils/prelude.rs @@ -1,4 +1,5 @@ use smithay::{ + backend::drm::VrrSupport as Support, output::{Output, WeakOutput}, utils::{Rectangle, Transform}, }; @@ -21,6 +22,8 @@ pub trait OutputExt { fn geometry(&self) -> Rectangle; fn adaptive_sync(&self) -> AdaptiveSync; fn set_adaptive_sync(&self, vrr: AdaptiveSync); + fn adaptive_sync_support(&self) -> Option; + fn set_adaptive_sync_support(&self, vrr: Option); fn mirroring(&self) -> Option; fn set_mirroring(&self, output: Option); @@ -30,7 +33,7 @@ pub trait OutputExt { } struct Vrr(AtomicU8); - +struct VrrSupport(AtomicU8); struct Mirroring(Mutex>); impl OutputExt for Output { @@ -72,6 +75,32 @@ impl OutputExt for Output { ); } + fn adaptive_sync_support(&self) -> Option { + self.user_data() + .get::() + .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) { + let user_data = self.user_data(); + user_data.insert_if_missing_threadsafe(|| VrrSupport(AtomicU8::new(0))); + user_data.get::().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 { self.user_data().get::().and_then(|mirroring| { mirroring diff --git a/src/wayland/handlers/output_configuration.rs b/src/wayland/handlers/output_configuration.rs index 6e8b23ce..eb900ddc 100644 --- a/src/wayland/handlers/output_configuration.rs +++ b/src/wayland/handlers/output_configuration.rs @@ -4,7 +4,7 @@ use smithay::{output::Output, utils::Point}; use tracing::{error, warn}; use crate::{ - config::{AdaptiveSync, OutputConfig, OutputState}, + config::{OutputConfig, OutputState}, state::State, wayland::protocols::output_configuration::{ delegate_output_configuration, ModeConfiguration, OutputConfiguration, @@ -120,11 +120,7 @@ impl State { current_config.position = (position.x as u32, position.y as u32); } if let Some(vrr) = adaptive_sync { - current_config.vrr = if *vrr { - AdaptiveSync::Force - } else { - AdaptiveSync::Disabled - }; + current_config.vrr = *vrr; } if let Some(mirror) = mirroring { current_config.enabled = OutputState::Mirroring(mirror.name()); diff --git a/src/wayland/protocols/output_configuration/handlers/cosmic.rs b/src/wayland/protocols/output_configuration/handlers/cosmic.rs index 61be21d6..f36d002d 100644 --- a/src/wayland/protocols/output_configuration/handlers/cosmic.rs +++ b/src/wayland/protocols/output_configuration/handlers/cosmic.rs @@ -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::() { + 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), + }; + } + } + } _ => {} } } diff --git a/src/wayland/protocols/output_configuration/handlers/wlr.rs b/src/wayland/protocols/output_configuration/handlers/wlr.rs index 56565c0c..1ac7ee19 100644 --- a/src/wayland/protocols/output_configuration/handlers/wlr.rs +++ b/src/wayland/protocols/output_configuration/handlers/wlr.rs @@ -481,8 +481,8 @@ where } pending.adaptive_sync = Some(match state.into_result() { Ok(state) => match state { - zwlr_output_head_v1::AdaptiveSyncState::Enabled => true, - _ => false, + zwlr_output_head_v1::AdaptiveSyncState::Enabled => AdaptiveSync::Force, + _ => AdaptiveSync::Disabled, }, Err(err) => { obj.post_error( diff --git a/src/wayland/protocols/output_configuration/mod.rs b/src/wayland/protocols/output_configuration/mod.rs index 8f32407e..a75c1d16 100644 --- a/src/wayland/protocols/output_configuration/mod.rs +++ b/src/wayland/protocols/output_configuration/mod.rs @@ -3,9 +3,11 @@ use cosmic_protocols::output_management::v1::server::{ zcosmic_output_configuration_head_v1::ZcosmicOutputConfigurationHeadV1, 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::{ + backend::drm::VrrSupport, output::{Mode, Output, WeakOutput}, reexports::{ wayland_protocols_wlr::output_management::v1::server::{ @@ -98,7 +100,7 @@ pub struct PendingOutputConfigurationInner { position: Option>, transform: Option, scale: Option, - adaptive_sync: Option, + adaptive_sync: Option, } pub type PendingOutputConfiguration = Mutex; @@ -110,7 +112,7 @@ pub enum OutputConfiguration { position: Option>, transform: Option, scale: Option, - adaptive_sync: Option, + adaptive_sync: Option, }, Disabled, } @@ -178,7 +180,7 @@ where ); let extension_global = dh.create_global::( - 1, + 2, OutputMngrGlobalData { filter: Box::new(client_filter), }, @@ -434,11 +436,6 @@ where let scale = output.current_scale().fractional_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 { instance @@ -449,6 +446,41 @@ where 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 {