1
0
Fork 0
forked from wry/wry

color-management: add more capabilities

This commit is contained in:
Julian Orth 2025-03-02 15:16:07 +01:00
parent e92de36f7a
commit 8f992f7cef
13 changed files with 293 additions and 97 deletions

View file

@ -560,6 +560,10 @@ impl MetalConnector {
} }
return None; return None;
}; };
if ct.cd.id != self.state.color_manager.srgb_srgb().id {
// Direct scanout requires identical color descriptions.
return None;
}
if ct.alpha.is_some() { if ct.alpha.is_some() {
// Direct scanout with alpha factor is not supported. // Direct scanout with alpha factor is not supported.
return None; return None;

View file

@ -17,7 +17,6 @@ impl Luminance {
white: F64(80.0), white: F64(80.0),
}; };
#[expect(dead_code)]
pub const BT1886: Self = Self { pub const BT1886: Self = Self {
min: F64(0.01), min: F64(0.01),
max: F64(100.0), max: F64(100.0),

View file

@ -100,12 +100,10 @@ impl ColorManager {
&self.srgb_linear &self.srgb_linear
} }
#[expect(dead_code)]
pub fn windows_scrgb(&self) -> &Rc<ColorDescription> { pub fn windows_scrgb(&self) -> &Rc<ColorDescription> {
&self.windows_scrgb &self.windows_scrgb
} }
#[expect(dead_code)]
pub fn get_description( pub fn get_description(
self: &Rc<Self>, self: &Rc<Self>,
named_primaries: Option<NamedPrimaries>, named_primaries: Option<NamedPrimaries>,

View file

@ -3,23 +3,14 @@ use {crate::utils::ordered_float::F64, std::hash::Hash};
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub enum NamedPrimaries { pub enum NamedPrimaries {
Srgb, Srgb,
#[expect(dead_code)]
PalM, PalM,
#[expect(dead_code)]
Pal, Pal,
#[expect(dead_code)]
Ntsc, Ntsc,
#[expect(dead_code)]
GenericFilm, GenericFilm,
#[expect(dead_code)]
Bt2020, Bt2020,
#[expect(dead_code)]
Cie1931Xyz, Cie1931Xyz,
#[expect(dead_code)]
DciP3, DciP3,
#[expect(dead_code)]
DisplayP3, DisplayP3,
#[expect(dead_code)]
AdobeRgb, AdobeRgb,
} }
@ -103,7 +94,6 @@ impl Primaries {
}; };
} }
impl NamedPrimaries { impl NamedPrimaries {
#[expect(dead_code)]
pub const fn primaries(self) -> Primaries { pub const fn primaries(self) -> Primaries {
match self { match self {
NamedPrimaries::Srgb => Primaries::SRGB, NamedPrimaries::Srgb => Primaries::SRGB,

View file

@ -1,56 +1,63 @@
pub use consts::*;
pub mod wp_color_management_output_v1; pub mod wp_color_management_output_v1;
pub mod wp_color_management_surface_feedback_v1; pub mod wp_color_management_surface_feedback_v1;
pub mod wp_color_management_surface_v1;
pub mod wp_color_manager_v1; pub mod wp_color_manager_v1;
pub mod wp_image_description_creator_icc_v1; pub mod wp_image_description_creator_icc_v1;
pub mod wp_image_description_creator_params_v1; pub mod wp_image_description_creator_params_v1;
pub mod wp_image_description_info_v1; pub mod wp_image_description_info_v1;
pub mod wp_image_description_v1; pub mod wp_image_description_v1;
const PRIMARIES_MUL: f64 = 1_000_000.0;
const PRIMARIES_MUL_INV: f64 = 1.0 / PRIMARIES_MUL;
const MIN_LUM_MUL: f64 = 10_000.0;
const MIN_LUM_MUL_INV: f64 = 1.0 / MIN_LUM_MUL;
#[expect(dead_code)] #[expect(dead_code)]
mod consts { mod consts {
pub(super) const RENDER_INTENT_PERCEPTUAL: u32 = 0; pub const RENDER_INTENT_PERCEPTUAL: u32 = 0;
pub(super) const RENDER_INTENT_RELATIVE: u32 = 1; pub const RENDER_INTENT_RELATIVE: u32 = 1;
pub(super) const RENDER_INTENT_SATURATION: u32 = 2; pub const RENDER_INTENT_SATURATION: u32 = 2;
pub(super) const RENDER_INTENT_ABSOLUTE: u32 = 3; pub const RENDER_INTENT_ABSOLUTE: u32 = 3;
pub(super) const RENDER_INTENT_RELATIVE_BPC: u32 = 4; pub const RENDER_INTENT_RELATIVE_BPC: u32 = 4;
pub(super) const FEATURE_ICC_V2_V4: u32 = 0; pub const FEATURE_ICC_V2_V4: u32 = 0;
pub(super) const FEATURE_PARAMETRIC: u32 = 1; pub const FEATURE_PARAMETRIC: u32 = 1;
pub(super) const FEATURE_SET_PRIMARIES: u32 = 2; pub const FEATURE_SET_PRIMARIES: u32 = 2;
pub(super) const FEATURE_SET_TF_POWER: u32 = 3; pub const FEATURE_SET_TF_POWER: u32 = 3;
pub(super) const FEATURE_SET_LUMINANCES: u32 = 4; pub const FEATURE_SET_LUMINANCES: u32 = 4;
pub(super) const FEATURE_SET_MASTERING_DISPLAY_PRIMARIES: u32 = 5; pub const FEATURE_SET_MASTERING_DISPLAY_PRIMARIES: u32 = 5;
pub(super) const FEATURE_EXTENDED_TARGET_VOLUME: u32 = 6; pub const FEATURE_EXTENDED_TARGET_VOLUME: u32 = 6;
pub(super) const FEATURE_WINDOWS_SCRGB: u32 = 7; pub const FEATURE_WINDOWS_SCRGB: u32 = 7;
pub(super) const PRIMARIES_SRGB: u32 = 1; pub const PRIMARIES_SRGB: u32 = 1;
pub(super) const PRIMARIES_PAL_M: u32 = 2; pub const PRIMARIES_PAL_M: u32 = 2;
pub(super) const PRIMARIES_PAL: u32 = 3; pub const PRIMARIES_PAL: u32 = 3;
pub(super) const PRIMARIES_NTSC: u32 = 4; pub const PRIMARIES_NTSC: u32 = 4;
pub(super) const PRIMARIES_GENERIC_FILM: u32 = 5; pub const PRIMARIES_GENERIC_FILM: u32 = 5;
pub(super) const PRIMARIES_BT2020: u32 = 6; pub const PRIMARIES_BT2020: u32 = 6;
pub(super) const PRIMARIES_CIE1931_XYZ: u32 = 7; pub const PRIMARIES_CIE1931_XYZ: u32 = 7;
pub(super) const PRIMARIES_DCI_P3: u32 = 8; pub const PRIMARIES_DCI_P3: u32 = 8;
pub(super) const PRIMARIES_DISPLAY_P3: u32 = 9; pub const PRIMARIES_DISPLAY_P3: u32 = 9;
pub(super) const PRIMARIES_ADOBE_RGB: u32 = 10; pub const PRIMARIES_ADOBE_RGB: u32 = 10;
pub(super) const TRANSFER_FUNCTION_BT1886: u32 = 1; pub const TRANSFER_FUNCTION_BT1886: u32 = 1;
pub(super) const TRANSFER_FUNCTION_GAMMA22: u32 = 2; pub const TRANSFER_FUNCTION_GAMMA22: u32 = 2;
pub(super) const TRANSFER_FUNCTION_GAMMA28: u32 = 3; pub const TRANSFER_FUNCTION_GAMMA28: u32 = 3;
pub(super) const TRANSFER_FUNCTION_ST240: u32 = 4; pub const TRANSFER_FUNCTION_ST240: u32 = 4;
pub(super) const TRANSFER_FUNCTION_EXT_LINEAR: u32 = 5; pub const TRANSFER_FUNCTION_EXT_LINEAR: u32 = 5;
pub(super) const TRANSFER_FUNCTION_LOG_100: u32 = 6; pub const TRANSFER_FUNCTION_LOG_100: u32 = 6;
pub(super) const TRANSFER_FUNCTION_LOG_316: u32 = 7; pub const TRANSFER_FUNCTION_LOG_316: u32 = 7;
pub(super) const TRANSFER_FUNCTION_XVYCC: u32 = 8; pub const TRANSFER_FUNCTION_XVYCC: u32 = 8;
pub(super) const TRANSFER_FUNCTION_SRGB: u32 = 9; pub const TRANSFER_FUNCTION_SRGB: u32 = 9;
pub(super) const TRANSFER_FUNCTION_EXT_SRGB: u32 = 10; pub const TRANSFER_FUNCTION_EXT_SRGB: u32 = 10;
pub(super) const TRANSFER_FUNCTION_ST2084_PQ: u32 = 11; pub const TRANSFER_FUNCTION_ST2084_PQ: u32 = 11;
pub(super) const TRANSFER_FUNCTION_ST428: u32 = 12; pub const TRANSFER_FUNCTION_ST428: u32 = 12;
pub(super) const TRANSFER_FUNCTION_HLG: u32 = 13; pub const TRANSFER_FUNCTION_HLG: u32 = 13;
pub(super) const CAUSE_LOW_VERSION: u32 = 0; pub const CAUSE_LOW_VERSION: u32 = 0;
pub(super) const CAUSE_UNSUPPORTED: u32 = 1; pub const CAUSE_UNSUPPORTED: u32 = 1;
pub(super) const CAUSE_OPERATING_SYSTEM: u32 = 2; pub const CAUSE_OPERATING_SYSTEM: u32 = 2;
pub(super) const CAUSE_NO_OUTPUT: u32 = 3; pub const CAUSE_NO_OUTPUT: u32 = 3;
} }

View file

@ -43,10 +43,11 @@ impl WpColorManagementOutputV1RequestHandler for WpColorManagementOutputV1 {
client: self.client.clone(), client: self.client.clone(),
version: self.version, version: self.version,
tracker: Default::default(), tracker: Default::default(),
description: self.client.state.color_manager.srgb_srgb().clone(),
}); });
track!(self.client, obj); track!(self.client, obj);
self.client.add_client_obj(&obj)?; self.client.add_client_obj(&obj)?;
obj.send_ready(0); obj.send_ready();
Ok(()) Ok(())
} }
} }

