From b5c0e3a07ec4842323b6dae6ba9f3e267caecba8 Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Thu, 18 Dec 2025 18:03:35 +0100 Subject: [PATCH] cmm: add support for compound_power_2_4 --- src/cmm/cmm_eotf.rs | 1 + src/gfx_apis/vulkan/eotfs.rs | 4 ++++ src/gfx_apis/vulkan/shaders/eotfs.glsl | 19 ++++++++++++++++++ src/gfx_apis/vulkan/shaders_bin/out.frag.spv | Bin 12764 -> 13824 bytes src/gfx_apis/vulkan/shaders_bin/tex.frag.spv | Bin 13536 -> 14596 bytes src/gfx_apis/vulkan/shaders_hash.txt | 2 +- src/ifs/color_management.rs | 1 + .../color_management/wp_color_manager_v1.rs | 8 ++++++-- .../wp_image_description_creator_params_v1.rs | 6 +++++- .../wp_image_description_info_v1.rs | 8 +++++--- src/theme.rs | 16 +++++++++++++++ 11 files changed, 58 insertions(+), 7 deletions(-) diff --git a/src/cmm/cmm_eotf.rs b/src/cmm/cmm_eotf.rs index 40cf1ccb..89e123aa 100644 --- a/src/cmm/cmm_eotf.rs +++ b/src/cmm/cmm_eotf.rs @@ -13,6 +13,7 @@ pub enum Eotf { Log316, St428, Pow(EotfPow), + CompoundPower24, } const MUL: u32 = 10_000; diff --git a/src/gfx_apis/vulkan/eotfs.rs b/src/gfx_apis/vulkan/eotfs.rs index 61d27a23..bf6ee707 100644 --- a/src/gfx_apis/vulkan/eotfs.rs +++ b/src/gfx_apis/vulkan/eotfs.rs @@ -11,6 +11,7 @@ pub const EOTF_LOG316: u32 = 9; pub const EOTF_ST428: u32 = 10; pub const EOTF_POW: u32 = 11; pub const EOTF_GAMMA24: u32 = 12; +pub const EOTF_COMPOUND_POWER_2_4: u32 = 13; #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Linearize)] pub enum VulkanEotf { @@ -25,6 +26,7 @@ pub enum VulkanEotf { Log316, St428, Pow, + CompoundPower24, } pub trait EotfExt: Sized { @@ -54,6 +56,7 @@ impl EotfExt for Eotf { Log316, St428, Pow, + CompoundPower24, } } } @@ -72,6 +75,7 @@ impl VulkanEotf { Self::Log316 => EOTF_LOG316, Self::St428 => EOTF_ST428, Self::Pow => EOTF_POW, + Self::CompoundPower24 => EOTF_COMPOUND_POWER_2_4, } } } diff --git a/src/gfx_apis/vulkan/shaders/eotfs.glsl b/src/gfx_apis/vulkan/shaders/eotfs.glsl index 5538a96b..139f7a97 100644 --- a/src/gfx_apis/vulkan/shaders/eotfs.glsl +++ b/src/gfx_apis/vulkan/shaders/eotfs.glsl @@ -15,6 +15,7 @@ #define TF_ST428 10 #define TF_POW 11 #define TF_GAMMA24 12 +#define TF_COMPOUND_POWER_2_4 13 vec3 eotf_bt1886(vec3 c) { c = clamp(c, 0.0, 1.0); @@ -101,6 +102,22 @@ vec3 inv_eotf_st428(vec3 c) { return pow(vec3(48.0) * c / vec3(52.37), vec3(1.0 / 2.6)); } +vec3 eotf_compound_power_2_4(vec3 c) { + return mix( + c * vec3(1.0 / 12.92), + pow((c + vec3(0.055)) * vec3(1.0 / 1.055), vec3(2.4)), + greaterThanEqual(c, vec3(0.04045)) + ); +} + +vec3 inv_eotf_compound_power_2_4(vec3 c) { + return mix( + vec3(12.92) * c, + vec3(1.055) * pow(c, vec3(1.0 / 2.4)) - vec3(0.055), + greaterThanEqual(c, vec3(0.0031308)) + ); +} + vec3 apply_eotf(vec3 c) { switch (eotf) { case TF_LINEAR: return c; @@ -114,6 +131,7 @@ vec3 apply_eotf(vec3 c) { case TF_LOG316: return eotf_log316(c); case TF_ST428: return eotf_st428(c); case TF_POW: return sign(c) * pow(abs(c), vec3(cm_eotf_args.arg1)); + case TF_COMPOUND_POWER_2_4: return eotf_compound_power_2_4(c); default: return c; } } @@ -131,6 +149,7 @@ vec3 apply_inv_eotf(vec3 c) { case TF_LOG316: return inv_eotf_log316(c); case TF_ST428: return inv_eotf_st428(c); case TF_POW: return sign(c) * pow(abs(c), vec3(cm_inv_eotf_args.arg1)); + case TF_COMPOUND_POWER_2_4: return inv_eotf_compound_power_2_4(c); default: return c; } } diff --git a/src/gfx_apis/vulkan/shaders_bin/out.frag.spv b/src/gfx_apis/vulkan/shaders_bin/out.frag.spv index 749e0ff685e3f299cef9a18e0bad4c95fa77fa98..d74211665cc8122459eeb268d1e3d834d378a9b3 100644 GIT binary patch literal 13824 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 Z!3>%U2aRtqLF!o$9~2g#G7nZZ0{~|FD|P?? literal 12764 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 XW?}&E#{!9i!UDtxg$1b0gO$wye2;6m literal 13536 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 tj0_AQF&Ku$= COMPOUND_POWER_2_4_SINCE { + self.send_supported_tf_named(TRANSFER_FUNCTION_COMPOUND_POWER_2_4); + } self.send_supported_primaries_named(PRIMARIES_SRGB); self.send_supported_primaries_named(PRIMARIES_PAL_M); self.send_supported_primaries_named(PRIMARIES_PAL); 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 181cf958..f6b7e4e8 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 @@ -7,7 +7,8 @@ use { cmm_primaries::{NamedPrimaries, Primaries}, }, ifs::color_management::{ - MIN_LUM_MUL_INV, PRIMARIES_MUL_INV, SRGB_DEPRECATED_SINCE, + COMPOUND_POWER_2_4_SINCE, MIN_LUM_MUL_INV, PRIMARIES_MUL_INV, SRGB_DEPRECATED_SINCE, + TRANSFER_FUNCTION_COMPOUND_POWER_2_4, consts::{ PRIMARIES_ADOBE_RGB, PRIMARIES_BT2020, PRIMARIES_CIE1931_XYZ, PRIMARIES_DCI_P3, PRIMARIES_DISPLAY_P3, PRIMARIES_GENERIC_FILM, PRIMARIES_NTSC, PRIMARIES_PAL, @@ -120,6 +121,9 @@ impl WpImageDescriptionCreatorParamsV1RequestHandler for WpImageDescriptionCreat TRANSFER_FUNCTION_EXT_SRGB if self.version < SRGB_DEPRECATED_SINCE => Eotf::Gamma22, TRANSFER_FUNCTION_ST2084_PQ => Eotf::St2084Pq, TRANSFER_FUNCTION_ST428 => Eotf::St428, + TRANSFER_FUNCTION_COMPOUND_POWER_2_4 if self.version >= COMPOUND_POWER_2_4_SINCE => { + Eotf::CompoundPower24 + } _ => { return Err(WpImageDescriptionCreatorParamsV1Error::UnsupportedTf( req.tf, 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 7a745389..9b19a15f 100644 --- a/src/ifs/color_management/wp_image_description_info_v1.rs +++ b/src/ifs/color_management/wp_image_description_info_v1.rs @@ -10,9 +10,10 @@ use { 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, PRIMARIES_SRGB, - TRANSFER_FUNCTION_BT1886, TRANSFER_FUNCTION_EXT_LINEAR, TRANSFER_FUNCTION_GAMMA22, - TRANSFER_FUNCTION_GAMMA28, TRANSFER_FUNCTION_LOG_100, TRANSFER_FUNCTION_LOG_316, - TRANSFER_FUNCTION_ST240, TRANSFER_FUNCTION_ST428, TRANSFER_FUNCTION_ST2084_PQ, + TRANSFER_FUNCTION_BT1886, TRANSFER_FUNCTION_COMPOUND_POWER_2_4, + TRANSFER_FUNCTION_EXT_LINEAR, TRANSFER_FUNCTION_GAMMA22, TRANSFER_FUNCTION_GAMMA28, + TRANSFER_FUNCTION_LOG_100, TRANSFER_FUNCTION_LOG_316, TRANSFER_FUNCTION_ST240, + TRANSFER_FUNCTION_ST428, TRANSFER_FUNCTION_ST2084_PQ, }, leaks::Tracker, object::{Object, Version}, @@ -51,6 +52,7 @@ impl WpImageDescriptionInfoV1 { self.send_tf_power(e); break 'tf; } + Eotf::CompoundPower24 => TRANSFER_FUNCTION_COMPOUND_POWER_2_4, }; self.send_tf_named(tf); } diff --git a/src/theme.rs b/src/theme.rs index 6c711c3f..91602aeb 100644 --- a/src/theme.rs +++ b/src/theme.rs @@ -108,6 +108,13 @@ impl Color { fn gamma28(c: f32) -> f32 { c.signum() * c.abs().powf(2.8) } + fn compound_power_2_4(c: f32) -> f32 { + if c < 0.04045 { + c / 12.92 + } else { + ((c + 0.055) / 1.055).powf(2.4) + } + } macro_rules! convert { ($tf:ident) => {{ r = $tf(r); @@ -135,6 +142,7 @@ impl Color { let pow = |c: f32| -> f32 { c.signum() * c.abs().powf(e) }; convert!(pow) } + Eotf::CompoundPower24 => convert!(compound_power_2_4), } Self { r, g, b, a: 1.0 } } @@ -237,6 +245,13 @@ impl Color { fn gamma28(c: f32) -> f32 { c.signum() * c.abs().powf(1.0 / 2.8) } + fn compound_power_2_4(c: f32) -> f32 { + if c < 0.0031308 { + 12.92 * c + } else { + 1.055 * c.powf(1.0 / 2.4) - 0.055 + } + } macro_rules! convert { ($tf:ident) => {{ for c in &mut res[..3] { @@ -270,6 +285,7 @@ impl Color { let pow = |c: f32| -> f32 { c.signum() * c.abs().powf(e) }; convert!(pow) } + Eotf::CompoundPower24 => convert!(compound_power_2_4), } if self.a < 1.0 { for c in &mut res[..3] {