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

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

View file

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

View file

@ -1,73 +0,0 @@
use {
crate::{
client::{Client, ClientError},
ifs::color_management::consts::RENDER_INTENT_PERCEPTUAL,
leaks::Tracker,
object::{Object, Version},
wire::{
WpColorManagementSurfaceV1Id,
wp_color_management_surface_v1::{
Destroy, SetImageDescription, UnsetImageDescription,
WpColorManagementSurfaceV1RequestHandler,
},
},
},
std::rc::Rc,
thiserror::Error,
};
pub struct WpColorManagementSurfaceV1 {
pub id: WpColorManagementSurfaceV1Id,
pub client: Rc<Client>,
pub version: Version,
pub tracker: Tracker<Self>,
}
impl WpColorManagementSurfaceV1RequestHandler for WpColorManagementSurfaceV1 {
type Error = WpColorManagementSurfaceV1Error;
fn destroy(&self, _req: Destroy, _slf: &Rc<Self>) -> Result<(), Self::Error> {
self.client.remove_obj(self)?;
Ok(())
}
fn set_image_description(
&self,
req: SetImageDescription,
_slf: &Rc<Self>,
) -> Result<(), Self::Error> {
let _ = self.client.lookup(req.image_description)?;
if req.render_intent != RENDER_INTENT_PERCEPTUAL {
return Err(WpColorManagementSurfaceV1Error::UnsupportedRenderIntent(
req.render_intent,
));
}
Ok(())
}
fn unset_image_description(
&self,
_req: UnsetImageDescription,
_slf: &Rc<Self>,
) -> Result<(), Self::Error> {
Ok(())
}
}
object_base! {
self = WpColorManagementSurfaceV1;
version = self.version;
}
impl Object for WpColorManagementSurfaceV1 {}
simple_add_obj!(WpColorManagementSurfaceV1);
#[derive(Debug, Error)]
pub enum WpColorManagementSurfaceV1Error {
#[error(transparent)]
ClientError(Box<ClientError>),
#[error("{} is not a supported render intent", .0)]
UnsupportedRenderIntent(u32),
}
efrom!(WpColorManagementSurfaceV1Error, ClientError);

View file

