From 15e68fc551b8ff421d9062d70008de79672b8b76 Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Mon, 14 Jul 2025 15:46:57 +0200 Subject: [PATCH] head-management: add format-setter-v1 extension --- src/compositor.rs | 1 + src/ifs/head_management.rs | 14 ++++ .../head_management/head_management_macros.rs | 1 + src/ifs/head_management/jay_head_ext.rs | 1 + .../jay_head_ext_format_setter_v1.rs | 78 +++++++++++++++++++ .../jay_head_manager_session_v1.rs | 11 +++ src/tasks/connector.rs | 2 + src/utils/rc_eq.rs | 1 + wire/jay_head_ext_format_setter_v1.txt | 15 ++++ .../jay_head_manager_ext_format_setter_v1.txt | 7 ++ 10 files changed, 131 insertions(+) create mode 100644 src/ifs/head_management/jay_head_ext/jay_head_ext_format_setter_v1.rs create mode 100644 wire/jay_head_ext_format_setter_v1.txt create mode 100644 wire/jay_head_manager_ext_format_setter_v1.txt diff --git a/src/compositor.rs b/src/compositor.rs index 382bc46e..1217fa0f 100644 --- a/src/compositor.rs +++ b/src/compositor.rs @@ -661,6 +661,7 @@ fn create_dummy_output(state: &Rc) { format: XRGB8888, color_space: backend_state.color_space, transfer_function: backend_state.transfer_function, + supported_formats: Default::default(), }; let connector_data = Rc::new(ConnectorData { id, diff --git a/src/ifs/head_management.rs b/src/ifs/head_management.rs index 0d691b5f..e15cd19b 100644 --- a/src/ifs/head_management.rs +++ b/src/ifs/head_management.rs @@ -91,6 +91,7 @@ pub struct HeadState { pub format: &'static Format, pub color_space: BackendColorSpace, pub transfer_function: BackendTransferFunction, + pub supported_formats: RcEq>, } impl HeadState { @@ -129,6 +130,7 @@ enum HeadOp { SetNonDesktopOverride(Option), SetVrrMode(VrrMode), SetTearingMode(TearingMode), + SetFormat(&'static Format), } #[derive(Copy, Clone, Debug, Eq, PartialEq, Default)] @@ -481,4 +483,16 @@ impl HeadManagers { } } } + + pub fn handle_formats_change(&self, formats: &Rc>) { + let state = &mut *self.state.borrow_mut(); + state.supported_formats.0 = formats.clone(); + for head in self.managers.lock().values() { + skip_in_transaction!(head); + if let Some(ext) = &head.ext.format_setter_v1 { + ext.send_supported_formats(state); + head.session.schedule_done(); + } + } + } } diff --git a/src/ifs/head_management/head_management_macros.rs b/src/ifs/head_management/head_management_macros.rs index 5b7dfcfa..f6862a77 100644 --- a/src/ifs/head_management/head_management_macros.rs +++ b/src/ifs/head_management/head_management_macros.rs @@ -408,4 +408,5 @@ declare_extensions! { jay_tearing_mode_info_v1: JayTearingModeInfoV1, jay_vrr_mode_setter_v1: JayVrrModeSetterV1, jay_tearing_mode_setter_v1: JayTearingModeSetterV1, + format_setter_v1: FormatSetterV1, } diff --git a/src/ifs/head_management/jay_head_ext.rs b/src/ifs/head_management/jay_head_ext.rs index e5ca8933..3eb0ee22 100644 --- a/src/ifs/head_management/jay_head_ext.rs +++ b/src/ifs/head_management/jay_head_ext.rs @@ -7,6 +7,7 @@ pub(super) mod jay_head_ext_connector_info_v1; pub(super) mod jay_head_ext_core_info_v1; pub(super) mod jay_head_ext_drm_color_space_info_v1; pub(super) mod jay_head_ext_format_info_v1; +pub(super) mod jay_head_ext_format_setter_v1; pub(super) mod jay_head_ext_jay_tearing_mode_info_v1; pub(super) mod jay_head_ext_jay_tearing_mode_setter_v1; pub(super) mod jay_head_ext_jay_vrr_mode_info_v1; diff --git a/src/ifs/head_management/jay_head_ext/jay_head_ext_format_setter_v1.rs b/src/ifs/head_management/jay_head_ext/jay_head_ext_format_setter_v1.rs new file mode 100644 index 00000000..09207aa7 --- /dev/null +++ b/src/ifs/head_management/jay_head_ext/jay_head_ext_format_setter_v1.rs @@ -0,0 +1,78 @@ +use { + crate::{ + format::formats, + ifs::head_management::{HeadOp, HeadState}, + wire::{ + jay_head_ext_format_setter_v1::{ + JayHeadExtFormatSetterV1RequestHandler, Reset, SetFormat, SupportedFormat, + }, + jay_head_manager_ext_format_setter_v1::JayHeadManagerExtFormatSetterV1RequestHandler, + }, + }, + isnt::std_1::primitive::IsntSlice2Ext, + std::rc::Rc, +}; + +impl_format_setter_v1! { + version = 1, + after_announce = after_announce, + after_transaction = after_transaction, +} + +impl HeadName { + fn after_announce(&self, shared: &HeadState) { + self.send_supported_formats(shared); + } + + fn after_transaction(&self, shared: &HeadState, tran: &HeadState) { + if shared.supported_formats != tran.supported_formats { + self.send_supported_formats(shared); + } + } + + pub(in super::super) fn send_supported_formats(&self, state: &HeadState) { + self.client.event(Reset { self_id: self.id }); + for format in &*state.supported_formats { + self.client.event(SupportedFormat { + self_id: self.id, + format: format.drm, + }); + } + } +} + +impl JayHeadManagerExtFormatSetterV1RequestHandler for MgrName { + type Error = ErrorName; + + mgr_common_req!(); +} + +impl JayHeadExtFormatSetterV1RequestHandler for HeadName { + type Error = ErrorName; + + head_common_req!(); + + fn set_format(&self, req: SetFormat, _slf: &Rc) -> Result<(), Self::Error> { + let Some(format) = formats().get(&req.format) else { + return Err(ErrorName::UnknownFormat(req.format)); + }; + if self + .common + .transaction_state + .borrow() + .supported_formats + .not_contains(format) + { + return Err(ErrorName::UnsupportedFormat(req.format)); + } + self.common.push_op(HeadOp::SetFormat(format))?; + Ok(()) + } +} + +error! { + #[error("Unknown format {0}")] + UnknownFormat(u32), + #[error("Unsupported format {0}")] + UnsupportedFormat(u32), +} diff --git a/src/ifs/head_management/jay_head_manager_session_v1.rs b/src/ifs/head_management/jay_head_manager_session_v1.rs index c049c315..94d97dd8 100644 --- a/src/ifs/head_management/jay_head_manager_session_v1.rs +++ b/src/ifs/head_management/jay_head_manager_session_v1.rs @@ -266,6 +266,7 @@ impl JayHeadManagerSessionV1 { new.enabled = desired.connector_enabled; new.mode = desired.mode; new.non_desktop_override = desired.override_non_desktop; + new.format = desired.format; if old == new { continue; } @@ -387,6 +388,7 @@ impl JayHeadManagerSessionV1RequestHandler for JayHeadManagerSessionV1 { NON_DESKTOP_INFO = 1 << 7, VRR_MODE_INFO = 1 << 8, TEARING_MODE_INFO = 1 << 9, + FORMAT_INFO = 1 << 10, COMPOSITOR_SPACE_INFO_ENABLED = 1 << 13, } for head in self.heads.lock().values() { @@ -440,6 +442,10 @@ impl JayHeadManagerSessionV1RequestHandler for JayHeadManagerSessionV1 { state.tearing_mode = m; to_send |= TEARING_MODE_INFO; } + HeadOp::SetFormat(f) => { + state.format = f; + to_send |= FORMAT_INFO; + } } } if to_send.contains(CORE_INFO) @@ -488,6 +494,11 @@ impl JayHeadManagerSessionV1RequestHandler for JayHeadManagerSessionV1 { { i.send_mode(state); } + if to_send.contains(FORMAT_INFO) + && let Some(i) = &head.ext.format_info_v1 + { + i.send_format(state); + } } slf.schedule_transaction_result(req.result, None)?; Ok(()) diff --git a/src/tasks/connector.rs b/src/tasks/connector.rs index fb9dd1ad..668b5fe5 100644 --- a/src/tasks/connector.rs +++ b/src/tasks/connector.rs @@ -67,6 +67,7 @@ pub fn handle(state: &Rc, connector: &Rc) { format: backend_state.format, color_space: backend_state.color_space, transfer_function: backend_state.transfer_function, + supported_formats: Default::default(), }; let data = Rc::new(ConnectorData { id, @@ -324,6 +325,7 @@ impl ConnectorHandler { self.state.refresh_hardware_cursors(); } ConnectorEvent::FormatsChanged(formats) => { + self.data.head_managers.handle_formats_change(&formats); on.global.formats.set(formats); } ConnectorEvent::State(state) => { diff --git a/src/utils/rc_eq.rs b/src/utils/rc_eq.rs index 378fcc24..9c7e855c 100644 --- a/src/utils/rc_eq.rs +++ b/src/utils/rc_eq.rs @@ -4,6 +4,7 @@ pub fn rc_eq(a: &Rc, b: &Rc) -> bool { Rc::as_ptr(a) as *const u8 == Rc::as_ptr(b) as *const u8 } +#[derive(Default)] pub struct RcEq(pub Rc); impl Clone for RcEq { diff --git a/wire/jay_head_ext_format_setter_v1.txt b/wire/jay_head_ext_format_setter_v1.txt new file mode 100644 index 00000000..4608eeda --- /dev/null +++ b/wire/jay_head_ext_format_setter_v1.txt @@ -0,0 +1,15 @@ +request destroy (destructor) { + +} + +event reset { + +} + +event supported_format { + format: u32, +} + +request set_format { + format: u32, +} diff --git a/wire/jay_head_manager_ext_format_setter_v1.txt b/wire/jay_head_manager_ext_format_setter_v1.txt new file mode 100644 index 00000000..5d9db104 --- /dev/null +++ b/wire/jay_head_manager_ext_format_setter_v1.txt @@ -0,0 +1,7 @@ +request destroy (destructor) { + +} + +event head { + head: id(jay_head_ext_format_setter_v1) (new), +}