View file

@ -30,10 +30,11 @@ impl WpColorManagementSurfaceFeedbackV1 {
client: self.client.clone(), client: self.client.clone(),
version: self.version, version: self.version,
tracker: Default::default(), tracker: Default::default(),
description: self.client.state.color_manager.srgb_srgb().clone(),
}); });
track!(self.client, obj); track!(self.client, obj);
self.client.add_client_obj(&obj)?; self.client.add_client_obj(&obj)?;
obj.send_ready(0); obj.send_ready();
Ok(()) Ok(())
} }
} }

View file

@ -2,15 +2,27 @@ use {
crate::{ crate::{
client::{Client, ClientError}, client::{Client, ClientError},
globals::{Global, GlobalName}, globals::{Global, GlobalName},
ifs::color_management::{ ifs::{
consts::{ color_management::{
FEATURE_PARAMETRIC, PRIMARIES_SRGB, RENDER_INTENT_PERCEPTUAL, consts::{
TRANSFER_FUNCTION_SRGB, FEATURE_PARAMETRIC, FEATURE_SET_LUMINANCES, FEATURE_SET_PRIMARIES,
FEATURE_WINDOWS_SCRGB, PRIMARIES_ADOBE_RGB, PRIMARIES_BT2020,
PRIMARIES_CIE1931_XYZ, PRIMARIES_DCI_P3, PRIMARIES_DISPLAY_P3,
PRIMARIES_GENERIC_FILM, PRIMARIES_NTSC, PRIMARIES_PAL, PRIMARIES_PAL_M,
PRIMARIES_SRGB, RENDER_INTENT_PERCEPTUAL, TRANSFER_FUNCTION_BT1886,
TRANSFER_FUNCTION_EXT_LINEAR, TRANSFER_FUNCTION_EXT_SRGB,
TRANSFER_FUNCTION_GAMMA22, TRANSFER_FUNCTION_GAMMA28,
TRANSFER_FUNCTION_LOG_100, TRANSFER_FUNCTION_LOG_316, TRANSFER_FUNCTION_SRGB,
TRANSFER_FUNCTION_ST240, TRANSFER_FUNCTION_ST428, TRANSFER_FUNCTION_ST2084_PQ,
},
wp_color_management_output_v1::WpColorManagementOutputV1,
wp_color_management_surface_feedback_v1::WpColorManagementSurfaceFeedbackV1,
wp_image_description_creator_params_v1::WpImageDescriptionCreatorParamsV1,
wp_image_description_v1::WpImageDescriptionV1,
},
wl_surface::wp_color_management_surface_v1::{
WpColorManagementSurfaceV1, WpColorManagementSurfaceV1Error,
}, },
wp_color_management_output_v1::WpColorManagementOutputV1,
wp_color_management_surface_feedback_v1::WpColorManagementSurfaceFeedbackV1,
wp_color_management_surface_v1::WpColorManagementSurfaceV1,
wp_image_description_creator_params_v1::WpImageDescriptionCreatorParamsV1,
}, },
leaks::Tracker, leaks::Tracker,
object::{Object, Version}, object::{Object, Version},
@ -63,8 +75,30 @@ impl WpColorManagerV1 {
fn send_capabilities(&self) { fn send_capabilities(&self) {
self.send_supported_intent(RENDER_INTENT_PERCEPTUAL); self.send_supported_intent(RENDER_INTENT_PERCEPTUAL);
self.send_supported_feature(FEATURE_PARAMETRIC); self.send_supported_feature(FEATURE_PARAMETRIC);
self.send_supported_feature(FEATURE_SET_PRIMARIES);
self.send_supported_feature(FEATURE_SET_LUMINANCES);
self.send_supported_feature(FEATURE_WINDOWS_SCRGB);
self.send_supported_tf_named(TRANSFER_FUNCTION_BT1886);
self.send_supported_tf_named(TRANSFER_FUNCTION_GAMMA22);
self.send_supported_tf_named(TRANSFER_FUNCTION_GAMMA28);
self.send_supported_tf_named(TRANSFER_FUNCTION_ST240);
self.send_supported_tf_named(TRANSFER_FUNCTION_EXT_LINEAR);
self.send_supported_tf_named(TRANSFER_FUNCTION_LOG_100);
self.send_supported_tf_named(TRANSFER_FUNCTION_LOG_316);
self.send_supported_tf_named(TRANSFER_FUNCTION_SRGB); self.send_supported_tf_named(TRANSFER_FUNCTION_SRGB);
self.send_supported_tf_named(TRANSFER_FUNCTION_EXT_SRGB);
self.send_supported_tf_named(TRANSFER_FUNCTION_ST2084_PQ);
self.send_supported_tf_named(TRANSFER_FUNCTION_ST428);
self.send_supported_primaries_named(PRIMARIES_SRGB); self.send_supported_primaries_named(PRIMARIES_SRGB);
self.send_supported_primaries_named(PRIMARIES_PAL_M);
self.send_supported_primaries_named(PRIMARIES_PAL);
self.send_supported_primaries_named(PRIMARIES_NTSC);
self.send_supported_primaries_named(PRIMARIES_GENERIC_FILM);
self.send_supported_primaries_named(PRIMARIES_BT2020);
self.send_supported_primaries_named(PRIMARIES_CIE1931_XYZ);
self.send_supported_primaries_named(PRIMARIES_DCI_P3);
self.send_supported_primaries_named(PRIMARIES_DISPLAY_P3);
self.send_supported_primaries_named(PRIMARIES_ADOBE_RGB);
self.send_done(); self.send_done();
} }
@ -123,15 +157,17 @@ impl WpColorManagerV1RequestHandler for WpColorManagerV1 {
} }
fn get_surface(&self, req: GetSurface, _slf: &Rc<Self>) -> Result<(), Self::Error> { fn get_surface(&self, req: GetSurface, _slf: &Rc<Self>) -> Result<(), Self::Error> {
let _ = self.client.lookup(req.surface)?; let surface = self.client.lookup(req.surface)?;
let obj = Rc::new(WpColorManagementSurfaceV1 { let obj = Rc::new(WpColorManagementSurfaceV1 {
id: req.id, id: req.id,
client: self.client.clone(), client: self.client.clone(),
version: self.version, version: self.version,
tracker: Default::default(), tracker: Default::default(),
surface: surface.clone(),
}); });
track!(self.client, obj); track!(self.client, obj);
self.client.add_client_obj(&obj)?; self.client.add_client_obj(&obj)?;
obj.install()?;
Ok(()) Ok(())
} }
@ -170,6 +206,9 @@ impl WpColorManagerV1RequestHandler for WpColorManagerV1 {
client: self.client.clone(), client: self.client.clone(),
version: self.version, version: self.version,
tracker: Default::default(), tracker: Default::default(),
tf: Default::default(),
primaries: Default::default(),
luminance: Default::default(),
}); });
track!(self.client, obj); track!(self.client, obj);
self.client.add_client_obj(&obj)?; self.client.add_client_obj(&obj)?;
@ -178,10 +217,20 @@ impl WpColorManagerV1RequestHandler for WpColorManagerV1 {
fn create_windows_scrgb( fn create_windows_scrgb(
&self, &self,
_req: CreateWindowsScrgb, req: CreateWindowsScrgb,
_slf: &Rc<Self>, _slf: &Rc<Self>,
) -> Result<(), Self::Error> { ) -> Result<(), Self::Error> {
Err(WpColorManagerV1Error::CreateWindowsScrgbNotSupported) let obj = Rc::new(WpImageDescriptionV1 {
id: req.image_description,
client: self.client.clone(),
version: self.version,
tracker: Default::default(),
description: self.client.state.color_manager.windows_scrgb().clone(),
});
track!(self.client, obj);
self.client.add_client_obj(&obj)?;
obj.send_ready();
Ok(())
} }
} }
@ -222,7 +271,7 @@ pub enum WpColorManagerV1Error {
ClientError(Box<ClientError>), ClientError(Box<ClientError>),
#[error("create_icc_creator is not supported")] #[error("create_icc_creator is not supported")]
CreateIccCreatorNotSupported, CreateIccCreatorNotSupported,
#[error("create_windows_scrgb is not supported")] #[error(transparent)]
CreateWindowsScrgbNotSupported, Surface(#[from] WpColorManagementSurfaceV1Error),
} }
efrom!(WpColorManagerV1Error, ClientError); efrom!(WpColorManagerV1Error, ClientError);

