From 04f280aabe79168368b2d1f6856d09e1cdd3a9d4 Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Tue, 11 Mar 2025 11:41:42 +0100 Subject: [PATCH] color-management-v1: implement target color volume --- src/backends/metal/present.rs | 4 +- src/cmm/cmm_description.rs | 29 ++++- src/cmm/cmm_luminance.rs | 15 +++ src/cmm/cmm_manager.rs | 40 +++++- src/cmm/cmm_tests.rs | 13 +- src/gfx_apis/vulkan/renderer.rs | 2 +- .../color_management/wp_color_manager_v1.rs | 7 + .../wp_image_description_creator_params_v1.rs | 79 ++++++++++-- .../wp_image_description_info_v1.rs | 122 ++++++++++++------ .../wp_image_description_v1.rs | 2 +- 10 files changed, 249 insertions(+), 64 deletions(-) diff --git a/src/backends/metal/present.rs b/src/backends/metal/present.rs index 3af4f794..56fc7e3f 100644 --- a/src/backends/metal/present.rs +++ b/src/backends/metal/present.rs @@ -560,8 +560,8 @@ impl MetalConnector { } return None; }; - if ct.cd.id != self.state.color_manager.srgb_srgb().id { - // Direct scanout requires identical color descriptions. + if !ct.cd.embeds_into(self.state.color_manager.srgb_srgb()) { + // Direct scanout requires embeddable color descriptions. return None; } if ct.alpha.is_some() { diff --git a/src/cmm/cmm_description.rs b/src/cmm/cmm_description.rs index eef9a923..642d271c 100644 --- a/src/cmm/cmm_description.rs +++ b/src/cmm/cmm_description.rs @@ -1,13 +1,13 @@ use { crate::{ cmm::{ - cmm_luminance::{Luminance, white_balance}, + cmm_luminance::{Luminance, TargetLuminance, white_balance}, cmm_manager::Shared, cmm_primaries::{NamedPrimaries, Primaries}, cmm_transfer_function::TransferFunction, cmm_transform::{ColorMatrix, Local, Xyz, bradford_adjustment}, }, - utils::free_list::FreeList, + utils::{free_list::FreeList, ordered_float::F64}, }, std::rc::Rc, }; @@ -38,6 +38,10 @@ pub struct LinearColorDescription { pub xyz_from_local: ColorMatrix, pub local_from_xyz: ColorMatrix, pub luminance: Luminance, + pub target_primaries: Primaries, + pub target_luminance: TargetLuminance, + pub max_cll: Option, + pub max_fall: Option, pub(super) shared: Rc, } @@ -45,7 +49,6 @@ pub struct LinearColorDescription { pub struct ColorDescription { pub id: ColorDescriptionId, pub linear: Rc, - #[expect(dead_code)] pub named_primaries: Option, pub transfer_function: TransferFunction, pub(super) shared: Rc, @@ -62,6 +65,26 @@ impl LinearColorDescription { } mat * self.xyz_from_local } + + pub fn embeds_into(&self, target: &Self) -> bool { + if self.id == target.id { + return true; + } + if self.primaries != target.primaries { + return false; + } + if self.luminance != target.luminance { + return false; + } + true + } +} + +impl ColorDescription { + pub fn embeds_into(&self, target: &Self) -> bool { + self.transfer_function == target.transfer_function + && self.linear.embeds_into(&target.linear) + } } impl Drop for LinearColorDescription { diff --git a/src/cmm/cmm_luminance.rs b/src/cmm/cmm_luminance.rs index 760f50f5..3cbb31ee 100644 --- a/src/cmm/cmm_luminance.rs +++ b/src/cmm/cmm_luminance.rs @@ -10,6 +10,12 @@ pub struct Luminance { pub white: F64, } +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +pub struct TargetLuminance { + pub min: F64, + pub max: F64, +} + impl Luminance { pub const SRGB: Self = Self { min: F64(0.2), @@ -46,6 +52,15 @@ impl Luminance { }; } +impl Luminance { + pub fn to_target(&self) -> TargetLuminance { + TargetLuminance { + min: self.min, + max: self.max, + } + } +} + impl Default for Luminance { fn default() -> Self { Self::SRGB diff --git a/src/cmm/cmm_manager.rs b/src/cmm/cmm_manager.rs index 6837fadc..02658e40 100644 --- a/src/cmm/cmm_manager.rs +++ b/src/cmm/cmm_manager.rs @@ -5,11 +5,11 @@ use { ColorDescription, ColorDescriptionIds, LinearColorDescription, LinearColorDescriptionId, LinearColorDescriptionIds, }, - cmm_luminance::Luminance, + cmm_luminance::{Luminance, TargetLuminance}, cmm_primaries::{NamedPrimaries, Primaries}, cmm_transfer_function::TransferFunction, }, - utils::{copyhashmap::CopyHashMap, numcell::NumCell}, + utils::{copyhashmap::CopyHashMap, numcell::NumCell, ordered_float::F64}, }, std::rc::{Rc, Weak}, }; @@ -35,6 +35,10 @@ pub(super) struct Shared { struct LinearDescriptionKey { primaries: Primaries, luminance: Luminance, + target_primaries: Primaries, + target_luminance: TargetLuminance, + max_cll: Option, + max_fall: Option, } #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] @@ -60,6 +64,10 @@ impl ColorManager { Primaries::SRGB, Luminance::SRGB, TransferFunction::Srgb, + Primaries::SRGB, + Luminance::SRGB.to_target(), + None, + None, ); let srgb_linear = get_description( &shared, @@ -70,6 +78,10 @@ impl ColorManager { Primaries::SRGB, Luminance::SRGB, TransferFunction::Linear, + Primaries::SRGB, + Luminance::SRGB.to_target(), + None, + None, ); let windows_scrgb = get_description( &shared, @@ -80,6 +92,10 @@ impl ColorManager { Primaries::SRGB, Luminance::WINDOWS_SCRGB, TransferFunction::Linear, + Primaries::BT2020, + Luminance::ST2084_PQ.to_target(), + None, + None, ); Rc::new(Self { linear_ids, @@ -110,6 +126,10 @@ impl ColorManager { primaries: Primaries, luminance: Luminance, transfer_function: TransferFunction, + target_primaries: Primaries, + target_luminance: TargetLuminance, + max_cll: Option, + max_fall: Option, ) -> Rc { get_description( &self.shared, @@ -120,6 +140,10 @@ impl ColorManager { primaries, luminance, transfer_function, + target_primaries, + target_luminance, + max_cll, + max_fall, ) } } @@ -133,6 +157,10 @@ fn get_description( primaries: Primaries, luminance: Luminance, transfer_function: TransferFunction, + target_primaries: Primaries, + target_luminance: TargetLuminance, + max_cll: Option, + max_fall: Option, ) -> Rc { macro_rules! gc { ($d:ident, $i:expr) => { @@ -147,6 +175,10 @@ fn get_description( let key = LinearDescriptionKey { primaries, luminance, + target_primaries, + target_luminance, + max_cll, + max_fall, }; if let Some(d) = linear_descriptions.get(&key) { if let Some(d) = d.upgrade() { @@ -180,6 +212,10 @@ fn get_description( xyz_from_local, local_from_xyz, luminance, + target_primaries, + target_luminance, + max_cll, + max_fall, shared: shared.clone(), }); linear_descriptions.set(key, Rc::downgrade(&d)); diff --git a/src/cmm/cmm_tests.rs b/src/cmm/cmm_tests.rs index 52b98d72..5bc11101 100644 --- a/src/cmm/cmm_tests.rs +++ b/src/cmm/cmm_tests.rs @@ -141,7 +141,18 @@ mod transforms { fn check(p1: Primaries, p2: Primaries, expected: [[f64; 4]; 3]) { let manager = ColorManager::new(); - let d = |p| manager.get_description(None, p, Luminance::SRGB, TransferFunction::Linear); + let d = |p| { + manager.get_description( + None, + p, + Luminance::SRGB, + TransferFunction::Linear, + p, + Luminance::SRGB.to_target(), + None, + None, + ) + }; let d1 = d(p1); let d2 = d(p2); let m = d1.linear.color_transform(&d2.linear); diff --git a/src/gfx_apis/vulkan/renderer.rs b/src/gfx_apis/vulkan/renderer.rs index efb31306..f3da7e78 100644 --- a/src/gfx_apis/vulkan/renderer.rs +++ b/src/gfx_apis/vulkan/renderer.rs @@ -2138,7 +2138,7 @@ impl ColorTransforms { src: &LinearColorDescription, dst: &ColorDescription, ) -> Option<&mut ColorTransform> { - if src.id == dst.linear.id { + if src.embeds_into(&dst.linear) { return None; } let ct = match self.map.entry([src.id, dst.linear.id]) { diff --git a/src/ifs/color_management/wp_color_manager_v1.rs b/src/ifs/color_management/wp_color_manager_v1.rs index 05546d97..5dcc4ebf 100644 --- a/src/ifs/color_management/wp_color_manager_v1.rs +++ b/src/ifs/color_management/wp_color_manager_v1.rs @@ -4,6 +4,7 @@ use { globals::{Global, GlobalName}, ifs::{ color_management::{ + FEATURE_EXTENDED_TARGET_VOLUME, FEATURE_SET_MASTERING_DISPLAY_PRIMARIES, consts::{ FEATURE_PARAMETRIC, FEATURE_SET_LUMINANCES, FEATURE_SET_PRIMARIES, FEATURE_WINDOWS_SCRGB, PRIMARIES_ADOBE_RGB, PRIMARIES_BT2020, @@ -77,6 +78,8 @@ impl WpColorManagerV1 { 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_SET_MASTERING_DISPLAY_PRIMARIES); + self.send_supported_feature(FEATURE_EXTENDED_TARGET_VOLUME); self.send_supported_feature(FEATURE_WINDOWS_SCRGB); self.send_supported_tf_named(TRANSFER_FUNCTION_BT1886); self.send_supported_tf_named(TRANSFER_FUNCTION_GAMMA22); @@ -209,6 +212,10 @@ impl WpColorManagerV1RequestHandler for WpColorManagerV1 { tf: Default::default(), primaries: Default::default(), luminance: Default::default(), + mastering_primaries: Default::default(), + mastering_luminance: Default::default(), + max_cll: Default::default(), + max_fall: Default::default(), }); track!(self.client, obj); self.client.add_client_obj(&obj)?; diff --git a/src/ifs/color_management/wp_image_description_creator_params_v1.rs b/src/ifs/color_management/wp_image_description_creator_params_v1.rs index a4d7dc2f..15de1e84 100644 --- a/src/ifs/color_management/wp_image_description_creator_params_v1.rs +++ b/src/ifs/color_management/wp_image_description_creator_params_v1.rs @@ -2,7 +2,7 @@ use { crate::{ client::{Client, ClientError}, cmm::{ - cmm_luminance::Luminance, + cmm_luminance::{Luminance, TargetLuminance}, cmm_primaries::{NamedPrimaries, Primaries}, cmm_transfer_function::TransferFunction, }, @@ -43,6 +43,10 @@ pub struct WpImageDescriptionCreatorParamsV1 { pub tf: Cell>, pub primaries: Cell, Primaries)>>, pub luminance: Cell>, + pub mastering_primaries: Cell>, + pub mastering_luminance: Cell>, + pub max_cll: Cell>, + pub max_fall: Cell>, } impl WpImageDescriptionCreatorParamsV1RequestHandler for WpImageDescriptionCreatorParamsV1 { @@ -67,11 +71,20 @@ impl WpImageDescriptionCreatorParamsV1RequestHandler for WpImageDescriptionCreat if luminance.max.0 <= luminance.min.0 || luminance.white.0 <= luminance.min.0 { return Err(WpImageDescriptionCreatorParamsV1Error::MinLuminanceTooLow); } + let target_primaries = self.mastering_primaries.get().unwrap_or(primaries); + let target_luminance = self + .mastering_luminance + .get() + .unwrap_or(luminance.to_target()); let description = self.client.state.color_manager.get_description( named_primaries, primaries, luminance, transfer_function, + target_primaries, + target_luminance, + self.max_cll.get(), + self.max_fall.get(), ); let obj = Rc::new(WpImageDescriptionV1 { id: req.image_description, @@ -174,25 +187,59 @@ impl WpImageDescriptionCreatorParamsV1RequestHandler for WpImageDescriptionCreat fn set_mastering_display_primaries( &self, - _req: SetMasteringDisplayPrimaries, + req: SetMasteringDisplayPrimaries, _slf: &Rc, ) -> Result<(), Self::Error> { - Err(WpImageDescriptionCreatorParamsV1Error::SetMasteringDisplayPrimariesNotSupported) + 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)), + }; + if self.mastering_primaries.replace(Some(primaries)).is_some() { + return Err(WpImageDescriptionCreatorParamsV1Error::MasteringPrimariesAlreadySet); + } + Ok(()) } fn set_mastering_luminance( &self, - _req: SetMasteringLuminance, + req: SetMasteringLuminance, _slf: &Rc, ) -> Result<(), Self::Error> { - Err(WpImageDescriptionCreatorParamsV1Error::SetMasteringLuminanceNotSupported) - } - - fn set_max_cll(&self, _req: SetMaxCll, _slf: &Rc) -> Result<(), Self::Error> { + let luminance = TargetLuminance { + min: F64(req.min_lum as f64 * MIN_LUM_MUL_INV), + max: F64(req.max_lum as f64), + }; + if luminance.max.0 <= luminance.min.0 { + return Err(WpImageDescriptionCreatorParamsV1Error::MinMasteringLuminanceTooLow); + } + if self.mastering_luminance.replace(Some(luminance)).is_some() { + return Err(WpImageDescriptionCreatorParamsV1Error::MasteringLuminancesAlreadySet); + } Ok(()) } - fn set_max_fall(&self, _req: SetMaxFall, _slf: &Rc) -> Result<(), Self::Error> { + fn set_max_cll(&self, req: SetMaxCll, _slf: &Rc) -> Result<(), Self::Error> { + if self + .max_cll + .replace(Some(F64(req.max_cll as f64))) + .is_some() + { + return Err(WpImageDescriptionCreatorParamsV1Error::MaxCllAlreadySet); + } + Ok(()) + } + + fn set_max_fall(&self, req: SetMaxFall, _slf: &Rc) -> Result<(), Self::Error> { + if self + .max_fall + .replace(Some(F64(req.max_fall as f64))) + .is_some() + { + return Err(WpImageDescriptionCreatorParamsV1Error::MaxFallAlreadySet); + } Ok(()) } } @@ -210,10 +257,6 @@ simple_add_obj!(WpImageDescriptionCreatorParamsV1); pub enum WpImageDescriptionCreatorParamsV1Error { #[error(transparent)] ClientError(Box), - #[error("set_mastering_luminance is not supported")] - SetMasteringLuminanceNotSupported, - #[error("set_mastering_display_primaries is not supported")] - SetMasteringDisplayPrimariesNotSupported, #[error("{} is not a supported named primary", .0)] UnsupportedPrimaries(u32), #[error("set_tf_power is not supported")] @@ -232,5 +275,15 @@ pub enum WpImageDescriptionCreatorParamsV1Error { TfNotSet, #[error("The primaries were not set")] PrimariesNotSet, + #[error("The mastering display primaries have already been set")] + MasteringPrimariesAlreadySet, + #[error("The mastering display luminances have already been set")] + MasteringLuminancesAlreadySet, + #[error("The minimum mastering luminance is too low")] + MinMasteringLuminanceTooLow, + #[error("The max CLL has already been set")] + MaxCllAlreadySet, + #[error("The max FALL has already been set")] + MaxFallAlreadySet, } efrom!(WpImageDescriptionCreatorParamsV1Error, ClientError); diff --git a/src/ifs/color_management/wp_image_description_info_v1.rs b/src/ifs/color_management/wp_image_description_info_v1.rs index bb23069f..352f7a90 100644 --- a/src/ifs/color_management/wp_image_description_info_v1.rs +++ b/src/ifs/color_management/wp_image_description_info_v1.rs @@ -1,9 +1,22 @@ use { crate::{ client::Client, - ifs::color_management::consts::{PRIMARIES_SRGB, TRANSFER_FUNCTION_SRGB}, + cmm::{ + cmm_description::ColorDescription, cmm_primaries::NamedPrimaries, + cmm_transfer_function::TransferFunction, + }, + ifs::color_management::{ + MIN_LUM_MUL, PRIMARIES_ADOBE_RGB, PRIMARIES_BT2020, PRIMARIES_CIE1931_XYZ, + PRIMARIES_DCI_P3, PRIMARIES_DISPLAY_P3, PRIMARIES_GENERIC_FILM, PRIMARIES_MUL, + PRIMARIES_NTSC, PRIMARIES_PAL, PRIMARIES_PAL_M, 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_ST240, TRANSFER_FUNCTION_ST428, TRANSFER_FUNCTION_ST2084_PQ, + consts::{PRIMARIES_SRGB, TRANSFER_FUNCTION_SRGB}, + }, leaks::Tracker, object::{Object, Version}, + utils::ordered_float::F64, wire::{WpImageDescriptionInfoV1Id, wp_image_description_info_v1::*}, }, std::{convert::Infallible, rc::Rc}, @@ -18,17 +31,46 @@ pub struct WpImageDescriptionInfoV1 { } impl WpImageDescriptionInfoV1 { - pub fn send_srgb(&self) { - let red = [0.64, 0.33]; - let green = [0.3, 0.6]; - let blue = [0.15, 0.06]; - let white = [0.3127, 0.3290]; - self.send_primaries(red, green, blue, white); - self.send_primaries_named(PRIMARIES_SRGB); - self.send_tf_named(TRANSFER_FUNCTION_SRGB); - self.send_luminances(0.2, 80.0, 80.0); - self.send_target_primaries(red, green, blue, white); - self.send_target_luminances(0.2, 80.0); + pub fn send_description(&self, d: &ColorDescription) { + let tf = match d.transfer_function { + TransferFunction::Srgb => TRANSFER_FUNCTION_SRGB, + TransferFunction::Linear => TRANSFER_FUNCTION_EXT_LINEAR, + TransferFunction::St2084Pq => TRANSFER_FUNCTION_ST2084_PQ, + TransferFunction::Bt1886 => TRANSFER_FUNCTION_BT1886, + TransferFunction::Gamma22 => TRANSFER_FUNCTION_GAMMA22, + TransferFunction::Gamma28 => TRANSFER_FUNCTION_GAMMA28, + TransferFunction::St240 => TRANSFER_FUNCTION_ST240, + TransferFunction::ExtSrgb => TRANSFER_FUNCTION_EXT_SRGB, + TransferFunction::Log100 => TRANSFER_FUNCTION_LOG_100, + TransferFunction::Log316 => TRANSFER_FUNCTION_LOG_316, + TransferFunction::St428 => TRANSFER_FUNCTION_ST428, + }; + self.send_primaries(&d.linear.primaries); + if let Some(n) = d.named_primaries { + let n = match n { + NamedPrimaries::Srgb => PRIMARIES_SRGB, + NamedPrimaries::PalM => PRIMARIES_PAL_M, + NamedPrimaries::Pal => PRIMARIES_PAL, + NamedPrimaries::Ntsc => PRIMARIES_NTSC, + NamedPrimaries::GenericFilm => PRIMARIES_GENERIC_FILM, + NamedPrimaries::Bt2020 => PRIMARIES_BT2020, + NamedPrimaries::Cie1931Xyz => PRIMARIES_CIE1931_XYZ, + NamedPrimaries::DciP3 => PRIMARIES_DCI_P3, + NamedPrimaries::DisplayP3 => PRIMARIES_DISPLAY_P3, + NamedPrimaries::AdobeRgb => PRIMARIES_ADOBE_RGB, + }; + self.send_primaries_named(n); + } + self.send_tf_named(tf); + self.send_luminances(&d.linear.luminance); + self.send_target_primaries(&d.linear.target_primaries); + self.send_target_luminances(&d.linear.target_luminance); + if let Some(max_cll) = d.linear.max_cll { + self.send_target_max_cll(max_cll.0); + } + if let Some(max_fall) = d.linear.max_fall { + self.send_target_max_fall(max_fall.0); + } self.send_done(); } @@ -45,18 +87,18 @@ impl WpImageDescriptionInfoV1 { }); } - pub fn send_primaries(&self, r: [f64; 2], g: [f64; 2], b: [f64; 2], w: [f64; 2]) { - let map = |c: f64| (c * 1_000_000.0) as i32; + pub fn send_primaries(&self, p: &crate::cmm::cmm_primaries::Primaries) { + let map = |c: F64| (c.0 * PRIMARIES_MUL) as i32; self.client.event(Primaries { self_id: self.id, - r_x: map(r[0]), - r_y: map(r[1]), - g_x: map(g[0]), - g_y: map(g[1]), - b_x: map(b[0]), - b_y: map(b[1]), - w_x: map(w[0]), - w_y: map(w[1]), + r_x: map(p.r.0), + r_y: map(p.r.1), + g_x: map(p.g.0), + g_y: map(p.g.1), + b_x: map(p.b.0), + b_y: map(p.b.1), + w_x: map(p.wp.0), + w_y: map(p.wp.1), }); } @@ -82,39 +124,38 @@ impl WpImageDescriptionInfoV1 { }); } - pub fn send_luminances(&self, min_lum: f64, max_lum: f64, reference_lum: f64) { + pub fn send_luminances(&self, l: &crate::cmm::cmm_luminance::Luminance) { self.client.event(Luminances { self_id: self.id, - min_lum: (min_lum * 10_000.0) as u32, - max_lum: max_lum as _, - reference_lum: reference_lum as _, + min_lum: (l.min.0 * MIN_LUM_MUL) as u32, + max_lum: l.max.0 as _, + reference_lum: l.white.0 as _, }); } - pub fn send_target_primaries(&self, r: [f64; 2], g: [f64; 2], b: [f64; 2], w: [f64; 2]) { - let map = |c: f64| (c * 1_000_000.0) as i32; + pub fn send_target_primaries(&self, p: &crate::cmm::cmm_primaries::Primaries) { + let map = |c: F64| (c.0 * PRIMARIES_MUL) as i32; self.client.event(TargetPrimaries { self_id: self.id, - r_x: map(r[0]), - r_y: map(r[1]), - g_x: map(g[0]), - g_y: map(g[1]), - b_x: map(b[0]), - b_y: map(b[1]), - w_x: map(w[0]), - w_y: map(w[1]), + r_x: map(p.r.0), + r_y: map(p.r.1), + g_x: map(p.g.0), + g_y: map(p.g.1), + b_x: map(p.b.0), + b_y: map(p.b.1), + w_x: map(p.wp.0), + w_y: map(p.wp.1), }); } - pub fn send_target_luminances(&self, min_lum: f64, max_lum: f64) { + pub fn send_target_luminances(&self, l: &crate::cmm::cmm_luminance::TargetLuminance) { self.client.event(TargetLuminance { self_id: self.id, - min_lum: (min_lum * 10_000.0) as u32, - max_lum: max_lum as _, + min_lum: (l.min.0 * MIN_LUM_MUL) as u32, + max_lum: l.max.0 as _, }); } - #[expect(dead_code)] pub fn send_target_max_cll(&self, max_cll: f64) { self.client.event(TargetMaxCll { self_id: self.id, @@ -122,7 +163,6 @@ impl WpImageDescriptionInfoV1 { }); } - #[expect(dead_code)] pub fn send_target_max_fall(&self, max_fall: f64) { self.client.event(TargetMaxFall { self_id: self.id, diff --git a/src/ifs/color_management/wp_image_description_v1.rs b/src/ifs/color_management/wp_image_description_v1.rs index 00ec4d02..f72a84a7 100644 --- a/src/ifs/color_management/wp_image_description_v1.rs +++ b/src/ifs/color_management/wp_image_description_v1.rs @@ -54,7 +54,7 @@ impl WpImageDescriptionV1RequestHandler for WpImageDescriptionV1 { }); self.client.add_client_obj(&obj)?; track!(self.client, obj); - obj.send_srgb(); + obj.send_description(self.client.state.color_manager.srgb_srgb()); self.client.remove_obj(&*obj)?; Ok(()) }