diff --git a/src/ifs/head_management.rs b/src/ifs/head_management.rs index e15cd19b..d3d734b9 100644 --- a/src/ifs/head_management.rs +++ b/src/ifs/head_management.rs @@ -131,6 +131,8 @@ enum HeadOp { SetVrrMode(VrrMode), SetTearingMode(TearingMode), SetFormat(&'static Format), + SetTransferFunction(BackendTransferFunction), + SetColorSpace(BackendColorSpace), } #[derive(Copy, Clone, Debug, Eq, PartialEq, Default)] @@ -280,6 +282,10 @@ impl HeadManagers { ext.send_mode(state); head.session.schedule_done(); } + if let Some(ext) = &head.ext.drm_color_space_setter_v1 { + ext.send_supported(state); + head.session.schedule_done(); + } } } @@ -310,6 +316,10 @@ impl HeadManagers { ext.send_state(state); head.session.schedule_done(); } + if let Some(ext) = &head.ext.drm_color_space_setter_v1 { + ext.send_supported(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 f6862a77..99bbe9a1 100644 --- a/src/ifs/head_management/head_management_macros.rs +++ b/src/ifs/head_management/head_management_macros.rs @@ -409,4 +409,5 @@ declare_extensions! { jay_vrr_mode_setter_v1: JayVrrModeSetterV1, jay_tearing_mode_setter_v1: JayTearingModeSetterV1, format_setter_v1: FormatSetterV1, + drm_color_space_setter_v1: DrmColorSpaceSetterV1, } diff --git a/src/ifs/head_management/jay_head_ext.rs b/src/ifs/head_management/jay_head_ext.rs index 3eb0ee22..a901d8d9 100644 --- a/src/ifs/head_management/jay_head_ext.rs +++ b/src/ifs/head_management/jay_head_ext.rs @@ -6,6 +6,7 @@ pub(super) mod jay_head_ext_compositor_space_transformer_v1; 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_drm_color_space_setter_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; diff --git a/src/ifs/head_management/jay_head_ext/jay_head_ext_drm_color_space_setter_v1.rs b/src/ifs/head_management/jay_head_ext/jay_head_ext_drm_color_space_setter_v1.rs new file mode 100644 index 00000000..d6f7f486 --- /dev/null +++ b/src/ifs/head_management/jay_head_ext/jay_head_ext_drm_color_space_setter_v1.rs @@ -0,0 +1,129 @@ +use { + crate::{ + backend::{BackendColorSpace, BackendTransferFunction}, + ifs::head_management::{HeadOp, HeadState}, + video::drm::{ + DRM_MODE_COLORIMETRY_BT2020_RGB, DRM_MODE_COLORIMETRY_DEFAULT, HDMI_EOTF_SMPTE_ST2084, + HDMI_EOTF_TRADITIONAL_GAMMA_SDR, + }, + wire::{ + jay_head_ext_drm_color_space_setter_v1::{ + JayHeadExtDrmColorSpaceSetterV1RequestHandler, Reset, SetColorimetry, SetHdmiEotf, + SupportedColorimetry, SupportedHdmiEotf, + }, + jay_head_manager_ext_drm_color_space_setter_v1::JayHeadManagerExtDrmColorSpaceSetterV1RequestHandler, + }, + }, + isnt::std_1::primitive::IsntSlice2Ext, + std::rc::Rc, +}; + +impl_drm_color_space_setter_v1! { + version = 1, + after_announce = after_announce, + after_transaction = after_transaction, +} + +impl HeadName { + fn after_announce(&self, shared: &HeadState) { + self.send_supported(shared); + } + + fn after_transaction(&self, shared: &HeadState, tran: &HeadState) { + if shared.monitor_info != tran.monitor_info { + self.send_supported(shared); + } + } + + pub(in super::super) fn send_supported(&self, state: &HeadState) { + self.client.event(Reset { self_id: self.id }); + let Some(mi) = &state.monitor_info else { + return; + }; + self.send_supported_eotf(HDMI_EOTF_TRADITIONAL_GAMMA_SDR); + for tf in &mi.transfer_functions { + self.send_supported_eotf(tf.to_drm()); + } + self.send_supported_colorimetry(DRM_MODE_COLORIMETRY_DEFAULT); + for cs in &mi.color_spaces { + self.send_supported_colorimetry(cs.to_drm()); + } + } + + fn send_supported_eotf(&self, eotf: u8) { + self.client.event(SupportedHdmiEotf { + self_id: self.id, + eotf: eotf as u32, + }); + } + + fn send_supported_colorimetry(&self, colorimetry: u64) { + self.client.event(SupportedColorimetry { + self_id: self.id, + colorimetry: colorimetry as u32, + }); + } +} + +impl JayHeadManagerExtDrmColorSpaceSetterV1RequestHandler for MgrName { + type Error = ErrorName; + + mgr_common_req!(); +} + +impl JayHeadExtDrmColorSpaceSetterV1RequestHandler for HeadName { + type Error = ErrorName; + + head_common_req!(); + + fn set_hdmi_eotf(&self, req: SetHdmiEotf, _slf: &Rc) -> Result<(), Self::Error> { + const DEFAULT: u32 = HDMI_EOTF_TRADITIONAL_GAMMA_SDR as u32; + const PQ: u32 = HDMI_EOTF_SMPTE_ST2084 as u32; + let eotf = match req.eotf { + DEFAULT => BackendTransferFunction::Default, + PQ => BackendTransferFunction::Pq, + _ => return Err(ErrorName::UnknownEotf(req.eotf)), + }; + if eotf != BackendTransferFunction::Default { + let state = &*self.common.transaction_state.borrow(); + let Some(mi) = &state.monitor_info else { + return Err(ErrorName::UnsupportedEotf(req.eotf)); + }; + if mi.transfer_functions.not_contains(&eotf) { + return Err(ErrorName::UnsupportedEotf(req.eotf)); + } + } + self.common.push_op(HeadOp::SetTransferFunction(eotf))?; + Ok(()) + } + + fn set_colorimetry(&self, req: SetColorimetry, _slf: &Rc) -> Result<(), Self::Error> { + let cs = match req.colorimetry as u64 { + DRM_MODE_COLORIMETRY_DEFAULT => BackendColorSpace::Default, + DRM_MODE_COLORIMETRY_BT2020_RGB => BackendColorSpace::Bt2020, + _ => return Err(ErrorName::UnknownColorimetry(req.colorimetry)), + }; + if cs != BackendColorSpace::Default { + let state = &*self.common.transaction_state.borrow(); + let Some(mi) = &state.monitor_info else { + return Err(ErrorName::UnsupportedColorimetry(req.colorimetry)); + }; + if mi.color_spaces.not_contains(&cs) { + return Err(ErrorName::UnsupportedColorimetry(req.colorimetry)); + } + } + self.common.push_op(HeadOp::SetColorSpace(cs))?; + Ok(()) + } +} + +error! { + #[error("Unknown EOTF {0}")] + UnknownEotf(u32), + #[error("Unknown colorimetry {0}")] + UnknownColorimetry(u32), + #[error("Unsupported EOTF {0}")] + UnsupportedEotf(u32), + #[error("Unsupported colorimetry {0}")] + UnsupportedColorimetry(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 94d97dd8..c6fb87f5 100644 --- a/src/ifs/head_management/jay_head_manager_session_v1.rs +++ b/src/ifs/head_management/jay_head_manager_session_v1.rs @@ -267,6 +267,8 @@ impl JayHeadManagerSessionV1 { new.mode = desired.mode; new.non_desktop_override = desired.override_non_desktop; new.format = desired.format; + new.color_space = desired.color_space; + new.transfer_function = desired.transfer_function; if old == new { continue; } @@ -389,6 +391,7 @@ impl JayHeadManagerSessionV1RequestHandler for JayHeadManagerSessionV1 { VRR_MODE_INFO = 1 << 8, TEARING_MODE_INFO = 1 << 9, FORMAT_INFO = 1 << 10, + DRM_COLOR_SPACE_INFO = 1 << 11, COMPOSITOR_SPACE_INFO_ENABLED = 1 << 13, } for head in self.heads.lock().values() { @@ -446,6 +449,14 @@ impl JayHeadManagerSessionV1RequestHandler for JayHeadManagerSessionV1 { state.format = f; to_send |= FORMAT_INFO; } + HeadOp::SetTransferFunction(e) => { + state.transfer_function = e; + to_send |= DRM_COLOR_SPACE_INFO; + } + HeadOp::SetColorSpace(c) => { + state.color_space = c; + to_send |= DRM_COLOR_SPACE_INFO; + } } } if to_send.contains(CORE_INFO) @@ -499,6 +510,11 @@ impl JayHeadManagerSessionV1RequestHandler for JayHeadManagerSessionV1 { { i.send_format(state); } + if to_send.contains(DRM_COLOR_SPACE_INFO) + && let Some(i) = &head.ext.drm_color_space_info_v1 + { + i.send_state(state); + } } slf.schedule_transaction_result(req.result, None)?; Ok(()) diff --git a/wire/jay_head_ext_drm_color_space_setter_v1.txt b/wire/jay_head_ext_drm_color_space_setter_v1.txt new file mode 100644 index 00000000..9ce7eec0 --- /dev/null +++ b/wire/jay_head_ext_drm_color_space_setter_v1.txt @@ -0,0 +1,23 @@ +request destroy (destructor) { + +} + +event reset { + +} + +event supported_hdmi_eotf { + eotf: u32, +} + +event supported_colorimetry { + colorimetry: u32, +} + +request set_hdmi_eotf { + eotf: u32, +} + +request set_colorimetry { + colorimetry: u32, +} diff --git a/wire/jay_head_manager_ext_drm_color_space_setter_v1.txt b/wire/jay_head_manager_ext_drm_color_space_setter_v1.txt new file mode 100644 index 00000000..178120ba --- /dev/null +++ b/wire/jay_head_manager_ext_drm_color_space_setter_v1.txt @@ -0,0 +1,7 @@ +request destroy (destructor) { + +} + +event head { + head: id(jay_head_ext_drm_color_space_setter_v1) (new), +}