@ -2,15 +2,27 @@ use {
crate::{
client::{Client, ClientError},
globals::{Global, GlobalName},
ifs::color_management::{
consts::{
FEATURE_PARAMETRIC, PRIMARIES_SRGB, RENDER_INTENT_PERCEPTUAL,
TRANSFER_FUNCTION_SRGB,
ifs::{
color_management::{
consts::{
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,
object::{Object, Version},
@ -63,8 +75,30 @@ impl WpColorManagerV1 {
fn send_capabilities(&self) {
self.send_supported_intent(RENDER_INTENT_PERCEPTUAL);
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_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_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();
}
@ -123,15 +157,17 @@ impl WpColorManagerV1RequestHandler for WpColorManagerV1 {
}
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 {
id: req.id,
client: self.client.clone(),
version: self.version,
tracker: Default::default(),
surface: surface.clone(),
});
track!(self.client, obj);
self.client.add_client_obj(&obj)?;
obj.install()?;
Ok(())
}
@ -170,6 +206,9 @@ impl WpColorManagerV1RequestHandler for WpColorManagerV1 {
client: self.client.clone(),
version: self.version,
tracker: Default::default(),
tf: Default::default(),
primaries: Default::default(),
luminance: Default::default(),
});
track!(self.client, obj);
self.client.add_client_obj(&obj)?;
@ -178,10 +217,20 @@ impl WpColorManagerV1RequestHandler for WpColorManagerV1 {
fn create_windows_scrgb(
&self,
_req: CreateWindowsScrgb,
req: CreateWindowsScrgb,
_slf: &Rc<Self>,
) -> 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>),
#[error("create_icc_creator is not supported")]
CreateIccCreatorNotSupported,
#[error("create_windows_scrgb is not supported")]
CreateWindowsScrgbNotSupported,
#[error(transparent)]
Surface(#[from] WpColorManagementSurfaceV1Error),
}
efrom!(WpColorManagerV1Error, ClientError);

View file

@ -1,12 +1,27 @@
use {
crate::{
client::{Client, ClientError},
cmm::{
cmm_luminance::Luminance,
cmm_primaries::{NamedPrimaries, Primaries},
cmm_transfer_function::TransferFunction,
},
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,
},
leaks::Tracker,
object::{Object, Version},
utils::ordered_float::F64,
wire::{
WpImageDescriptionCreatorParamsV1Id,
wp_image_description_creator_params_v1::{
@ -16,7 +31,7 @@ use {
},
},
},
std::rc::Rc,
std::{cell::Cell, rc::Rc},
thiserror::Error,
};
@ -25,30 +40,74 @@ pub struct WpImageDescriptionCreatorParamsV1 {
pub client: Rc<Client>,
pub version: Version,
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 {
type Error = WpImageDescriptionCreatorParamsV1Error;
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 {
id: req.image_description,
client: self.client.clone(),
version: self.version,
tracker: Default::default(),
description,
});
track!(self.client, obj);
self.client.add_client_obj(&obj)?;
obj.send_ready(0);
obj.send_ready();
self.client.remove_obj(self)?;
Ok(())
}
fn set_tf_named(&self, req: SetTfNamed, _slf: &Rc<Self>) -> Result<(), Self::Error> {
if req.tf != TRANSFER_FUNCTION_SRGB {
return Err(WpImageDescriptionCreatorParamsV1Error::UnsupportedTf(
req.tf,
));
let tf = match req.tf {
TRANSFER_FUNCTION_BT1886 => TransferFunction::Bt1886,
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(())
}
@ -62,20 +121,55 @@ impl WpImageDescriptionCreatorParamsV1RequestHandler for WpImageDescriptionCreat
req: SetPrimariesNamed,
_slf: &Rc<Self>,
) -> Result<(), Self::Error> {
if req.primaries != PRIMARIES_SRGB {
return Err(
WpImageDescriptionCreatorParamsV1Error::UnsupportedPrimaries(req.primaries),
);
let primaries = match req.primaries {
PRIMARIES_SRGB => NamedPrimaries::Srgb,
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(())
}
fn set_primaries(&self, _req: SetPrimaries, _slf: &Rc<Self>) -> Result<(), Self::Error> {
Err(WpImageDescriptionCreatorParamsV1Error::SetPrimariesNotSupported)
fn set_primaries(&self, req: SetPrimaries, _slf: &Rc<Self>) -> Result<(), Self::Error> {
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> {
Err(WpImageDescriptionCreatorParamsV1Error::SetLuminancesNotSupported)
fn set_luminances(&self, req: SetLuminances, _slf: &Rc<Self>) -> Result<(), Self::Error> {
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(
@ -120,15 +214,23 @@ pub enum WpImageDescriptionCreatorParamsV1Error {
SetMasteringLuminanceNotSupported,
#[error("set_mastering_display_primaries is not supported")]
SetMasteringDisplayPrimariesNotSupported,
#[error("set_luminances is not supported")]
SetLuminancesNotSupported,
#[error("set_primaries is not supported")]
SetPrimariesNotSupported,
#[error("{} is not a supported named primary", .0)]
UnsupportedPrimaries(u32),
#[error("set_tf_power is not supported")]
SetTfPowerNotSupported,
#[error("{} is not a supported named transfer function", .0)]
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);

View file

@ -1,6 +1,7 @@
use {
crate::{
client::{Client, ClientError},
cmm::cmm_description::ColorDescription,
ifs::color_management::wp_image_description_info_v1::WpImageDescriptionInfoV1,
leaks::Tracker,
object::{Object, Version},
@ -15,6 +16,7 @@ pub struct WpImageDescriptionV1 {
pub client: Rc<Client>,
pub version: Version,
pub tracker: Tracker<Self>,
pub description: Rc<ColorDescription>,
}
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_id: self.id,
identity,
identity: self.description.id.into(),
});
}
}