View file

@ -1,12 +1,27 @@
use { use {
crate::{ crate::{
client::{Client, ClientError}, client::{Client, ClientError},
cmm::{
cmm_luminance::Luminance,
cmm_primaries::{NamedPrimaries, Primaries},
cmm_transfer_function::TransferFunction,
},
ifs::color_management::{ ifs::color_management::{
consts::{PRIMARIES_SRGB, TRANSFER_FUNCTION_SRGB}, MIN_LUM_MUL_INV, PRIMARIES_MUL_INV,
consts::{
PRIMARIES_ADOBE_RGB, PRIMARIES_BT2020, PRIMARIES_CIE1931_XYZ, PRIMARIES_DCI_P3,
PRIMARIES_DISPLAY_P3, PRIMARIES_GENERIC_FILM, PRIMARIES_NTSC, PRIMARIES_PAL,
PRIMARIES_PAL_M, PRIMARIES_SRGB, TRANSFER_FUNCTION_BT1886,
TRANSFER_FUNCTION_EXT_LINEAR, TRANSFER_FUNCTION_EXT_SRGB,
TRANSFER_FUNCTION_GAMMA22, TRANSFER_FUNCTION_GAMMA28, TRANSFER_FUNCTION_LOG_100,
TRANSFER_FUNCTION_LOG_316, TRANSFER_FUNCTION_SRGB, TRANSFER_FUNCTION_ST240,
TRANSFER_FUNCTION_ST428, TRANSFER_FUNCTION_ST2084_PQ,
},
wp_image_description_v1::WpImageDescriptionV1, wp_image_description_v1::WpImageDescriptionV1,
}, },
leaks::Tracker, leaks::Tracker,
object::{Object, Version}, object::{Object, Version},
utils::ordered_float::F64,
wire::{ wire::{
WpImageDescriptionCreatorParamsV1Id, WpImageDescriptionCreatorParamsV1Id,
wp_image_description_creator_params_v1::{ wp_image_description_creator_params_v1::{
@ -16,7 +31,7 @@ use {
}, },
}, },
}, },
std::rc::Rc, std::{cell::Cell, rc::Rc},
thiserror::Error, thiserror::Error,
}; };
@ -25,30 +40,74 @@ pub struct WpImageDescriptionCreatorParamsV1 {
pub client: Rc<Client>, pub client: Rc<Client>,
pub version: Version, pub version: Version,
pub tracker: Tracker<Self>, pub tracker: Tracker<Self>,
pub tf: Cell<Option<TransferFunction>>,
pub primaries: Cell<Option<(Option<NamedPrimaries>, Primaries)>>,
pub luminance: Cell<Option<Luminance>>,
} }
impl WpImageDescriptionCreatorParamsV1RequestHandler for WpImageDescriptionCreatorParamsV1 { impl WpImageDescriptionCreatorParamsV1RequestHandler for WpImageDescriptionCreatorParamsV1 {
type Error = WpImageDescriptionCreatorParamsV1Error; type Error = WpImageDescriptionCreatorParamsV1Error;
fn create(&self, req: Create, _slf: &Rc<Self>) -> Result<(), Self::Error> { fn create(&self, req: Create, _slf: &Rc<Self>) -> Result<(), Self::Error> {
let Some(transfer_function) = self.tf.get() else {
return Err(WpImageDescriptionCreatorParamsV1Error::TfNotSet);
};
let Some((named_primaries, primaries)) = self.primaries.get() else {
return Err(WpImageDescriptionCreatorParamsV1Error::PrimariesNotSet);
};
let default_luminance = match transfer_function {
TransferFunction::Bt1886 => Luminance::BT1886,
TransferFunction::St2084Pq => Luminance::ST2084_PQ,
_ => Luminance::SRGB,
};
let mut luminance = self.luminance.get().unwrap_or(default_luminance);
if transfer_function == TransferFunction::St2084Pq {
luminance.max.0 = luminance.min.0 + 10_000.0;
}
if luminance.max.0 <= luminance.min.0 || luminance.white.0 <= luminance.min.0 {
return Err(WpImageDescriptionCreatorParamsV1Error::MinLuminanceTooLow);
}
let description = self.client.state.color_manager.get_description(
named_primaries,
primaries,
luminance,
transfer_function,
);
let obj = Rc::new(WpImageDescriptionV1 { let obj = Rc::new(WpImageDescriptionV1 {
id: req.image_description, id: req.image_description,
client: self.client.clone(), client: self.client.clone(),
version: self.version, version: self.version,
tracker: Default::default(), tracker: Default::default(),
description,
}); });
track!(self.client, obj); track!(self.client, obj);
self.client.add_client_obj(&obj)?; self.client.add_client_obj(&obj)?;
obj.send_ready(0); obj.send_ready();
self.client.remove_obj(self)?; self.client.remove_obj(self)?;
Ok(()) Ok(())
} }
fn set_tf_named(&self, req: SetTfNamed, _slf: &Rc<Self>) -> Result<(), Self::Error> { fn set_tf_named(&self, req: SetTfNamed, _slf: &Rc<Self>) -> Result<(), Self::Error> {
if req.tf != TRANSFER_FUNCTION_SRGB { let tf = match req.tf {
return Err(WpImageDescriptionCreatorParamsV1Error::UnsupportedTf( TRANSFER_FUNCTION_BT1886 => TransferFunction::Bt1886,
req.tf, TRANSFER_FUNCTION_GAMMA22 => TransferFunction::Gamma22,
)); TRANSFER_FUNCTION_GAMMA28 => TransferFunction::Gamma28,
TRANSFER_FUNCTION_ST240 => TransferFunction::St240,
TRANSFER_FUNCTION_EXT_LINEAR => TransferFunction::Linear,
TRANSFER_FUNCTION_LOG_100 => TransferFunction::Log100,
TRANSFER_FUNCTION_LOG_316 => TransferFunction::Log316,
TRANSFER_FUNCTION_SRGB => TransferFunction::Srgb,
TRANSFER_FUNCTION_EXT_SRGB => TransferFunction::ExtSrgb,
TRANSFER_FUNCTION_ST2084_PQ => TransferFunction::St2084Pq,
TRANSFER_FUNCTION_ST428 => TransferFunction::St428,
_ => {
return Err(WpImageDescriptionCreatorParamsV1Error::UnsupportedTf(
req.tf,
));
}
};
if self.tf.replace(Some(tf)).is_some() {
return Err(WpImageDescriptionCreatorParamsV1Error::TfAlreadySet);
} }
Ok(()) Ok(())
} }
@ -62,20 +121,55 @@ impl WpImageDescriptionCreatorParamsV1RequestHandler for WpImageDescriptionCreat
req: SetPrimariesNamed, req: SetPrimariesNamed,
_slf: &Rc<Self>, _slf: &Rc<Self>,
) -> Result<(), Self::Error> { ) -> Result<(), Self::Error> {
if req.primaries != PRIMARIES_SRGB { let primaries = match req.primaries {
return Err( PRIMARIES_SRGB => NamedPrimaries::Srgb,
WpImageDescriptionCreatorParamsV1Error::UnsupportedPrimaries(req.primaries), PRIMARIES_PAL_M => NamedPrimaries::PalM,
); PRIMARIES_PAL => NamedPrimaries::Pal,
PRIMARIES_NTSC => NamedPrimaries::Ntsc,
PRIMARIES_GENERIC_FILM => NamedPrimaries::GenericFilm,
PRIMARIES_BT2020 => NamedPrimaries::Bt2020,
PRIMARIES_CIE1931_XYZ => NamedPrimaries::Cie1931Xyz,
PRIMARIES_DCI_P3 => NamedPrimaries::DciP3,
PRIMARIES_DISPLAY_P3 => NamedPrimaries::DisplayP3,
PRIMARIES_ADOBE_RGB => NamedPrimaries::AdobeRgb,
_ => {
return Err(
WpImageDescriptionCreatorParamsV1Error::UnsupportedPrimaries(req.primaries),
);
}
};
let primaries = (Some(primaries), primaries.primaries());
if self.primaries.replace(Some(primaries)).is_some() {
return Err(WpImageDescriptionCreatorParamsV1Error::PrimariesAlreadySet);
} }
Ok(()) Ok(())
} }
fn set_primaries(&self, _req: SetPrimaries, _slf: &Rc<Self>) -> Result<(), Self::Error> { fn set_primaries(&self, req: SetPrimaries, _slf: &Rc<Self>) -> Result<(), Self::Error> {
Err(WpImageDescriptionCreatorParamsV1Error::SetPrimariesNotSupported) let map = |n: i32| F64(n as f64 * PRIMARIES_MUL_INV);
let primaries = Primaries {
r: (map(req.r_x), map(req.r_y)),
g: (map(req.g_x), map(req.g_y)),
b: (map(req.b_x), map(req.b_y)),
wp: (map(req.w_x), map(req.w_y)),
};
let primaries = (None, primaries);
if self.primaries.replace(Some(primaries)).is_some() {
return Err(WpImageDescriptionCreatorParamsV1Error::PrimariesAlreadySet);
}
Ok(())
} }
fn set_luminances(&self, _req: SetLuminances, _slf: &Rc<Self>) -> Result<(), Self::Error> { fn set_luminances(&self, req: SetLuminances, _slf: &Rc<Self>) -> Result<(), Self::Error> {
Err(WpImageDescriptionCreatorParamsV1Error::SetLuminancesNotSupported) let luminance = Luminance {
min: F64(req.min_lum as f64 * MIN_LUM_MUL_INV),
max: F64(req.max_lum as f64),
white: F64(req.reference_lum as f64),
};
if self.luminance.replace(Some(luminance)).is_some() {
return Err(WpImageDescriptionCreatorParamsV1Error::LuminancesAlreadySet);
}
Ok(())
} }
fn set_mastering_display_primaries( fn set_mastering_display_primaries(
@ -120,15 +214,23 @@ pub enum WpImageDescriptionCreatorParamsV1Error {
SetMasteringLuminanceNotSupported, SetMasteringLuminanceNotSupported,
#[error("set_mastering_display_primaries is not supported")] #[error("set_mastering_display_primaries is not supported")]
SetMasteringDisplayPrimariesNotSupported, SetMasteringDisplayPrimariesNotSupported,
#[error("set_luminances is not supported")]
SetLuminancesNotSupported,
#[error("set_primaries is not supported")]
SetPrimariesNotSupported,
#[error("{} is not a supported named primary", .0)] #[error("{} is not a supported named primary", .0)]
UnsupportedPrimaries(u32), UnsupportedPrimaries(u32),
#[error("set_tf_power is not supported")] #[error("set_tf_power is not supported")]
SetTfPowerNotSupported, SetTfPowerNotSupported,
#[error("{} is not a supported named transfer function", .0)] #[error("{} is not a supported named transfer function", .0)]
UnsupportedTf(u32), UnsupportedTf(u32),
#[error("The transfer function has already been set")]
TfAlreadySet,
#[error("The primaries have already been set")]
PrimariesAlreadySet,
#[error("The luminances have already been set")]
LuminancesAlreadySet,
#[error("The minimum luminance is too low")]
MinLuminanceTooLow,
#[error("The transfer function was not set")]
TfNotSet,
#[error("The primaries were not set")]
PrimariesNotSet,
} }
efrom!(WpImageDescriptionCreatorParamsV1Error, ClientError); efrom!(WpImageDescriptionCreatorParamsV1Error, ClientError);

View file

@ -1,6 +1,7 @@
use { use {
crate::{ crate::{
client::{Client, ClientError}, client::{Client, ClientError},
cmm::cmm_description::ColorDescription,
ifs::color_management::wp_image_description_info_v1::WpImageDescriptionInfoV1, ifs::color_management::wp_image_description_info_v1::WpImageDescriptionInfoV1,
leaks::Tracker, leaks::Tracker,
object::{Object, Version}, object::{Object, Version},
@ -15,6 +16,7 @@ pub struct WpImageDescriptionV1 {
pub client: Rc<Client>, pub client: Rc<Client>,
pub version: Version, pub version: Version,
pub tracker: Tracker<Self>, pub tracker: Tracker<Self>,
pub description: Rc<ColorDescription>,
} }
impl WpImageDescriptionV1 { impl WpImageDescriptionV1 {
@ -27,10 +29,10 @@ impl WpImageDescriptionV1 {
}); });
} }
pub fn send_ready(&self, identity: u32) { pub fn send_ready(&self) {
self.client.event(Ready { self.client.event(Ready {
self_id: self.id, self_id: self.id,
identity, identity: self.description.id.into(),
}); });
} }
} }

