From 37674a229c949d980cfd357e01fc118556c149c4 Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Sat, 21 Feb 2026 14:14:45 +0100 Subject: [PATCH] theme: add support for alpha modes --- src/cmm/cmm_transform.rs | 14 ++++-- src/gfx_api.rs | 8 ++++ src/ifs/jay_damage_tracking.rs | 10 +++- src/renderer.rs | 11 +++-- src/theme.rs | 84 ++++++++++++++++++++++++---------- 5 files changed, 93 insertions(+), 34 deletions(-) diff --git a/src/cmm/cmm_transform.rs b/src/cmm/cmm_transform.rs index 2c2816a7..64e576ca 100644 --- a/src/cmm/cmm_transform.rs +++ b/src/cmm/cmm_transform.rs @@ -1,6 +1,7 @@ use { crate::{ cmm::{cmm_eotf::Eotf, cmm_primaries::Primaries}, + gfx_api::AlphaMode, theme::Color, utils::ordered_float::F64, }, @@ -140,11 +141,14 @@ impl Mul for ColorMatrix { } } let [r, g, b] = self * [rgba[0] as f64, rgba[1] as f64, rgba[2] as f64]; - let mut color = Color::new(Eotf::Linear, r as f32, g as f32, b as f32); - if a < 1.0 { - color = color * a; - } - color + Color::new( + Eotf::Linear, + AlphaMode::Straight, + r as f32, + g as f32, + b as f32, + a, + ) } } diff --git a/src/gfx_api.rs b/src/gfx_api.rs index 44704c20..c622af3f 100644 --- a/src/gfx_api.rs +++ b/src/gfx_api.rs @@ -292,6 +292,14 @@ pub enum ResetStatus { Other(u32), } +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Default)] +pub enum AlphaMode { + #[default] + PremultipliedElectrical, + PremultipliedOptical, + Straight, +} + pub trait GfxBlendBuffer: Any + Debug {} pub trait GfxFramebuffer: Debug { diff --git a/src/ifs/jay_damage_tracking.rs b/src/ifs/jay_damage_tracking.rs index 7d58ed59..04d30db0 100644 --- a/src/ifs/jay_damage_tracking.rs +++ b/src/ifs/jay_damage_tracking.rs @@ -2,6 +2,7 @@ use { crate::{ client::{CAP_JAY_COMPOSITOR, Client, ClientCaps, ClientError}, cmm::cmm_eotf::Eotf, + gfx_api::AlphaMode, globals::{Global, GlobalName}, leaks::Tracker, object::{Object, Version}, @@ -97,7 +98,14 @@ impl JayDamageTrackingRequestHandler for JayDamageTracking { req: SetVisualizerColor, _slf: &Rc, ) -> Result<(), Self::Error> { - let color = Color::new(Eotf::Gamma22, req.r, req.g, req.b) * req.a; + let color = Color::new( + Eotf::Gamma22, + AlphaMode::Straight, + req.r, + req.g, + req.b, + req.a, + ); self.client.state.damage_visualizer.set_color(color); Ok(()) } diff --git a/src/renderer.rs b/src/renderer.rs index 2c94020f..2530ef03 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -1,6 +1,6 @@ use { crate::{ - gfx_api::{AcquireSync, GfxApiOpt, ReleaseSync, SampleRect}, + gfx_api::{AcquireSync, AlphaMode, GfxApiOpt, ReleaseSync, SampleRect}, icons::{IconState, SizedIcons}, ifs::wl_surface::{ SurfaceBuffer, WlSurface, @@ -493,8 +493,13 @@ impl Renderer<'_> { Some(bounds) => rect.intersect(*bounds), }; if !rect.is_empty() { - let color = Color::from_u32_premultiplied( - cd.eotf, color[0], color[1], color[2], color[3], + let color = Color::from_u32( + cd.eotf, + AlphaMode::PremultipliedElectrical, + color[0], + color[1], + color[2], + color[3], ); self.base.sync(); self.base diff --git a/src/theme.rs b/src/theme.rs index 91602aeb..8deda63d 100644 --- a/src/theme.rs +++ b/src/theme.rs @@ -3,6 +3,7 @@ use { crate::{ cmm::cmm_eotf::{Eotf, bt1886_eotf_args, bt1886_inv_eotf_args}, + gfx_api::AlphaMode, utils::clonecell::CloneCell, }, jay_config::theme::BarPosition, @@ -72,7 +73,27 @@ impl Color { a: 1.0, }; - pub fn new(eotf: Eotf, mut r: f32, mut g: f32, mut b: f32) -> Self { + pub fn new( + eotf: Eotf, + alpha_mode: AlphaMode, + mut r: f32, + mut g: f32, + mut b: f32, + a: f32, + ) -> Self { + if eotf == Eotf::Linear { + if alpha_mode == AlphaMode::Straight && a < 1.0 { + for c in [&mut r, &mut g, &mut b] { + *c *= a; + } + } + return Self { r, g, b, a }; + } + if alpha_mode == AlphaMode::PremultipliedElectrical && a < 1.0 && a > 0.0 { + for c in [&mut r, &mut g, &mut b] { + *c /= a; + } + } #[inline(always)] fn linear(c: f32) -> f32 { c @@ -144,23 +165,12 @@ impl Color { } Eotf::CompoundPower24 => convert!(compound_power_2_4), } - Self { r, g, b, a: 1.0 } - } - - pub fn new_premultiplied(eotf: Eotf, mut r: f32, mut g: f32, mut b: f32, a: f32) -> Self { - if eotf == Eotf::Linear { - return Self { r, g, b, a }; - } - if a < 1.0 && a > 0.0 { + if alpha_mode != AlphaMode::PremultipliedOptical && a < 1.0 { for c in [&mut r, &mut g, &mut b] { - *c /= a; + *c *= a; } } - let mut c = Self::new(eotf, r, g, b); - if a < 1.0 { - c = c * a; - } - c + Self { r, g, b, a } } pub fn is_opaque(&self) -> bool { @@ -172,26 +182,43 @@ impl Color { } pub fn from_srgb(r: u8, g: u8, b: u8) -> Self { - Self::new(Eotf::Gamma22, to_f32(r), to_f32(g), to_f32(b)) + Self::new( + Eotf::Gamma22, + AlphaMode::PremultipliedOptical, + to_f32(r), + to_f32(g), + to_f32(b), + 1.0, + ) } pub fn from_srgba_premultiplied(r: u8, g: u8, b: u8, a: u8) -> Self { - Self::new_premultiplied(Eotf::Gamma22, to_f32(r), to_f32(g), to_f32(b), to_f32(a)) + Self::new( + Eotf::Gamma22, + AlphaMode::PremultipliedElectrical, + to_f32(r), + to_f32(g), + to_f32(b), + to_f32(a), + ) } - pub fn from_u32_premultiplied(eotf: Eotf, r: u32, g: u32, b: u32, a: u32) -> Self { + pub fn from_u32(eotf: Eotf, alpha_mode: AlphaMode, r: u32, g: u32, b: u32, a: u32) -> Self { fn to_f32(c: u32) -> f32 { ((c as f64) / (u32::MAX as f64)) as f32 } - Self::new_premultiplied(eotf, to_f32(r), to_f32(g), to_f32(b), to_f32(a)) + Self::new(eotf, alpha_mode, to_f32(r), to_f32(g), to_f32(b), to_f32(a)) } pub fn from_srgba_straight(r: u8, g: u8, b: u8, a: u8) -> Self { - let mut c = Self::new(Eotf::Gamma22, to_f32(r), to_f32(g), to_f32(b)); - if a < 255 { - c = c * to_f32(a); - } - c + Self::new( + Eotf::Gamma22, + AlphaMode::Straight, + to_f32(r), + to_f32(g), + to_f32(b), + to_f32(a), + ) } pub fn to_srgba_premultiplied(self) -> [u8; 4] { @@ -314,7 +341,14 @@ impl Color { impl From for Color { fn from(f: jay_config::theme::Color) -> Self { let [r, g, b, a] = f.to_f32_premultiplied(); - Self::new_premultiplied(Eotf::Gamma22, r, g, b, a) + Self::new( + Eotf::Gamma22, + AlphaMode::PremultipliedElectrical, + r, + g, + b, + a, + ) } }