View file

@ -5,6 +5,7 @@ pub mod ext_session_lock_surface_v1;
pub mod tray; pub mod tray;
pub mod wl_subsurface; pub mod wl_subsurface;
pub mod wp_alpha_modifier_surface_v1; pub mod wp_alpha_modifier_surface_v1;
pub mod wp_color_management_surface_v1;
pub mod wp_commit_timer_v1; pub mod wp_commit_timer_v1;
pub mod wp_fifo_v1; pub mod wp_fifo_v1;
pub mod wp_fractional_scale_v1; pub mod wp_fractional_scale_v1;
@ -22,6 +23,7 @@ use {
crate::{ crate::{
backend::KeyState, backend::KeyState,
client::{Client, ClientError}, client::{Client, ClientError},
cmm::cmm_description::ColorDescription,
cursor_user::{CursorUser, CursorUserId}, cursor_user::{CursorUser, CursorUserId},
damage::DamageMatrix, damage::DamageMatrix,
drm_feedback::DrmFeedback, drm_feedback::DrmFeedback,
@ -104,6 +106,7 @@ use {
rc::{Rc, Weak}, rc::{Rc, Weak},
}, },
thiserror::Error, thiserror::Error,
wp_color_management_surface_v1::WpColorManagementSurfaceV1,
zwp_idle_inhibitor_v1::ZwpIdleInhibitorV1, zwp_idle_inhibitor_v1::ZwpIdleInhibitorV1,
}; };
@ -332,6 +335,8 @@ pub struct WlSurface {
commit_timer: CloneCell<Option<Rc<WpCommitTimerV1>>>, commit_timer: CloneCell<Option<Rc<WpCommitTimerV1>>>,
before_latch_listener: EventListener<dyn BeforeLatchListener>, before_latch_listener: EventListener<dyn BeforeLatchListener>,
is_opaque: Cell<bool>, is_opaque: Cell<bool>,
color_management_surface: CloneCell<Option<Rc<WpColorManagementSurfaceV1>>>,
color_description: CloneCell<Option<Rc<ColorDescription>>>,
} }
impl Debug for WlSurface { impl Debug for WlSurface {
@ -461,6 +466,7 @@ struct PendingState {
fifo_barrier_wait: bool, fifo_barrier_wait: bool,
commit_time: Option<u64>, commit_time: Option<u64>,
tray_item_ack_serial: Option<u32>, tray_item_ack_serial: Option<u32>,
color_description: Option<Option<Rc<ColorDescription>>>,
} }
struct AttachedSubsurfaceState { struct AttachedSubsurfaceState {
@ -513,6 +519,7 @@ impl PendingState {
opt!(alpha_multiplier); opt!(alpha_multiplier);
opt!(commit_time); opt!(commit_time);
opt!(tray_item_ack_serial); opt!(tray_item_ack_serial);
opt!(color_description);
{ {
let (dx1, dy1) = self.offset; let (dx1, dy1) = self.offset;
let (dx2, dy2) = mem::take(&mut next.offset); let (dx2, dy2) = mem::take(&mut next.offset);
@ -670,6 +677,8 @@ impl WlSurface {
commit_timer: Default::default(), commit_timer: Default::default(),
before_latch_listener: EventListener::new(slf.clone()), before_latch_listener: EventListener::new(slf.clone()),
is_opaque: Cell::new(false), is_opaque: Cell::new(false),
color_management_surface: Default::default(),
color_description: Default::default(),
} }
} }
@ -1137,6 +1146,11 @@ impl WlSurface {
} }
} }
} }
let mut color_description_changed = false;
if let Some(desc) = pending.color_description.take() {
color_description_changed = true;
self.color_description.set(desc);
}
let mut alpha_changed = false; let mut alpha_changed = false;
if let Some(alpha) = pending.alpha_multiplier.take() { if let Some(alpha) = pending.alpha_multiplier.take() {
alpha_changed = true; alpha_changed = true;
@ -1144,8 +1158,11 @@ impl WlSurface {
} }
let buffer_abs_pos = self.buffer_abs_pos.get(); let buffer_abs_pos = self.buffer_abs_pos.get();
let mut max_surface_size = buffer_abs_pos.size(); let mut max_surface_size = buffer_abs_pos.size();
let mut damage_full = let mut damage_full = scale_changed
scale_changed || buffer_transform_changed || viewport_changed || alpha_changed; || buffer_transform_changed
|| viewport_changed
|| alpha_changed
|| color_description_changed;
let mut buffer_changed = false; let mut buffer_changed = false;
let mut old_raw_size = None; let mut old_raw_size = None;
let (mut dx, mut dy) = mem::take(&mut pending.offset); let (mut dx, mut dy) = mem::take(&mut pending.offset);
@ -1658,6 +1675,13 @@ impl WlSurface {
pub fn opaque_region(&self) -> Option<Rc<Region>> { pub fn opaque_region(&self) -> Option<Rc<Region>> {
self.opaque_region.get() self.opaque_region.get()
} }
pub fn color_description(&self) -> Rc<ColorDescription> {
match self.color_description.get() {
Some(cd) => cd,
None => self.client.state.color_manager.srgb_srgb().clone(),
}
}
} }
object_base! { object_base! {
@ -1689,6 +1713,7 @@ impl Object for WlSurface {
self.text_input_connections.clear(); self.text_input_connections.clear();
self.fifo.take(); self.fifo.take();
self.commit_timer.take(); self.commit_timer.take();
self.color_management_surface.take();
} }
} }

View file

@ -1,7 +1,7 @@
use { use {
crate::{ crate::{
client::{Client, ClientError}, client::{Client, ClientError},
ifs::color_management::consts::RENDER_INTENT_PERCEPTUAL, ifs::{color_management, wl_surface::WlSurface},
leaks::Tracker, leaks::Tracker,
object::{Object, Version}, object::{Object, Version},
wire::{ wire::{
@ -21,12 +21,26 @@ pub struct WpColorManagementSurfaceV1 {
pub client: Rc<Client>, pub client: Rc<Client>,
pub version: Version, pub version: Version,
pub tracker: Tracker<Self>, pub tracker: Tracker<Self>,
pub surface: Rc<WlSurface>,
}
impl WpColorManagementSurfaceV1 {
pub fn install(self: &Rc<Self>) -> Result<(), WpColorManagementSurfaceV1Error> {
if self.surface.color_management_surface.is_some() {
return Err(WpColorManagementSurfaceV1Error::HasSurface);
}
self.surface
.color_management_surface
.set(Some(self.clone()));
Ok(())
}
} }
impl WpColorManagementSurfaceV1RequestHandler for WpColorManagementSurfaceV1 { impl WpColorManagementSurfaceV1RequestHandler for WpColorManagementSurfaceV1 {
type Error = WpColorManagementSurfaceV1Error; type Error = WpColorManagementSurfaceV1Error;
fn destroy(&self, _req: Destroy, _slf: &Rc<Self>) -> Result<(), Self::Error> { fn destroy(&self, _req: Destroy, _slf: &Rc<Self>) -> Result<(), Self::Error> {
self.surface.color_management_surface.take();
self.client.remove_obj(self)?; self.client.remove_obj(self)?;
Ok(()) Ok(())
} }
@ -36,12 +50,13 @@ impl WpColorManagementSurfaceV1RequestHandler for WpColorManagementSurfaceV1 {
req: SetImageDescription, req: SetImageDescription,
_slf: &Rc<Self>, _slf: &Rc<Self>,
) -> Result<(), Self::Error> { ) -> Result<(), Self::Error> {
let _ = self.client.lookup(req.image_description)?; if req.render_intent != color_management::RENDER_INTENT_PERCEPTUAL {
if req.render_intent != RENDER_INTENT_PERCEPTUAL {
return Err(WpColorManagementSurfaceV1Error::UnsupportedRenderIntent( return Err(WpColorManagementSurfaceV1Error::UnsupportedRenderIntent(
req.render_intent, req.render_intent,
)); ));
} }
let desc = self.client.lookup(req.image_description)?;
self.surface.pending.borrow_mut().color_description = Some(Some(desc.description.clone()));
Ok(()) Ok(())
} }
@ -50,6 +65,7 @@ impl WpColorManagementSurfaceV1RequestHandler for WpColorManagementSurfaceV1 {
_req: UnsetImageDescription, _req: UnsetImageDescription,
_slf: &Rc<Self>, _slf: &Rc<Self>,
) -> Result<(), Self::Error> { ) -> Result<(), Self::Error> {
self.surface.pending.borrow_mut().color_description = Some(None);
Ok(()) Ok(())
} }
} }
@ -69,5 +85,7 @@ pub enum WpColorManagementSurfaceV1Error {
ClientError(Box<ClientError>), ClientError(Box<ClientError>),
#[error("{} is not a supported render intent", .0)] #[error("{} is not a supported render intent", .0)]
UnsupportedRenderIntent(u32), UnsupportedRenderIntent(u32),
#[error("wl_surface already has a color-management extension")]
HasSurface,
} }
efrom!(WpColorManagementSurfaceV1Error, ClientError); efrom!(WpColorManagementSurfaceV1Error, ClientError);

View file

@ -444,7 +444,7 @@ impl Renderer<'_> {
bounds: Option<&Rect>, bounds: Option<&Rect>,
) { ) {
let alpha = surface.alpha(); let alpha = surface.alpha();
let cd = self.state.color_manager.srgb_srgb(); let cd = surface.color_description();
if let Some(tex) = buffer.buffer.get_texture(surface) { if let Some(tex) = buffer.buffer.get_texture(surface) {
let mut opaque = surface.opaque(); let mut opaque = surface.opaque();
if !opaque && tex.format().has_alpha { if !opaque && tex.format().has_alpha {
@ -463,7 +463,7 @@ impl Renderer<'_> {
AcquireSync::Unnecessary, AcquireSync::Unnecessary,
buffer.release_sync, buffer.release_sync,
opaque, opaque,
cd, &cd,
); );
} else if let Some(color) = &buffer.buffer.color { } else if let Some(color) = &buffer.buffer.color {
if let Some(rect) = Rect::new_sized(x, y, tsize.0, tsize.1) { if let Some(rect) = Rect::new_sized(x, y, tsize.0, tsize.1) {