1
0
Fork 0
forked from wry/wry

color-management: use more consistent naming

This commit is contained in:
Julian Orth 2025-09-05 13:45:09 +02:00
parent 32db933242
commit 83e79b68e6
65 changed files with 439 additions and 510 deletions

View file

@ -28,8 +28,8 @@ use {
theme::{Color, colors::Colorable, sized::Resizable}, theme::{Color, colors::Colorable, sized::Resizable},
timer::Timer, timer::Timer,
video::{ video::{
ColorSpace, Connector, DrmDevice, Format, GfxApi, Mode, TearingMode, TransferFunction, ColorSpace, Connector, DrmDevice, Eotf, Format, GfxApi, Mode, TearingMode, Transform,
Transform, VrrMode, VrrMode,
connector_type::{CON_UNKNOWN, ConnectorType}, connector_type::{CON_UNKNOWN, ConnectorType},
}, },
window::{ window::{
@ -1042,16 +1042,11 @@ impl ConfigClient {
self.send(&ClientMessage::ConnectorSetFormat { connector, format }); self.send(&ClientMessage::ConnectorSetFormat { connector, format });
} }
pub fn connector_set_colors( pub fn connector_set_colors(&self, connector: Connector, color_space: ColorSpace, eotf: Eotf) {
&self,
connector: Connector,
color_space: ColorSpace,
transfer_function: TransferFunction,
) {
self.send(&ClientMessage::ConnectorSetColors { self.send(&ClientMessage::ConnectorSetColors {
connector, connector,
color_space, color_space,
transfer_function, eotf,
}); });
} }

View file

@ -12,8 +12,8 @@ use {
theme::{Color, colors::Colorable, sized::Resizable}, theme::{Color, colors::Colorable, sized::Resizable},
timer::Timer, timer::Timer,
video::{ video::{
ColorSpace, Connector, DrmDevice, Format, GfxApi, TearingMode, TransferFunction, ColorSpace, Connector, DrmDevice, Eotf, Format, GfxApi, TearingMode, Transform,
Transform, VrrMode, connector_type::ConnectorType, VrrMode, connector_type::ConnectorType,
}, },
window::{ContentType, TileState, Window, WindowMatcher, WindowType}, window::{ContentType, TileState, Window, WindowMatcher, WindowType},
workspace::WorkspaceDisplayOrder, workspace::WorkspaceDisplayOrder,
@ -555,7 +555,7 @@ pub enum ClientMessage<'a> {
ConnectorSetColors { ConnectorSetColors {
connector: Connector, connector: Connector,
color_space: ColorSpace, color_space: ColorSpace,
transfer_function: TransferFunction, eotf: Eotf,
}, },
ConnectorSetBrightness { ConnectorSetBrightness {
connector: Connector, connector: Connector,

View file

@ -273,26 +273,26 @@ impl Connector {
get!().connector_set_format(self, format); get!().connector_set_format(self, format);
} }
/// Sets the color space and transfer function of the connector. /// Sets the color space and EOTF of the connector.
/// ///
/// By default, the default values are used which usually means sRGB color space with /// By default, the default values are used which usually means sRGB color space with
/// sRGB transfer function. /// gamma22 EOTF.
/// ///
/// If the output supports it, HDR10 can be enabled by setting the color space to /// If the output supports it, HDR10 can be enabled by setting the color space to
/// BT.2020 and the transfer function to PQ. /// BT.2020 and the EOTF to PQ.
/// ///
/// Note that some displays might ignore incompatible settings. /// Note that some displays might ignore incompatible settings.
pub fn set_colors(self, color_space: ColorSpace, transfer_function: TransferFunction) { pub fn set_colors(self, color_space: ColorSpace, eotf: Eotf) {
get!().connector_set_colors(self, color_space, transfer_function); get!().connector_set_colors(self, color_space, eotf);
} }
/// Sets the brightness of the output. /// Sets the brightness of the output.
/// ///
/// By default or when `brightness` is `None`, the brightness depends on the /// By default or when `brightness` is `None`, the brightness depends on the
/// transfer function: /// EOTF:
/// ///
/// - [`TransferFunction::DEFAULT`]: The maximum brightness of the output. /// - [`Eotf::DEFAULT`]: The maximum brightness of the output.
/// - [`TransferFunction::PQ`]: 203 cd/m^2. /// - [`Eotf::PQ`]: 203 cd/m^2.
/// ///
/// This should only be used with the PQ transfer function. If the default transfer /// This should only be used with the PQ transfer function. If the default transfer
/// function is used, you should instead calibrate the hardware directly. /// function is used, you should instead calibrate the hardware directly.
@ -718,13 +718,16 @@ impl ColorSpace {
pub const BT2020: Self = Self(1); pub const BT2020: Self = Self(1);
} }
/// A transfer function. /// An electro-optical transfer function (EOTF).
#[derive(Serialize, Deserialize, Copy, Clone, Debug, Eq, PartialEq, Hash)] #[derive(Serialize, Deserialize, Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub struct TransferFunction(pub u32); pub struct Eotf(pub u32);
impl TransferFunction { #[deprecated = "use the Eotf type instead"]
/// The default transfer function (usually sRGB). pub type TransferFunction = Eotf;
impl Eotf {
/// The default EOTF (usually gamma22).
pub const DEFAULT: Self = Self(0); pub const DEFAULT: Self = Self(0);
/// The PQ transfer function. /// The PQ EOTF.
pub const PQ: Self = Self(1); pub const PQ: Self = Self(1);
} }

View file

@ -106,7 +106,7 @@ pub struct MonitorInfo {
pub non_desktop: bool, pub non_desktop: bool,
pub non_desktop_effective: bool, pub non_desktop_effective: bool,
pub vrr_capable: bool, pub vrr_capable: bool,
pub transfer_functions: Vec<BackendTransferFunction>, pub eotfs: Vec<BackendEotfs>,
pub color_spaces: Vec<BackendColorSpace>, pub color_spaces: Vec<BackendColorSpace>,
pub primaries: Primaries, pub primaries: Primaries,
pub luminance: Option<BackendLuminance>, pub luminance: Option<BackendLuminance>,
@ -540,7 +540,7 @@ pub trait BackendDrmLessee {
} }
#[derive(Copy, Clone, Debug, Eq, PartialEq, Default, Linearize)] #[derive(Copy, Clone, Debug, Eq, PartialEq, Default, Linearize)]
pub enum BackendTransferFunction { pub enum BackendEotfs {
#[default] #[default]
Default, Default,
Pq, Pq,
@ -560,18 +560,18 @@ pub struct BackendLuminance {
pub max_fall: f64, pub max_fall: f64,
} }
impl BackendTransferFunction { impl BackendEotfs {
pub fn to_drm(self) -> u8 { pub fn to_drm(self) -> u8 {
match self { match self {
BackendTransferFunction::Default => HDMI_EOTF_TRADITIONAL_GAMMA_SDR, BackendEotfs::Default => HDMI_EOTF_TRADITIONAL_GAMMA_SDR,
BackendTransferFunction::Pq => HDMI_EOTF_SMPTE_ST2084, BackendEotfs::Pq => HDMI_EOTF_SMPTE_ST2084,
} }
} }
pub const fn name(self) -> &'static str { pub const fn name(self) -> &'static str {
match self { match self {
BackendTransferFunction::Default => "default", BackendEotfs::Default => "default",
BackendTransferFunction::Pq => "pq", BackendEotfs::Pq => "pq",
} }
} }
} }
@ -609,5 +609,5 @@ pub struct BackendConnectorState {
pub tearing: bool, pub tearing: bool,
pub format: &'static Format, pub format: &'static Format,
pub color_space: BackendColorSpace, pub color_space: BackendColorSpace,
pub transfer_function: BackendTransferFunction, pub eotf: BackendEotfs,
} }

View file

@ -1,8 +1,8 @@
use { use {
crate::{ crate::{
backend::{ backend::{
BackendColorSpace, BackendConnectorState, BackendTransferFunction, Connector, BackendColorSpace, BackendConnectorState, BackendEotfs, Connector, ConnectorId,
ConnectorId, ConnectorKernelId, Mode, ConnectorKernelId, Mode,
}, },
backends::metal::MetalError, backends::metal::MetalError,
state::State, state::State,
@ -112,8 +112,8 @@ pub enum BackendConnectorTransactionError {
TearingNotSupported(ConnectorKernelId), TearingNotSupported(ConnectorKernelId),
#[error("Connector {} does not support color space {:?}", .0, .1)] #[error("Connector {} does not support color space {:?}", .0, .1)]
ColorSpaceNotSupported(ConnectorKernelId, BackendColorSpace), ColorSpaceNotSupported(ConnectorKernelId, BackendColorSpace),
#[error("Connector {} does not support transfer function {:?}", .0, .1)] #[error("Connector {} does not support EOTF {:?}", .0, .1)]
TransferFunctionNotSupported(ConnectorKernelId, BackendTransferFunction), EotfNotSupported(ConnectorKernelId, BackendEotfs),
#[error("Could not create an hdr metadata blob")] #[error("Could not create an hdr metadata blob")]
CreateHdrMetadataBlob(#[source] DrmError), CreateHdrMetadataBlob(#[source] DrmError),
#[error("Could not create a mode blob")] #[error("Could not create a mode blob")]

View file

@ -2,8 +2,7 @@ use {
crate::{ crate::{
allocator::BufferObject, allocator::BufferObject,
backend::{ backend::{
BackendColorSpace, BackendConnectorState, BackendTransferFunction, Connector, BackendColorSpace, BackendConnectorState, BackendEotfs, Connector, ConnectorEvent,
ConnectorEvent,
transaction::{ transaction::{
BackendAppliedConnectorTransaction, BackendConnectorTransaction, BackendAppliedConnectorTransaction, BackendConnectorTransaction,
BackendConnectorTransactionError, BackendPreparedConnectorTransaction, BackendConnectorTransactionError, BackendPreparedConnectorTransaction,
@ -669,16 +668,14 @@ impl MetalDeviceTransaction {
} }
} }
} }
match state.transfer_function { match state.eotf {
BackendTransferFunction::Default => {} BackendEotfs::Default => {}
BackendTransferFunction::Pq => { BackendEotfs::Pq => {
if !dd.supports_pq { if !dd.supports_pq {
return Err( return Err(BackendConnectorTransactionError::EotfNotSupported(
BackendConnectorTransactionError::TransferFunctionNotSupported( connector.obj.kernel_id(),
connector.obj.kernel_id(), state.eotf,
state.transfer_function, ));
),
);
} }
} }
} }
@ -686,12 +683,10 @@ impl MetalDeviceTransaction {
*cs = state.color_space.to_drm(); *cs = state.color_space.to_drm();
} }
if dd.hdr_metadata.is_some() { if dd.hdr_metadata.is_some() {
let new = if state.transfer_function == BackendTransferFunction::Default { let new = if state.eotf == BackendEotfs::Default {
None None
} else { } else {
Some(hdr_output_metadata::from_eotf( Some(hdr_output_metadata::from_eotf(state.eotf.to_drm()))
state.transfer_function.to_drm(),
))
}; };
if connector.new.hdr_metadata != new { if connector.new.hdr_metadata != new {
if let Some(new) = &new { if let Some(new) = &new {

View file

@ -4,10 +4,10 @@ use {
async_engine::{Phase, SpawnedFuture}, async_engine::{Phase, SpawnedFuture},
backend::{ backend::{
BackendColorSpace, BackendConnectorState, BackendDrmDevice, BackendDrmLease, BackendColorSpace, BackendConnectorState, BackendDrmDevice, BackendDrmLease,
BackendDrmLessee, BackendEvent, BackendLuminance, BackendTransferFunction, BackendDrmLessee, BackendEotfs, BackendEvent, BackendLuminance, CONCAP_CONNECTOR,
CONCAP_CONNECTOR, CONCAP_MODE_SETTING, CONCAP_PHYSICAL_DISPLAY, Connector, CONCAP_MODE_SETTING, CONCAP_PHYSICAL_DISPLAY, Connector, ConnectorCaps, ConnectorEvent,
ConnectorCaps, ConnectorEvent, ConnectorId, ConnectorKernelId, DrmDeviceId, ConnectorId, ConnectorKernelId, DrmDeviceId, HardwareCursor, HardwareCursorUpdate,
HardwareCursor, HardwareCursorUpdate, Mode, MonitorInfo, Mode, MonitorInfo,
transaction::{ transaction::{
BackendConnectorTransaction, BackendConnectorTransactionError, BackendConnectorTransaction, BackendConnectorTransactionError,
BackendConnectorTransactionType, BackendConnectorTransactionTypeDyn, BackendConnectorTransactionType, BackendConnectorTransactionTypeDyn,
@ -1092,7 +1092,7 @@ fn create_connector(
backend: backend.clone(), backend: backend.clone(),
connector_id: backend.state.connector_ids.next(), connector_id: backend.state.connector_ids.next(),
buffers: Default::default(), buffers: Default::default(),
color_description: CloneCell::new(backend.state.color_manager.srgb_srgb().clone()), color_description: CloneCell::new(backend.state.color_manager.srgb_gamma22().clone()),
lease: Cell::new(None), lease: Cell::new(None),
buffers_idle: Cell::new(true), buffers_idle: Cell::new(true),
crtc_idle: Cell::new(true), crtc_idle: Cell::new(true),
@ -1315,7 +1315,7 @@ fn create_connector_display_data(
tearing: false, tearing: false,
format: XRGB8888, format: XRGB8888,
color_space: Default::default(), color_space: Default::default(),
transfer_function: Default::default(), eotf: Default::default(),
}), }),
}); });
dev.backend dev.backend
@ -1341,13 +1341,13 @@ fn create_connector_display_data(
Err(_) => false, Err(_) => false,
}; };
{ {
let viable = match desired_state.transfer_function { let viable = match desired_state.eotf {
BackendTransferFunction::Default => true, BackendEotfs::Default => true,
BackendTransferFunction::Pq => supports_pq, BackendEotfs::Pq => supports_pq,
}; };
if !viable { if !viable {
log::warn!("Discarding previously desired transfer function"); log::warn!("Discarding previously desired EOTF");
desired_state.transfer_function = BackendTransferFunction::Default; desired_state.eotf = BackendEotfs::Default;
} }
} }
{ {
@ -1900,9 +1900,9 @@ impl MetalBackend {
modes.push(mode); modes.push(mode);
} }
} }
let mut transfer_functions = vec![]; let mut eotfs = vec![];
if dd.supports_pq { if dd.supports_pq {
transfer_functions.push(BackendTransferFunction::Pq); eotfs.push(BackendEotfs::Pq);
} }
let mut color_spaces = vec![]; let mut color_spaces = vec![];
if dd.supports_bt2020 { if dd.supports_bt2020 {
@ -1918,7 +1918,7 @@ impl MetalBackend {
non_desktop: dd.non_desktop, non_desktop: dd.non_desktop,
non_desktop_effective: dd.non_desktop_effective, non_desktop_effective: dd.non_desktop_effective,
vrr_capable: dd.vrr_capable, vrr_capable: dd.vrr_capable,
transfer_functions, eotfs,
color_spaces, color_spaces,
primaries: dd.primaries, primaries: dd.primaries,
luminance: dd.luminance, luminance: dd.luminance,
@ -2684,7 +2684,7 @@ impl MetalBackend {
.clear( .clear(
AcquireSync::Unnecessary, AcquireSync::Unnecessary,
ReleaseSync::None, ReleaseSync::None,
self.state.color_manager.srgb_srgb(), self.state.color_manager.srgb_gamma22(),
) )
.map_err(MetalError::Clear)?; .map_err(MetalError::Clear)?;
let (dev_tex, render_tex, render_fb, render_bo) = if dev.id == render_ctx.dev_id { let (dev_tex, render_tex, render_fb, render_bo) = if dev.id == render_ctx.dev_id {
@ -2742,7 +2742,7 @@ impl MetalBackend {
.clear( .clear(
AcquireSync::Unnecessary, AcquireSync::Unnecessary,
ReleaseSync::None, ReleaseSync::None,
self.state.color_manager.srgb_srgb(), self.state.color_manager.srgb_gamma22(),
) )
.map_err(MetalError::Clear)?; .map_err(MetalError::Clear)?;
let render_tex = match render_img.to_texture() { let render_tex = match render_img.to_texture() {

View file

@ -491,7 +491,7 @@ impl XBackend {
tearing: false, tearing: false,
format: FORMAT, format: FORMAT,
color_space: Default::default(), color_space: Default::default(),
transfer_function: Default::default(), eotf: Default::default(),
}; };
let output = Rc::new(XOutput { let output = Rc::new(XOutput {
id: self.state.connector_ids.next(), id: self.state.connector_ids.next(),
@ -599,7 +599,7 @@ impl XBackend {
non_desktop: false, non_desktop: false,
non_desktop_effective: false, non_desktop_effective: false,
vrr_capable: false, vrr_capable: false,
transfer_functions: vec![], eotfs: vec![],
color_spaces: vec![], color_spaces: vec![],
primaries: Primaries::SRGB, primaries: Primaries::SRGB,
luminance: None, luminance: None,
@ -774,7 +774,7 @@ impl XBackend {
let res = self.state.present_output( let res = self.state.present_output(
&node, &node,
&image.fb.get(), &image.fb.get(),
self.state.color_manager.srgb_srgb(), self.state.color_manager.srgb_gamma22(),
AcquireSync::Implicit, AcquireSync::Implicit,
ReleaseSync::Implicit, ReleaseSync::Implicit,
&image.tex.get(), &image.tex.get(),

View file

@ -1,7 +1,7 @@
use { use {
crate::{ crate::{
cli::{GlobalArgs, color::parse_color, duration::parse_duration}, cli::{GlobalArgs, color::parse_color, duration::parse_duration},
cmm::cmm_transfer_function::TransferFunction, cmm::cmm_eotf::Eotf,
tools::tool_client::{ToolClient, with_tool_client}, tools::tool_client::{ToolClient, with_tool_client},
wire::jay_damage_tracking::{SetVisualizerColor, SetVisualizerDecay, SetVisualizerEnabled}, wire::jay_damage_tracking::{SetVisualizerColor, SetVisualizerDecay, SetVisualizerEnabled},
}, },
@ -86,7 +86,7 @@ impl DamageTracking {
} }
DamageTrackingCmd::SetColor(c) => { DamageTrackingCmd::SetColor(c) => {
let color = parse_color(&c.color); let color = parse_color(&c.color);
let [r, g, b, a] = color.to_array(TransferFunction::Gamma22); let [r, g, b, a] = color.to_array(Eotf::Gamma22);
tc.send(SetVisualizerColor { tc.send(SetVisualizerColor {
self_id: dt, self_id: dt,
r, r,

View file

@ -1,6 +1,6 @@
use { use {
crate::{ crate::{
backend::{BackendColorSpace, BackendTransferFunction}, backend::{BackendColorSpace, BackendEotfs},
cli::GlobalArgs, cli::GlobalArgs,
format::{Format, XRGB8888}, format::{Format, XRGB8888},
scale::Scale, scale::Scale,
@ -333,14 +333,14 @@ pub struct ColorsSettings {
#[derive(Subcommand, Debug, Clone)] #[derive(Subcommand, Debug, Clone)]
pub enum ColorsCommand { pub enum ColorsCommand {
/// Sets the color space and transfer function of the output. /// Sets the color space and EOTF of the output.
Set { Set {
/// The name of the color space. /// The name of the color space.
#[clap(value_parser = PossibleValuesParser::new(color_space_possible_values()))] #[clap(value_parser = PossibleValuesParser::new(color_space_possible_values()))]
color_space: String, color_space: String,
/// The name of the transfer function. /// The name of the EOTF.
#[clap(value_parser = PossibleValuesParser::new(transfer_function_possible_values()))] #[clap(value_parser = PossibleValuesParser::new(eotf_possible_values()))]
transfer_function: String, eotf: String,
}, },
} }
@ -357,13 +357,13 @@ fn color_space_possible_values() -> Vec<PossibleValue> {
res res
} }
fn transfer_function_possible_values() -> Vec<PossibleValue> { fn eotf_possible_values() -> Vec<PossibleValue> {
let mut res = vec![]; let mut res = vec![];
for cs in BackendTransferFunction::variants() { for cs in BackendEotfs::variants() {
use BackendTransferFunction::*; use BackendEotfs::*;
let help = match cs { let help = match cs {
Default => "The default transfer function (usually sRGB)", Default => "The default EOTF (usually gamma22)",
Pq => "The PQ transfer function", Pq => "The PQ EOTF",
}; };
res.push(PossibleValue::new(cs.name()).help(help)); res.push(PossibleValue::new(cs.name()).help(help));
} }
@ -375,12 +375,12 @@ pub struct BrightnessArgs {
/// The brightness of standard white in cd/m^2 or `default` to use the default /// The brightness of standard white in cd/m^2 or `default` to use the default
/// brightness. /// brightness.
/// ///
/// The default brightness depends on the transfer function: /// The default brightness depends on the EOTF:
/// ///
/// - default: the maximum display brightness /// - default: the maximum display brightness
/// - PQ: 203 cd/m^2. /// - PQ: 203 cd/m^2.
/// ///
/// When using the default transfer function, you likely want to set this to `default` /// When using the default EOTF, you likely want to set this to `default`
/// and adjust the display hardware brightness setting instead. /// and adjust the display hardware brightness setting instead.
/// ///
/// This has no effect unless the vulkan renderer is used. /// This has no effect unless the vulkan renderer is used.
@ -462,8 +462,8 @@ struct Output {
pub flip_margin_ns: Option<u64>, pub flip_margin_ns: Option<u64>,
pub supported_color_spaces: Vec<String>, pub supported_color_spaces: Vec<String>,
pub current_color_space: Option<String>, pub current_color_space: Option<String>,
pub supported_transfer_functions: Vec<String>, pub supported_eotfs: Vec<String>,
pub current_transfer_function: Option<String>, pub current_eotf: Option<String>,
pub brightness_range: Option<(f64, f64)>, pub brightness_range: Option<(f64, f64)>,
pub brightness: Option<f64>, pub brightness: Option<f64>,
} }
@ -713,15 +713,12 @@ impl Randr {
eprintln!("Could not change the colors: {}", msg); eprintln!("Could not change the colors: {}", msg);
}); });
match a.command { match a.command {
ColorsCommand::Set { ColorsCommand::Set { color_space, eotf } => {
color_space,
transfer_function,
} => {
tc.send(jay_randr::SetColors { tc.send(jay_randr::SetColors {
self_id: randr, self_id: randr,
output: &args.output, output: &args.output,
color_space: &color_space, color_space: &color_space,
transfer_function: &transfer_function, eotf: &eotf,
}); });
} }
} }
@ -957,19 +954,17 @@ impl Randr {
handle_cs("default"); handle_cs("default");
o.supported_color_spaces.iter().for_each(|cs| handle_cs(cs)); o.supported_color_spaces.iter().for_each(|cs| handle_cs(cs));
} }
if o.supported_transfer_functions.is_not_empty() { if o.supported_eotfs.is_not_empty() {
println!(" transfer functions:"); println!(" eotfs:");
let handle_tf = |tf: &str| { let handle_tf = |tf: &str| {
let current = match Some(tf) == o.current_transfer_function.as_deref() { let current = match Some(tf) == o.current_eotf.as_deref() {
false => "", false => "",
true => " (current)", true => " (current)",
}; };
println!(" {tf}{current}"); println!(" {tf}{current}");
}; };
handle_tf("default"); handle_tf("default");
o.supported_transfer_functions o.supported_eotfs.iter().for_each(|tf| handle_tf(tf));
.iter()
.for_each(|tf| handle_tf(tf));
} }
if let Some((min, max)) = o.brightness_range { if let Some((min, max)) = o.brightness_range {
println!(" min brightness: {:>10.4} cd/m^2", min); println!(" min brightness: {:>10.4} cd/m^2", min);
@ -1130,19 +1125,17 @@ impl Randr {
let output = c.output.as_mut().unwrap(); let output = c.output.as_mut().unwrap();
output.current_color_space = Some(msg.color_space.to_string()); output.current_color_space = Some(msg.color_space.to_string());
}); });
jay_randr::SupportedTransferFunction::handle(tc, randr, data.clone(), |data, msg| { jay_randr::SupportedEotf::handle(tc, randr, data.clone(), |data, msg| {
let mut data = data.borrow_mut(); let mut data = data.borrow_mut();
let c = data.connectors.last_mut().unwrap(); let c = data.connectors.last_mut().unwrap();
let output = c.output.as_mut().unwrap(); let output = c.output.as_mut().unwrap();
output output.supported_eotfs.push(msg.eotf.to_string());
.supported_transfer_functions
.push(msg.transfer_function.to_string());
}); });
jay_randr::CurrentTransferFunction::handle(tc, randr, data.clone(), |data, msg| { jay_randr::CurrentEotf::handle(tc, randr, data.clone(), |data, msg| {
let mut data = data.borrow_mut(); let mut data = data.borrow_mut();
let c = data.connectors.last_mut().unwrap(); let c = data.connectors.last_mut().unwrap();
let output = c.output.as_mut().unwrap(); let output = c.output.as_mut().unwrap();
output.current_transfer_function = Some(msg.transfer_function.to_string()); output.current_eotf = Some(msg.eotf.to_string());
}); });
jay_randr::BrightnessRange::handle(tc, randr, data.clone(), |data, msg| { jay_randr::BrightnessRange::handle(tc, randr, data.clone(), |data, msg| {
let mut data = data.borrow_mut(); let mut data = data.borrow_mut();

View file

@ -1,8 +1,8 @@
pub mod cmm_description; pub mod cmm_description;
pub mod cmm_eotf;
pub mod cmm_luminance; pub mod cmm_luminance;
pub mod cmm_manager; pub mod cmm_manager;
pub mod cmm_primaries; pub mod cmm_primaries;
#[cfg(test)] #[cfg(test)]
mod cmm_tests; mod cmm_tests;
pub mod cmm_transfer_function;
pub mod cmm_transform; pub mod cmm_transform;

View file

@ -1,10 +1,10 @@
use { use {
crate::{ crate::{
cmm::{ cmm::{
cmm_eotf::Eotf,
cmm_luminance::{Luminance, TargetLuminance, white_balance}, cmm_luminance::{Luminance, TargetLuminance, white_balance},
cmm_manager::Shared, cmm_manager::Shared,
cmm_primaries::{NamedPrimaries, Primaries}, cmm_primaries::{NamedPrimaries, Primaries},
cmm_transfer_function::TransferFunction,
cmm_transform::{ColorMatrix, Local, Xyz, bradford_adjustment}, cmm_transform::{ColorMatrix, Local, Xyz, bradford_adjustment},
}, },
utils::ordered_float::F64, utils::ordered_float::F64,
@ -34,7 +34,7 @@ pub struct ColorDescription {
pub id: ColorDescriptionId, pub id: ColorDescriptionId,
pub linear: Rc<LinearColorDescription>, pub linear: Rc<LinearColorDescription>,
pub named_primaries: Option<NamedPrimaries>, pub named_primaries: Option<NamedPrimaries>,
pub transfer_function: TransferFunction, pub eotf: Eotf,
pub(super) shared: Rc<Shared>, pub(super) shared: Rc<Shared>,
} }
@ -66,8 +66,7 @@ impl LinearColorDescription {
impl ColorDescription { impl ColorDescription {
pub fn embeds_into(&self, target: &Self) -> bool { pub fn embeds_into(&self, target: &Self) -> bool {
self.transfer_function == target.transfer_function self.eotf == target.eotf && self.linear.embeds_into(&target.linear)
&& self.linear.embeds_into(&target.linear)
} }
} }

View file

@ -1,7 +1,7 @@
use linearize::Linearize; use linearize::Linearize;
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Linearize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Linearize)]
pub enum TransferFunction { pub enum Eotf {
Linear, Linear,
St2084Pq, St2084Pq,
Bt1886, Bt1886,

View file

@ -5,9 +5,9 @@ use {
ColorDescription, ColorDescriptionIds, LinearColorDescription, ColorDescription, ColorDescriptionIds, LinearColorDescription,
LinearColorDescriptionId, LinearColorDescriptionIds, LinearColorDescriptionId, LinearColorDescriptionIds,
}, },
cmm_eotf::Eotf,
cmm_luminance::{Luminance, TargetLuminance}, cmm_luminance::{Luminance, TargetLuminance},
cmm_primaries::{NamedPrimaries, Primaries}, cmm_primaries::{NamedPrimaries, Primaries},
cmm_transfer_function::TransferFunction,
}, },
utils::{copyhashmap::CopyHashMap, numcell::NumCell, ordered_float::F64}, utils::{copyhashmap::CopyHashMap, numcell::NumCell, ordered_float::F64},
}, },
@ -19,7 +19,7 @@ pub struct ColorManager {
linear_descriptions: CopyHashMap<LinearDescriptionKey, Weak<LinearColorDescription>>, linear_descriptions: CopyHashMap<LinearDescriptionKey, Weak<LinearColorDescription>>,
complete_descriptions: CopyHashMap<CompleteDescriptionKey, Weak<ColorDescription>>, complete_descriptions: CopyHashMap<CompleteDescriptionKey, Weak<ColorDescription>>,
shared: Rc<Shared>, shared: Rc<Shared>,
srgb_srgb: Rc<ColorDescription>, srgb_gamma22: Rc<ColorDescription>,
srgb_linear: Rc<ColorDescription>, srgb_linear: Rc<ColorDescription>,
windows_scrgb: Rc<ColorDescription>, windows_scrgb: Rc<ColorDescription>,
} }
@ -45,7 +45,7 @@ struct LinearDescriptionKey {
struct CompleteDescriptionKey { struct CompleteDescriptionKey {
linear: LinearColorDescriptionId, linear: LinearColorDescriptionId,
named_primaries: Option<NamedPrimaries>, named_primaries: Option<NamedPrimaries>,
transfer_function: TransferFunction, eotf: Eotf,
} }
impl ColorManager { impl ColorManager {
@ -55,7 +55,7 @@ impl ColorManager {
let complete_descriptions = CopyHashMap::default(); let complete_descriptions = CopyHashMap::default();
let shared = Rc::new(Shared::default()); let shared = Rc::new(Shared::default());
let _ = shared.complete_ids.next(); let _ = shared.complete_ids.next();
let srgb_srgb = get_description( let srgb_gamma22 = get_description(
&shared, &shared,
&linear_descriptions, &linear_descriptions,
&complete_descriptions, &complete_descriptions,
@ -63,7 +63,7 @@ impl ColorManager {
Some(NamedPrimaries::Srgb), Some(NamedPrimaries::Srgb),
Primaries::SRGB, Primaries::SRGB,
Luminance::SRGB, Luminance::SRGB,
TransferFunction::Gamma22, Eotf::Gamma22,
Primaries::SRGB, Primaries::SRGB,
Luminance::SRGB.to_target(), Luminance::SRGB.to_target(),
None, None,
@ -71,10 +71,10 @@ impl ColorManager {
); );
let srgb_linear = get_description2( let srgb_linear = get_description2(
&shared, &shared,
&srgb_srgb.linear, &srgb_gamma22.linear,
&complete_descriptions, &complete_descriptions,
Some(NamedPrimaries::Srgb), Some(NamedPrimaries::Srgb),
TransferFunction::Linear, Eotf::Linear,
); );
let windows_scrgb = get_description( let windows_scrgb = get_description(
&shared, &shared,
@ -84,7 +84,7 @@ impl ColorManager {
Some(NamedPrimaries::Srgb), Some(NamedPrimaries::Srgb),
Primaries::SRGB, Primaries::SRGB,
Luminance::WINDOWS_SCRGB, Luminance::WINDOWS_SCRGB,
TransferFunction::Linear, Eotf::Linear,
Primaries::BT2020, Primaries::BT2020,
Luminance::ST2084_PQ.to_target(), Luminance::ST2084_PQ.to_target(),
None, None,
@ -95,14 +95,14 @@ impl ColorManager {
linear_descriptions, linear_descriptions,
complete_descriptions, complete_descriptions,
shared, shared,
srgb_srgb, srgb_gamma22,
srgb_linear, srgb_linear,
windows_scrgb, windows_scrgb,
}) })
} }
pub fn srgb_srgb(&self) -> &Rc<ColorDescription> { pub fn srgb_gamma22(&self) -> &Rc<ColorDescription> {
&self.srgb_srgb &self.srgb_gamma22
} }
pub fn srgb_linear(&self) -> &Rc<ColorDescription> { pub fn srgb_linear(&self) -> &Rc<ColorDescription> {
@ -118,7 +118,7 @@ impl ColorManager {
named_primaries: Option<NamedPrimaries>, named_primaries: Option<NamedPrimaries>,
primaries: Primaries, primaries: Primaries,
luminance: Luminance, luminance: Luminance,
transfer_function: TransferFunction, eotf: Eotf,
target_primaries: Primaries, target_primaries: Primaries,
target_luminance: TargetLuminance, target_luminance: TargetLuminance,
max_cll: Option<F64>, max_cll: Option<F64>,
@ -132,7 +132,7 @@ impl ColorManager {
named_primaries, named_primaries,
primaries, primaries,
luminance, luminance,
transfer_function, eotf,
target_primaries, target_primaries,
target_luminance, target_luminance,
max_cll, max_cll,
@ -143,14 +143,14 @@ impl ColorManager {
pub fn get_with_tf( pub fn get_with_tf(
self: &Rc<Self>, self: &Rc<Self>,
cd: &Rc<ColorDescription>, cd: &Rc<ColorDescription>,
transfer_function: TransferFunction, eotf: Eotf,
) -> Rc<ColorDescription> { ) -> Rc<ColorDescription> {
get_description2( get_description2(
&self.shared, &self.shared,
&cd.linear, &cd.linear,
&self.complete_descriptions, &self.complete_descriptions,
cd.named_primaries, cd.named_primaries,
transfer_function, eotf,
) )
} }
} }
@ -163,7 +163,7 @@ fn get_description(
named_primaries: Option<NamedPrimaries>, named_primaries: Option<NamedPrimaries>,
primaries: Primaries, primaries: Primaries,
luminance: Luminance, luminance: Luminance,
transfer_function: TransferFunction, eotf: Eotf,
target_primaries: Primaries, target_primaries: Primaries,
target_luminance: TargetLuminance, target_luminance: TargetLuminance,
max_cll: Option<F64>, max_cll: Option<F64>,
@ -189,13 +189,7 @@ fn get_description(
}; };
if let Some(d) = linear_descriptions.get(&key) { if let Some(d) = linear_descriptions.get(&key) {
if let Some(d) = d.upgrade() { if let Some(d) = d.upgrade() {
return get_description2( return get_description2(shared, &d, complete_descriptions, named_primaries, eotf);
shared,
&d,
complete_descriptions,
named_primaries,
transfer_function,
);
} }
shared.dead_linear.fetch_sub(1); shared.dead_linear.fetch_sub(1);
} }
@ -216,13 +210,13 @@ fn get_description(
let key = CompleteDescriptionKey { let key = CompleteDescriptionKey {
linear: d.id, linear: d.id,
named_primaries, named_primaries,
transfer_function, eotf,
}; };
let d = Rc::new(ColorDescription { let d = Rc::new(ColorDescription {
id: shared.complete_ids.next(), id: shared.complete_ids.next(),
linear: d, linear: d,
named_primaries, named_primaries,
transfer_function, eotf,
shared: shared.clone(), shared: shared.clone(),
}); });
complete_descriptions.set(key, Rc::downgrade(&d)); complete_descriptions.set(key, Rc::downgrade(&d));
@ -234,12 +228,12 @@ fn get_description2(
ld: &Rc<LinearColorDescription>, ld: &Rc<LinearColorDescription>,
complete_descriptions: &CopyHashMap<CompleteDescriptionKey, Weak<ColorDescription>>, complete_descriptions: &CopyHashMap<CompleteDescriptionKey, Weak<ColorDescription>>,
named_primaries: Option<NamedPrimaries>, named_primaries: Option<NamedPrimaries>,
transfer_function: TransferFunction, eotf: Eotf,
) -> Rc<ColorDescription> { ) -> Rc<ColorDescription> {
let key = CompleteDescriptionKey { let key = CompleteDescriptionKey {
linear: ld.id, linear: ld.id,
named_primaries, named_primaries,
transfer_function, eotf,
}; };
if let Some(d) = complete_descriptions.get(&key) { if let Some(d) = complete_descriptions.get(&key) {
if let Some(d) = d.upgrade() { if let Some(d) = d.upgrade() {
@ -251,7 +245,7 @@ fn get_description2(
id: shared.complete_ids.next(), id: shared.complete_ids.next(),
linear: ld.clone(), linear: ld.clone(),
named_primaries, named_primaries,
transfer_function, eotf,
shared: shared.clone(), shared: shared.clone(),
}); });
complete_descriptions.set(key, Rc::downgrade(&d)); complete_descriptions.set(key, Rc::downgrade(&d));

View file

@ -135,8 +135,8 @@ mod matrices {
mod transforms { mod transforms {
use crate::cmm::{ use crate::cmm::{
cmm_luminance::Luminance, cmm_manager::ColorManager, cmm_primaries::Primaries, cmm_eotf::Eotf, cmm_luminance::Luminance, cmm_manager::ColorManager,
cmm_transfer_function::TransferFunction, cmm_primaries::Primaries,
}; };
fn check(p1: Primaries, p2: Primaries, expected: [[f64; 4]; 3]) { fn check(p1: Primaries, p2: Primaries, expected: [[f64; 4]; 3]) {
@ -146,7 +146,7 @@ mod transforms {
None, None,
p, p,
Luminance::SRGB, Luminance::SRGB,
TransferFunction::Linear, Eotf::Linear,
p, p,
Luminance::SRGB.to_target(), Luminance::SRGB.to_target(),
None, None,

View file

@ -1,6 +1,6 @@
use { use {
crate::{ crate::{
cmm::{cmm_primaries::Primaries, cmm_transfer_function::TransferFunction}, cmm::{cmm_eotf::Eotf, cmm_primaries::Primaries},
theme::Color, theme::Color,
utils::{debug_fn::debug_fn, ordered_float::F64}, utils::{debug_fn::debug_fn, ordered_float::F64},
}, },
@ -131,7 +131,7 @@ impl<T, U> Mul<Color> for ColorMatrix<T, U> {
type Output = Color; type Output = Color;
fn mul(self, rhs: Color) -> Self::Output { fn mul(self, rhs: Color) -> Self::Output {
let mut rgba = rhs.to_array(TransferFunction::Linear); let mut rgba = rhs.to_array(Eotf::Linear);
let a = rgba[3]; let a = rgba[3];
if a < 1.0 && a > 0.0 { if a < 1.0 && a > 0.0 {
for c in &mut rgba[..3] { for c in &mut rgba[..3] {
@ -139,7 +139,7 @@ impl<T, U> Mul<Color> for ColorMatrix<T, U> {
} }
} }
let [r, g, b] = self * [rgba[0] as f64, rgba[1] as f64, rgba[2] as f64]; let [r, g, b] = self * [rgba[0] as f64, rgba[1] as f64, rgba[2] as f64];
let mut color = Color::new(TransferFunction::Linear, r as f32, g as f32, b as f32); let mut color = Color::new(Eotf::Linear, r as f32, g as f32, b as f32);
if a < 1.0 { if a < 1.0 {
color = color * a; color = color * a;
} }

View file

@ -652,7 +652,7 @@ fn create_dummy_output(state: &Rc<State>) {
tearing: false, tearing: false,
format: XRGB8888, format: XRGB8888,
color_space: Default::default(), color_space: Default::default(),
transfer_function: Default::default(), eotf: Default::default(),
}; };
let id = state.connector_ids.next(); let id = state.connector_ids.next();
let connector = Rc::new(DummyOutput { id }) as Rc<dyn Connector>; let connector = Rc::new(DummyOutput { id }) as Rc<dyn Connector>;
@ -680,7 +680,7 @@ fn create_dummy_output(state: &Rc<State>) {
tearing_mode: TearingMode::Never.to_config(), tearing_mode: TearingMode::Never.to_config(),
format: XRGB8888, format: XRGB8888,
color_space: backend_state.color_space, color_space: backend_state.color_space,
transfer_function: backend_state.transfer_function, eotf: backend_state.eotf,
supported_formats: Default::default(), supported_formats: Default::default(),
brightness: None, brightness: None,
}; };

View file

@ -2,12 +2,12 @@ use {
crate::{ crate::{
async_engine::SpawnedFuture, async_engine::SpawnedFuture,
backend::{ backend::{
self, BackendColorSpace, BackendTransferFunction, ConnectorId, DrmDeviceId, self, BackendColorSpace, BackendEotfs, ConnectorId, DrmDeviceId,
InputDeviceAccelProfile, InputDeviceCapability, InputDeviceClickMethod, InputDeviceId, InputDeviceAccelProfile, InputDeviceCapability, InputDeviceClickMethod, InputDeviceId,
transaction::BackendConnectorTransactionError, transaction::BackendConnectorTransactionError,
}, },
client::{Client, ClientId}, client::{Client, ClientId},
cmm::cmm_transfer_function::TransferFunction, cmm::cmm_eotf::Eotf,
compositor::MAX_EXTENTS, compositor::MAX_EXTENTS,
config::ConfigProxy, config::ConfigProxy,
criteria::{ criteria::{
@ -69,9 +69,8 @@ use {
theme::{colors::Colorable, sized::Resizable}, theme::{colors::Colorable, sized::Resizable},
timer::Timer as JayTimer, timer::Timer as JayTimer,
video::{ video::{
ColorSpace, Connector, DrmDevice, Format as ConfigFormat, GfxApi, ColorSpace, Connector, DrmDevice, Eotf as ConfigEotf, Format as ConfigFormat, GfxApi,
TearingMode as ConfigTearingMode, TransferFunction as ConfigTransferFunction, TearingMode as ConfigTearingMode, Transform, VrrMode as ConfigVrrMode,
Transform, VrrMode as ConfigVrrMode,
}, },
window::{TileState, Window, WindowMatcher}, window::{TileState, Window, WindowMatcher},
workspace::WorkspaceDisplayOrder, workspace::WorkspaceDisplayOrder,
@ -1285,23 +1284,23 @@ impl ConfigProxyHandler {
&self, &self,
connector: Connector, connector: Connector,
color_space: ColorSpace, color_space: ColorSpace,
transfer_function: ConfigTransferFunction, eotf: ConfigEotf,
) -> Result<(), CphError> { ) -> Result<(), CphError> {
let bcs = match color_space { let bcs = match color_space {
ColorSpace::DEFAULT => BackendColorSpace::Default, ColorSpace::DEFAULT => BackendColorSpace::Default,
ColorSpace::BT2020 => BackendColorSpace::Bt2020, ColorSpace::BT2020 => BackendColorSpace::Bt2020,
_ => return Err(CphError::UnknownColorSpace(color_space)), _ => return Err(CphError::UnknownColorSpace(color_space)),
}; };
let btf = match transfer_function { let btf = match eotf {
ConfigTransferFunction::DEFAULT => BackendTransferFunction::Default, ConfigEotf::DEFAULT => BackendEotfs::Default,
ConfigTransferFunction::PQ => BackendTransferFunction::Pq, ConfigEotf::PQ => BackendEotfs::Pq,
_ => return Err(CphError::UnknownTransferFunction(transfer_function)), _ => return Err(CphError::UnknownEotf(eotf)),
}; };
let connector = self.get_connector(connector)?; let connector = self.get_connector(connector)?;
connector connector
.modify_state(&self.state, |s| { .modify_state(&self.state, |s| {
s.color_space = bcs; s.color_space = bcs;
s.transfer_function = btf; s.eotf = btf;
}) })
.map_err(CphError::ModifyConnectorState)?; .map_err(CphError::ModifyConnectorState)?;
Ok(()) Ok(())
@ -2365,7 +2364,7 @@ impl ConfigProxyHandler {
fn handle_get_color(&self, colorable: Colorable) -> Result<(), CphError> { fn handle_get_color(&self, colorable: Colorable) -> Result<(), CphError> {
let color = self.get_color(colorable)?.get(); let color = self.get_color(colorable)?.get();
let [r, g, b, a] = color.to_array(TransferFunction::Gamma22); let [r, g, b, a] = color.to_array(Eotf::Gamma22);
let color = jay_config::theme::Color::new_f32_premultiplied(r, g, b, a); let color = jay_config::theme::Color::new_f32_premultiplied(r, g, b, a);
self.respond(Response::GetColor { color }); self.respond(Response::GetColor { color });
Ok(()) Ok(())
@ -2930,9 +2929,9 @@ impl ConfigProxyHandler {
ClientMessage::ConnectorSetColors { ClientMessage::ConnectorSetColors {
connector, connector,
color_space, color_space,
transfer_function, eotf,
} => self } => self
.handle_connector_set_colors(connector, color_space, transfer_function) .handle_connector_set_colors(connector, color_space, eotf)
.wrn("connector_set_colors")?, .wrn("connector_set_colors")?,
ClientMessage::ConnectorSetBrightness { ClientMessage::ConnectorSetBrightness {
connector, connector,
@ -3211,8 +3210,8 @@ enum CphError {
UnknownXScalingMode(XScalingMode), UnknownXScalingMode(XScalingMode),
#[error("Unknown color space {0:?}")] #[error("Unknown color space {0:?}")]
UnknownColorSpace(ColorSpace), UnknownColorSpace(ColorSpace),
#[error("Unknown transfer function {0:?}")] #[error("Unknown EOTF {0:?}")]
UnknownTransferFunction(ConfigTransferFunction), UnknownEotf(ConfigEotf),
#[error("Client {0:?} does not exist")] #[error("Client {0:?} does not exist")]
ClientDoesNotExist(ConfigClient), ClientDoesNotExist(ConfigClient),
#[error("Window {0:?} does not exist")] #[error("Window {0:?} does not exist")]

View file

@ -397,7 +397,7 @@ fn render_img(image: &InstantiatedCursorImage, renderer: &mut Renderer, x: Fixed
AcquireSync::None, AcquireSync::None,
ReleaseSync::None, ReleaseSync::None,
false, false,
renderer.state.color_manager.srgb_srgb(), renderer.state.color_manager.srgb_gamma22(),
); );
} }
} }
@ -422,7 +422,7 @@ impl Cursor for StaticCursor {
AcquireSync::None, AcquireSync::None,
ReleaseSync::None, ReleaseSync::None,
false, false,
renderer.state.color_manager.srgb_srgb(), renderer.state.color_manager.srgb_gamma22(),
); );
} }
} }
@ -465,7 +465,7 @@ impl Cursor for AnimatedCursor {
AcquireSync::None, AcquireSync::None,
ReleaseSync::None, ReleaseSync::None,
false, false,
renderer.state.color_manager.srgb_srgb(), renderer.state.color_manager.srgb_gamma22(),
); );
} }
} }

View file

@ -165,7 +165,7 @@ impl DamageVisualizer {
let dy = -cursor_rect.y1(); let dy = -cursor_rect.y1();
let decay_millis = decay.as_millis() as u64 as f32; let decay_millis = decay.as_millis() as u64 as f32;
renderer.ops.push(GfxApiOpt::Sync); renderer.ops.push(GfxApiOpt::Sync);
let srgb = &self.color_manager.srgb_srgb().linear; let srgb = &self.color_manager.srgb_gamma22().linear;
for entry in entries.iter().rev() { for entry in entries.iter().rev() {
let region = Region::new(entry.rect); let region = Region::new(entry.rect);
let region = region.subtract_cow(&used); let region = region.subtract_cow(&used);

View file

@ -895,7 +895,7 @@ pub fn create_render_pass(
return GfxRenderPass { return GfxRenderPass {
ops: vec![], ops: vec![],
clear: Some(Color::SOLID_BLACK), clear: Some(Color::SOLID_BLACK),
clear_cd: state.color_manager.srgb_srgb().linear.clone(), clear_cd: state.color_manager.srgb_gamma22().linear.clone(),
}; };
} }
let mut ops = vec![]; let mut ops = vec![];
@ -962,7 +962,7 @@ pub fn create_render_pass(
GfxRenderPass { GfxRenderPass {
ops, ops,
clear: Some(c), clear: Some(c),
clear_cd: state.color_manager.srgb_srgb().linear.clone(), clear_cd: state.color_manager.srgb_gamma22().linear.clone(),
} }
} }

View file

@ -67,7 +67,7 @@ macro_rules! dynload {
use { use {
crate::{ crate::{
cmm::cmm_transfer_function::TransferFunction, cmm::cmm_eotf::Eotf,
gfx_api::{ gfx_api::{
AcquireSync, CopyTexture, FramebufferRect, GfxApiOpt, GfxContext, GfxError, GfxTexture, AcquireSync, CopyTexture, FramebufferRect, GfxApiOpt, GfxContext, GfxError, GfxTexture,
ReleaseSync, SyncFile, ReleaseSync, SyncFile,
@ -309,7 +309,7 @@ fn run_ops(fb: &Framebuffer, ops: &[GfxApiOpt]) -> Option<SyncFile> {
} }
fn fill_boxes3(ctx: &GlRenderContext, boxes: &[[f32; 2]], color: &Color) { fn fill_boxes3(ctx: &GlRenderContext, boxes: &[[f32; 2]], color: &Color) {
let [r, g, b, a] = color.to_array(TransferFunction::Gamma22); let [r, g, b, a] = color.to_array(Eotf::Gamma22);
let gles = ctx.ctx.dpy.gles; let gles = ctx.ctx.dpy.gles;
unsafe { unsafe {
(gles.glUseProgram)(ctx.fill_prog.prog); (gles.glUseProgram)(ctx.fill_prog.prog);

View file

@ -2,7 +2,7 @@ use {
crate::{ crate::{
cmm::{ cmm::{
cmm_description::{ColorDescription, LinearColorDescription}, cmm_description::{ColorDescription, LinearColorDescription},
cmm_transfer_function::TransferFunction, cmm_eotf::Eotf,
}, },
format::Format, format::Format,
gfx_api::{ gfx_api::{
@ -82,7 +82,7 @@ impl Framebuffer {
(gles.glBindFramebuffer)(GL_FRAMEBUFFER, self.gl.fbo); (gles.glBindFramebuffer)(GL_FRAMEBUFFER, self.gl.fbo);
(gles.glViewport)(0, 0, self.gl.width, self.gl.height); (gles.glViewport)(0, 0, self.gl.width, self.gl.height);
if let Some(c) = clear { if let Some(c) = clear {
let [r, g, b, a] = c.to_array(TransferFunction::Gamma22); let [r, g, b, a] = c.to_array(Eotf::Gamma22);
(gles.glClearColor)(r, g, b, a); (gles.glClearColor)(r, g, b, a);
(gles.glClear)(GL_COLOR_BUFFER_BIT); (gles.glClear)(GL_COLOR_BUFFER_BIT);
} }

View file

@ -6,6 +6,7 @@ mod command;
mod descriptor; mod descriptor;
mod descriptor_buffer; mod descriptor_buffer;
mod device; mod device;
mod eotfs;
mod fence; mod fence;
mod format; mod format;
mod image; mod image;
@ -18,7 +19,6 @@ mod shaders;
mod shm_image; mod shm_image;
mod staging; mod staging;
mod transfer; mod transfer;
mod transfer_functions;
use { use {
crate::{ crate::{

View file

@ -0,0 +1,31 @@
use crate::cmm::cmm_eotf::Eotf;
pub const EOTF_LINEAR: u32 = 1;
pub const EOTF_ST2084_PQ: u32 = 2;
pub const EOTF_GAMMA24: u32 = 3;
pub const EOTF_GAMMA22: u32 = 4;
pub const EOTF_GAMMA28: u32 = 5;
pub const EOTF_ST240: u32 = 6;
pub const EOTF_LOG100: u32 = 8;
pub const EOTF_LOG316: u32 = 9;
pub const EOTF_ST428: u32 = 10;
pub trait EotfExt: Sized {
fn to_vulkan(self) -> u32;
}
impl EotfExt for Eotf {
fn to_vulkan(self) -> u32 {
match self {
Eotf::Linear => EOTF_LINEAR,
Eotf::St2084Pq => EOTF_ST2084_PQ,
Eotf::Bt1886 => EOTF_GAMMA24,
Eotf::Gamma22 => EOTF_GAMMA22,
Eotf::Gamma28 => EOTF_GAMMA28,
Eotf::St240 => EOTF_ST240,
Eotf::Log100 => EOTF_LOG100,
Eotf::Log316 => EOTF_LOG316,
Eotf::St428 => EOTF_ST428,
}
}
}

View file

@ -40,7 +40,7 @@ pub(super) struct PipelineCreateInfo {
pub(super) src_has_alpha: bool, pub(super) src_has_alpha: bool,
pub(super) has_alpha_mult: bool, pub(super) has_alpha_mult: bool,
pub(super) eotf: u32, pub(super) eotf: u32,
pub(super) oetf: u32, pub(super) inv_eotf: u32,
pub(super) descriptor_set_layouts: ArrayVec<Rc<VulkanDescriptorSetLayout>, 2>, pub(super) descriptor_set_layouts: ArrayVec<Rc<VulkanDescriptorSetLayout>, 2>,
pub(super) has_color_management_data: bool, pub(super) has_color_management_data: bool,
} }
@ -91,7 +91,7 @@ impl VulkanDevice {
frag_spec_entry(&(info.src_has_alpha as u32).to_ne_bytes()); frag_spec_entry(&(info.src_has_alpha as u32).to_ne_bytes());
frag_spec_entry(&(info.has_alpha_mult as u32).to_ne_bytes()); frag_spec_entry(&(info.has_alpha_mult as u32).to_ne_bytes());
frag_spec_entry(&info.eotf.to_ne_bytes()); frag_spec_entry(&info.eotf.to_ne_bytes());
frag_spec_entry(&info.oetf.to_ne_bytes()); frag_spec_entry(&info.inv_eotf.to_ne_bytes());
frag_spec_entry(&(info.has_color_management_data as u32).to_ne_bytes()); frag_spec_entry(&(info.has_color_management_data as u32).to_ne_bytes());
let frag_spec = SpecializationInfo::default() let frag_spec = SpecializationInfo::default()
.map_entries(&frag_spec_entries) .map_entries(&frag_spec_entries)

View file

@ -3,7 +3,7 @@ use {
async_engine::{AsyncEngine, SpawnedFuture}, async_engine::{AsyncEngine, SpawnedFuture},
cmm::{ cmm::{
cmm_description::{ColorDescription, LinearColorDescription, LinearColorDescriptionId}, cmm_description::{ColorDescription, LinearColorDescription, LinearColorDescriptionId},
cmm_transfer_function::TransferFunction, cmm_eotf::Eotf,
cmm_transform::ColorMatrix, cmm_transform::ColorMatrix,
}, },
cpu_worker::PendingJob, cpu_worker::PendingJob,
@ -19,6 +19,7 @@ use {
descriptor::VulkanDescriptorSetLayout, descriptor::VulkanDescriptorSetLayout,
descriptor_buffer::VulkanDescriptorBufferWriter, descriptor_buffer::VulkanDescriptorBufferWriter,
device::VulkanDevice, device::VulkanDevice,
eotfs::{EOTF_LINEAR, EotfExt},
fence::VulkanFence, fence::VulkanFence,
image::{QueueFamily, QueueState, QueueTransfer, VulkanImage, VulkanImageMemory}, image::{QueueFamily, QueueState, QueueTransfer, VulkanImage, VulkanImageMemory},
pipeline::{PipelineCreateInfo, VulkanPipeline}, pipeline::{PipelineCreateInfo, VulkanPipeline},
@ -30,7 +31,6 @@ use {
OUT_FRAG, OUT_VERT, OutPushConstants, TEX_FRAG, TEX_VERT, TexColorManagementData, OUT_FRAG, OUT_VERT, OutPushConstants, TEX_FRAG, TEX_VERT, TexColorManagementData,
TexPushConstants, TexVertex, VulkanShader, TexPushConstants, TexVertex, VulkanShader,
}, },
transfer_functions::{TF_LINEAR, TransferFunctionExt},
}, },
io_uring::IoUring, io_uring::IoUring,
rect::{Rect, Region}, rect::{Rect, Region},
@ -78,10 +78,8 @@ pub struct VulkanRenderer {
pub(super) formats: Rc<AHashMap<u32, GfxFormat>>, pub(super) formats: Rc<AHashMap<u32, GfxFormat>>,
pub(super) device: Rc<VulkanDevice>, pub(super) device: Rc<VulkanDevice>,
pub(super) fill_pipelines: CopyHashMap<vk::Format, FillPipelines>, pub(super) fill_pipelines: CopyHashMap<vk::Format, FillPipelines>,
pub(super) tex_pipelines: pub(super) tex_pipelines: StaticMap<Eotf, CopyHashMap<vk::Format, Rc<TexPipelines>>>,
StaticMap<TransferFunction, CopyHashMap<vk::Format, Rc<TexPipelines>>>, pub(super) out_pipelines: StaticMap<Eotf, CopyHashMap<OutPipelineKey, Rc<VulkanPipeline>>>,
pub(super) out_pipelines:
StaticMap<TransferFunction, CopyHashMap<OutPipelineKey, Rc<VulkanPipeline>>>,
pub(super) gfx_command_buffers: CachedCommandBuffers, pub(super) gfx_command_buffers: CachedCommandBuffers,
pub(super) transfer_command_buffers: Option<CachedCommandBuffers>, pub(super) transfer_command_buffers: Option<CachedCommandBuffers>,
pub(super) wait_semaphores: Stack<Rc<VulkanSemaphore>>, pub(super) wait_semaphores: Stack<Rc<VulkanSemaphore>>,
@ -247,20 +245,20 @@ type FillPipelines = Rc<StaticMap<TexSourceType, Rc<VulkanPipeline>>>;
struct TexPipelineKey { struct TexPipelineKey {
tex_copy_type: TexCopyType, tex_copy_type: TexCopyType,
tex_source_type: TexSourceType, tex_source_type: TexSourceType,
eotf: TransferFunction, eotf: Eotf,
has_color_management_data: bool, has_color_management_data: bool,
} }
pub(super) struct TexPipelines { pub(super) struct TexPipelines {
format: vk::Format, format: vk::Format,
oetf: TransferFunction, eotf: Eotf,
pipelines: CopyHashMap<TexPipelineKey, Rc<VulkanPipeline>>, pipelines: CopyHashMap<TexPipelineKey, Rc<VulkanPipeline>>,
} }
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub(super) struct OutPipelineKey { pub(super) struct OutPipelineKey {
format: vk::Format, format: vk::Format,
eotf: TransferFunction, eotf: Eotf,
} }
impl VulkanDevice { impl VulkanDevice {
@ -417,8 +415,8 @@ impl VulkanRenderer {
src_has_alpha, src_has_alpha,
has_alpha_mult: false, has_alpha_mult: false,
// all transformations are applied in the compositor // all transformations are applied in the compositor
eotf: TF_LINEAR, eotf: EOTF_LINEAR,
oetf: TF_LINEAR, inv_eotf: EOTF_LINEAR,
descriptor_set_layouts: Default::default(), descriptor_set_layouts: Default::default(),
has_color_management_data: false, has_color_management_data: false,
}; };
@ -437,13 +435,13 @@ impl VulkanRenderer {
format: vk::Format, format: vk::Format,
target_cd: &ColorDescription, target_cd: &ColorDescription,
) -> Rc<TexPipelines> { ) -> Rc<TexPipelines> {
let pipelines = &self.tex_pipelines[target_cd.transfer_function]; let pipelines = &self.tex_pipelines[target_cd.eotf];
match pipelines.get(&format) { match pipelines.get(&format) {
Some(pl) => pl, Some(pl) => pl,
_ => { _ => {
let pl = Rc::new(TexPipelines { let pl = Rc::new(TexPipelines {
format, format,
oetf: target_cd.transfer_function, eotf: target_cd.eotf,
pipelines: Default::default(), pipelines: Default::default(),
}); });
pipelines.set(format, pl.clone()); pipelines.set(format, pl.clone());
@ -463,7 +461,7 @@ impl VulkanRenderer {
let key = TexPipelineKey { let key = TexPipelineKey {
tex_copy_type, tex_copy_type,
tex_source_type, tex_source_type,
eotf: tex_cd.transfer_function, eotf: tex_cd.eotf,
has_color_management_data, has_color_management_data,
}; };
if let Some(pl) = pipelines.pipelines.get(&key) { if let Some(pl) = pipelines.pipelines.get(&key) {
@ -490,7 +488,7 @@ impl VulkanRenderer {
src_has_alpha, src_has_alpha,
has_alpha_mult, has_alpha_mult,
eotf: key.eotf.to_vulkan(), eotf: key.eotf.to_vulkan(),
oetf: pipelines.oetf.to_vulkan(), inv_eotf: pipelines.eotf.to_vulkan(),
descriptor_set_layouts: self.tex_descriptor_set_layouts.clone(), descriptor_set_layouts: self.tex_descriptor_set_layouts.clone(),
has_color_management_data, has_color_management_data,
}; };
@ -507,9 +505,9 @@ impl VulkanRenderer {
) -> Result<Rc<VulkanPipeline>, VulkanError> { ) -> Result<Rc<VulkanPipeline>, VulkanError> {
let key = OutPipelineKey { let key = OutPipelineKey {
format, format,
eotf: bb_cd.transfer_function, eotf: bb_cd.eotf,
}; };
let pipelines = &self.out_pipelines[fb_cd.transfer_function]; let pipelines = &self.out_pipelines[fb_cd.eotf];
if let Some(pl) = pipelines.get(&key) { if let Some(pl) = pipelines.get(&key) {
return Ok(pl); return Ok(pl);
} }
@ -525,7 +523,7 @@ impl VulkanRenderer {
src_has_alpha: true, src_has_alpha: true,
has_alpha_mult: false, has_alpha_mult: false,
eotf: key.eotf.to_vulkan(), eotf: key.eotf.to_vulkan(),
oetf: fb_cd.transfer_function.to_vulkan(), inv_eotf: fb_cd.eotf.to_vulkan(),
descriptor_set_layouts, descriptor_set_layouts,
has_color_management_data: false, has_color_management_data: false,
})?; })?;
@ -725,7 +723,7 @@ impl VulkanRenderer {
RenderPass::BlendBuffer => blend_cd, RenderPass::BlendBuffer => blend_cd,
RenderPass::FrameBuffer => fb_cd, RenderPass::FrameBuffer => fb_cd,
}; };
let tf = target_cd.transfer_function; let tf = target_cd.eotf;
let color = memory let color = memory
.color_transforms .color_transforms
.apply_to_color(&fr.cd, target_cd, fr.color); .apply_to_color(&fr.cd, target_cd, fr.color);
@ -1047,7 +1045,7 @@ impl VulkanRenderer {
.apply_to_color(clear_cd, target_cd, *clear); .apply_to_color(clear_cd, target_cd, *clear);
let clear_value = ClearValue { let clear_value = ClearValue {
color: ClearColorValue { color: ClearColorValue {
float32: color.to_array(target_cd.transfer_function), float32: color.to_array(target_cd.eotf),
}, },
}; };
let use_load_clear = clear_rects.len() == 1 && { let use_load_clear = clear_rects.len() == 1 && {

View file

@ -1,5 +1,5 @@
#ifndef TRANSFER_FUNCTIONS_GLSL #ifndef EOTFS_GLSL
#define TRANSFER_FUNCTIONS_GLSL #define EOTFS_GLSL
#include "frag_spec_const.glsl" #include "frag_spec_const.glsl"
@ -21,7 +21,7 @@ vec3 eotf_st2084_pq(vec3 c) {
return pow(num / den, vec3(1.0 / 0.1593017578125)); return pow(num / den, vec3(1.0 / 0.1593017578125));
} }
vec3 oetf_st2084_pq(vec3 c) { vec3 inv_eotf_st2084_pq(vec3 c) {
c = clamp(c, 0.0, 1.0); c = clamp(c, 0.0, 1.0);
vec3 num = vec3(0.8359375) + vec3(18.8515625) * pow(c, vec3(0.1593017578125)); vec3 num = vec3(0.8359375) + vec3(18.8515625) * pow(c, vec3(0.1593017578125));
vec3 den = vec3(1.0) + vec3(18.6875) * pow(c, vec3(0.1593017578125)); vec3 den = vec3(1.0) + vec3(18.6875) * pow(c, vec3(0.1593017578125));
@ -36,7 +36,7 @@ vec3 eotf_st240(vec3 c) {
); );
} }
vec3 oetf_st240(vec3 c) { vec3 inv_eotf_st240(vec3 c) {
return mix( return mix(
vec3(4.0) * c, vec3(4.0) * c,
vec3(1.1115) * pow(c, vec3(0.45)) - vec3(0.1115), vec3(1.1115) * pow(c, vec3(0.45)) - vec3(0.1115),
@ -48,7 +48,7 @@ vec3 eotf_log100(vec3 c) {
return pow(vec3(10), vec3(2.0) * (c - vec3(1.0))); return pow(vec3(10), vec3(2.0) * (c - vec3(1.0)));
} }
vec3 oetf_log100(vec3 c) { vec3 inv_eotf_log100(vec3 c) {
c = clamp(c, 0.0, 1.0); c = clamp(c, 0.0, 1.0);
return mix( return mix(
vec3(0.0), vec3(0.0),
@ -61,7 +61,7 @@ vec3 eotf_log316(vec3 c) {
return pow(vec3(10), vec3(2.5) * (c - vec3(1.0))); return pow(vec3(10), vec3(2.5) * (c - vec3(1.0)));
} }
vec3 oetf_log316(vec3 c) { vec3 inv_eotf_log316(vec3 c) {
c = clamp(c, 0.0, 1.0); c = clamp(c, 0.0, 1.0);
return mix( return mix(
vec3(0.0), vec3(0.0),
@ -75,7 +75,7 @@ vec3 eotf_st428(vec3 c) {
return pow(c, vec3(2.6)) * vec3(52.37 / 48.0); return pow(c, vec3(2.6)) * vec3(52.37 / 48.0);
} }
vec3 oetf_st428(vec3 c) { vec3 inv_eotf_st428(vec3 c) {
c = max(c, 0.0); c = max(c, 0.0);
return pow(vec3(48.0) * c / vec3(52.37), vec3(1.0 / 2.6)); return pow(vec3(48.0) * c / vec3(52.37), vec3(1.0 / 2.6));
} }
@ -95,17 +95,17 @@ vec3 apply_eotf(vec3 c) {
} }
} }
vec3 apply_oetf(vec3 c) { vec3 apply_inv_eotf(vec3 c) {
switch (oetf) { switch (inv_eotf) {
case TF_LINEAR: return c; case TF_LINEAR: return c;
case TF_ST2084_PQ: return oetf_st2084_pq(c); case TF_ST2084_PQ: return inv_eotf_st2084_pq(c);
case TF_GAMMA24: return sign(c) * pow(abs(c), vec3(1.0 / 2.4)); case TF_GAMMA24: return sign(c) * pow(abs(c), vec3(1.0 / 2.4));
case TF_GAMMA22: return sign(c) * pow(abs(c), vec3(1.0 / 2.2)); case TF_GAMMA22: return sign(c) * pow(abs(c), vec3(1.0 / 2.2));
case TF_GAMMA28: return sign(c) * pow(abs(c), vec3(1.0 / 2.8)); case TF_GAMMA28: return sign(c) * pow(abs(c), vec3(1.0 / 2.8));
case TF_ST240: return oetf_st240(c); case TF_ST240: return inv_eotf_st240(c);
case TF_LOG100: return oetf_log100(c); case TF_LOG100: return inv_eotf_log100(c);
case TF_LOG316: return oetf_log316(c); case TF_LOG316: return inv_eotf_log316(c);
case TF_ST428: return oetf_st428(c); case TF_ST428: return inv_eotf_st428(c);
default: return c; default: return c;
} }
} }

View file

@ -4,7 +4,7 @@
layout(constant_id = 0) const bool src_has_alpha = false; layout(constant_id = 0) const bool src_has_alpha = false;
layout(constant_id = 1) const bool has_alpha_multiplier = false; layout(constant_id = 1) const bool has_alpha_multiplier = false;
layout(constant_id = 2) const uint eotf = 0; layout(constant_id = 2) const uint eotf = 0;
layout(constant_id = 3) const uint oetf = 0; layout(constant_id = 3) const uint inv_eotf = 0;
layout(constant_id = 4) const bool has_matrix = false; layout(constant_id = 4) const bool has_matrix = false;
#endif #endif

View file

@ -2,7 +2,7 @@
#extension GL_EXT_samplerless_texture_functions : require #extension GL_EXT_samplerless_texture_functions : require
#include "frag_spec_const.glsl" #include "frag_spec_const.glsl"
#include "transfer_functions.glsl" #include "eotfs.glsl"
#include "out.common.glsl" #include "out.common.glsl"
layout(set = 0, binding = 0) uniform texture2D in_color; layout(set = 0, binding = 0) uniform texture2D in_color;
@ -10,10 +10,10 @@ layout(location = 0) out vec4 out_color;
void main() { void main() {
vec4 c = texelFetch(in_color, ivec2(gl_FragCoord.xy), 0); vec4 c = texelFetch(in_color, ivec2(gl_FragCoord.xy), 0);
if (eotf != oetf) { if (eotf != inv_eotf) {
c.rgb /= mix(c.a, 1.0, c.a == 0.0); c.rgb /= mix(c.a, 1.0, c.a == 0.0);
c.rgb = apply_eotf(c.rgb); c.rgb = apply_eotf(c.rgb);
c.rgb = apply_oetf(c.rgb); c.rgb = apply_inv_eotf(c.rgb);
c.rgb *= c.a; c.rgb *= c.a;
} }
out_color = c; out_color = c;

View file

@ -3,7 +3,7 @@
#extension GL_EXT_scalar_block_layout : require #extension GL_EXT_scalar_block_layout : require
#include "frag_spec_const.glsl" #include "frag_spec_const.glsl"
#include "transfer_functions.glsl" #include "eotfs.glsl"
#include "tex.common.glsl" #include "tex.common.glsl"
layout(set = 0, binding = 0) uniform sampler sam; layout(set = 0, binding = 0) uniform sampler sam;
@ -16,7 +16,7 @@ layout(location = 0) out vec4 out_color;
void main() { void main() {
vec4 c = textureLod(sampler2D(tex, sam), tex_pos, 0); vec4 c = textureLod(sampler2D(tex, sam), tex_pos, 0);
if (eotf != oetf || has_matrix) { if (eotf != inv_eotf || has_matrix) {
vec3 rgb = c.rgb; vec3 rgb = c.rgb;
if (src_has_alpha) { if (src_has_alpha) {
rgb /= mix(c.a, 1.0, c.a == 0.0); rgb /= mix(c.a, 1.0, c.a == 0.0);
@ -25,7 +25,7 @@ void main() {
if (has_matrix) { if (has_matrix) {
rgb = (cm_data.matrix * vec4(rgb, 1.0)).rgb; rgb = (cm_data.matrix * vec4(rgb, 1.0)).rgb;
} }
rgb = apply_oetf(rgb); rgb = apply_inv_eotf(rgb);
if (src_has_alpha) { if (src_has_alpha) {
rgb *= c.a; rgb *= c.a;
} }

View file

@ -1,31 +0,0 @@
use crate::cmm::cmm_transfer_function::TransferFunction;
pub const TF_LINEAR: u32 = 1;
pub const TF_ST2084_PQ: u32 = 2;
pub const TF_GAMMA24: u32 = 3;
pub const TF_GAMMA22: u32 = 4;
pub const TF_GAMMA28: u32 = 5;
pub const TF_ST240: u32 = 6;
pub const TF_LOG100: u32 = 8;
pub const TF_LOG316: u32 = 9;
pub const TF_ST428: u32 = 10;
pub trait TransferFunctionExt: Sized {
fn to_vulkan(self) -> u32;
}
impl TransferFunctionExt for TransferFunction {
fn to_vulkan(self) -> u32 {
match self {
TransferFunction::Linear => TF_LINEAR,
TransferFunction::St2084Pq => TF_ST2084_PQ,
TransferFunction::Bt1886 => TF_GAMMA24,
TransferFunction::Gamma22 => TF_GAMMA22,
TransferFunction::Gamma28 => TF_GAMMA28,
TransferFunction::St240 => TF_ST240,
TransferFunction::Log100 => TF_LOG100,
TransferFunction::Log316 => TF_LOG316,
TransferFunction::St428 => TF_ST428,
}
}
}

View file

@ -2,7 +2,7 @@
use { use {
crate::{ crate::{
cmm::cmm_transfer_function::TransferFunction, cmm::cmm_eotf::Eotf,
format::ARGB8888, format::ARGB8888,
gfx_api::{GfxContext, GfxError, GfxTexture}, gfx_api::{GfxContext, GfxError, GfxTexture},
scale::Scale, scale::Scale,
@ -221,7 +221,7 @@ impl PathBuilderExt for PathBuilder {
impl From<crate::theme::Color> for Color { impl From<crate::theme::Color> for Color {
fn from(v: crate::theme::Color) -> Self { fn from(v: crate::theme::Color) -> Self {
let [r, g, b, a] = v.to_array(TransferFunction::Gamma22); let [r, g, b, a] = v.to_array(Eotf::Gamma22);
let mut c = Self::TRANSPARENT; let mut c = Self::TRANSPARENT;
c.set_red(r / a); c.set_red(r / a);
c.set_green(g / a); c.set_green(g / a);
@ -242,7 +242,7 @@ fn calculate_accents(srgb: crate::theme::Color) -> [Color; 2] {
} }
fn srgb_to_lab(srgb: crate::theme::Color) -> [f32; 4] { fn srgb_to_lab(srgb: crate::theme::Color) -> [f32; 4] {
let [mut r, mut g, mut b, alpha] = srgb.to_array(TransferFunction::Gamma22); let [mut r, mut g, mut b, alpha] = srgb.to_array(Eotf::Gamma22);
if alpha < 1.0 { if alpha < 1.0 {
r /= alpha; r /= alpha;
g /= alpha; g /= alpha;

View file

@ -2,9 +2,9 @@ use {
crate::{ crate::{
client::{Client, ClientError}, client::{Client, ClientError},
cmm::{ cmm::{
cmm_eotf::Eotf,
cmm_luminance::{Luminance, TargetLuminance}, cmm_luminance::{Luminance, TargetLuminance},
cmm_primaries::{NamedPrimaries, Primaries}, cmm_primaries::{NamedPrimaries, Primaries},
cmm_transfer_function::TransferFunction,
}, },
ifs::color_management::{ ifs::color_management::{
MIN_LUM_MUL_INV, PRIMARIES_MUL_INV, MIN_LUM_MUL_INV, PRIMARIES_MUL_INV,
@ -40,7 +40,7 @@ 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 tf: Cell<Option<Eotf>>,
pub primaries: Cell<Option<(Option<NamedPrimaries>, Primaries)>>, pub primaries: Cell<Option<(Option<NamedPrimaries>, Primaries)>>,
pub luminance: Cell<Option<Luminance>>, pub luminance: Cell<Option<Luminance>>,
pub mastering_primaries: Cell<Option<Primaries>>, pub mastering_primaries: Cell<Option<Primaries>>,
@ -53,19 +53,19 @@ impl WpImageDescriptionCreatorParamsV1RequestHandler for WpImageDescriptionCreat
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 { let Some(eotf) = self.tf.get() else {
return Err(WpImageDescriptionCreatorParamsV1Error::TfNotSet); return Err(WpImageDescriptionCreatorParamsV1Error::TfNotSet);
}; };
let Some((named_primaries, primaries)) = self.primaries.get() else { let Some((named_primaries, primaries)) = self.primaries.get() else {
return Err(WpImageDescriptionCreatorParamsV1Error::PrimariesNotSet); return Err(WpImageDescriptionCreatorParamsV1Error::PrimariesNotSet);
}; };
let default_luminance = match transfer_function { let default_luminance = match eotf {
TransferFunction::Bt1886 => Luminance::BT1886, Eotf::Bt1886 => Luminance::BT1886,
TransferFunction::St2084Pq => Luminance::ST2084_PQ, Eotf::St2084Pq => Luminance::ST2084_PQ,
_ => Luminance::SRGB, _ => Luminance::SRGB,
}; };
let mut luminance = self.luminance.get().unwrap_or(default_luminance); let mut luminance = self.luminance.get().unwrap_or(default_luminance);
if transfer_function == TransferFunction::St2084Pq { if eotf == Eotf::St2084Pq {
luminance.max.0 = luminance.min.0 + 10_000.0; luminance.max.0 = luminance.min.0 + 10_000.0;
} }
if luminance.max.0 <= luminance.min.0 || luminance.white.0 <= luminance.min.0 { if luminance.max.0 <= luminance.min.0 || luminance.white.0 <= luminance.min.0 {
@ -80,7 +80,7 @@ impl WpImageDescriptionCreatorParamsV1RequestHandler for WpImageDescriptionCreat
named_primaries, named_primaries,
primaries, primaries,
luminance, luminance,
transfer_function, eotf,
target_primaries, target_primaries,
target_luminance, target_luminance,
self.max_cll.get(), self.max_cll.get(),
@ -102,17 +102,17 @@ impl WpImageDescriptionCreatorParamsV1RequestHandler for WpImageDescriptionCreat
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> {
let tf = match req.tf { let tf = match req.tf {
TRANSFER_FUNCTION_BT1886 => TransferFunction::Bt1886, TRANSFER_FUNCTION_BT1886 => Eotf::Bt1886,
TRANSFER_FUNCTION_GAMMA22 => TransferFunction::Gamma22, TRANSFER_FUNCTION_GAMMA22 => Eotf::Gamma22,
TRANSFER_FUNCTION_GAMMA28 => TransferFunction::Gamma28, TRANSFER_FUNCTION_GAMMA28 => Eotf::Gamma28,
TRANSFER_FUNCTION_ST240 => TransferFunction::St240, TRANSFER_FUNCTION_ST240 => Eotf::St240,
TRANSFER_FUNCTION_EXT_LINEAR => TransferFunction::Linear, TRANSFER_FUNCTION_EXT_LINEAR => Eotf::Linear,
TRANSFER_FUNCTION_LOG_100 => TransferFunction::Log100, TRANSFER_FUNCTION_LOG_100 => Eotf::Log100,
TRANSFER_FUNCTION_LOG_316 => TransferFunction::Log316, TRANSFER_FUNCTION_LOG_316 => Eotf::Log316,
TRANSFER_FUNCTION_SRGB => TransferFunction::Gamma22, TRANSFER_FUNCTION_SRGB => Eotf::Gamma22,
TRANSFER_FUNCTION_EXT_SRGB => TransferFunction::Gamma22, TRANSFER_FUNCTION_EXT_SRGB => Eotf::Gamma22,
TRANSFER_FUNCTION_ST2084_PQ => TransferFunction::St2084Pq, TRANSFER_FUNCTION_ST2084_PQ => Eotf::St2084Pq,
TRANSFER_FUNCTION_ST428 => TransferFunction::St428, TRANSFER_FUNCTION_ST428 => Eotf::St428,
_ => { _ => {
return Err(WpImageDescriptionCreatorParamsV1Error::UnsupportedTf( return Err(WpImageDescriptionCreatorParamsV1Error::UnsupportedTf(
req.tf, req.tf,
@ -261,9 +261,9 @@ pub enum WpImageDescriptionCreatorParamsV1Error {
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 EOTF", .0)]
UnsupportedTf(u32), UnsupportedTf(u32),
#[error("The transfer function has already been set")] #[error("The EOTF has already been set")]
TfAlreadySet, TfAlreadySet,
#[error("The primaries have already been set")] #[error("The primaries have already been set")]
PrimariesAlreadySet, PrimariesAlreadySet,
@ -271,7 +271,7 @@ pub enum WpImageDescriptionCreatorParamsV1Error {
LuminancesAlreadySet, LuminancesAlreadySet,
#[error("The minimum luminance is too low")] #[error("The minimum luminance is too low")]
MinLuminanceTooLow, MinLuminanceTooLow,
#[error("The transfer function was not set")] #[error("The EOTF was not set")]
TfNotSet, TfNotSet,
#[error("The primaries were not set")] #[error("The primaries were not set")]
PrimariesNotSet, PrimariesNotSet,

View file

@ -1,10 +1,7 @@
use { use {
crate::{ crate::{
client::Client, client::Client,
cmm::{ cmm::{cmm_description::ColorDescription, cmm_eotf::Eotf, cmm_primaries::NamedPrimaries},
cmm_description::ColorDescription, cmm_primaries::NamedPrimaries,
cmm_transfer_function::TransferFunction,
},
ifs::color_management::{ ifs::color_management::{
MIN_LUM_MUL, PRIMARIES_ADOBE_RGB, PRIMARIES_BT2020, PRIMARIES_CIE1931_XYZ, MIN_LUM_MUL, PRIMARIES_ADOBE_RGB, PRIMARIES_BT2020, PRIMARIES_CIE1931_XYZ,
PRIMARIES_DCI_P3, PRIMARIES_DISPLAY_P3, PRIMARIES_GENERIC_FILM, PRIMARIES_MUL, PRIMARIES_DCI_P3, PRIMARIES_DISPLAY_P3, PRIMARIES_GENERIC_FILM, PRIMARIES_MUL,
@ -31,16 +28,16 @@ pub struct WpImageDescriptionInfoV1 {
impl WpImageDescriptionInfoV1 { impl WpImageDescriptionInfoV1 {
pub fn send_description(&self, d: &ColorDescription) { pub fn send_description(&self, d: &ColorDescription) {
let tf = match d.transfer_function { let tf = match d.eotf {
TransferFunction::Linear => TRANSFER_FUNCTION_EXT_LINEAR, Eotf::Linear => TRANSFER_FUNCTION_EXT_LINEAR,
TransferFunction::St2084Pq => TRANSFER_FUNCTION_ST2084_PQ, Eotf::St2084Pq => TRANSFER_FUNCTION_ST2084_PQ,
TransferFunction::Bt1886 => TRANSFER_FUNCTION_BT1886, Eotf::Bt1886 => TRANSFER_FUNCTION_BT1886,
TransferFunction::Gamma22 => TRANSFER_FUNCTION_GAMMA22, Eotf::Gamma22 => TRANSFER_FUNCTION_GAMMA22,
TransferFunction::Gamma28 => TRANSFER_FUNCTION_GAMMA28, Eotf::Gamma28 => TRANSFER_FUNCTION_GAMMA28,
TransferFunction::St240 => TRANSFER_FUNCTION_ST240, Eotf::St240 => TRANSFER_FUNCTION_ST240,
TransferFunction::Log100 => TRANSFER_FUNCTION_LOG_100, Eotf::Log100 => TRANSFER_FUNCTION_LOG_100,
TransferFunction::Log316 => TRANSFER_FUNCTION_LOG_316, Eotf::Log316 => TRANSFER_FUNCTION_LOG_316,
TransferFunction::St428 => TRANSFER_FUNCTION_ST428, Eotf::St428 => TRANSFER_FUNCTION_ST428,
}; };
self.send_primaries(&d.linear.primaries); self.send_primaries(&d.linear.primaries);
if let Some(n) = d.named_primaries { if let Some(n) = d.named_primaries {

View file

@ -217,7 +217,7 @@ impl ExtImageCopyCaptureFrameV1 {
aq, aq,
re, re,
jay_config::video::Transform::None, jay_config::video::Transform::None,
self.client.state.color_manager.srgb_srgb(), self.client.state.color_manager.srgb_gamma22(),
on.global.pos.get(), on.global.pos.get(),
render_hardware_cursors, render_hardware_cursors,
x_off, x_off,
@ -235,7 +235,7 @@ impl ExtImageCopyCaptureFrameV1 {
fb.render_node( fb.render_node(
aq, aq,
re, re,
self.client.state.color_manager.srgb_srgb(), self.client.state.color_manager.srgb_gamma22(),
node, node,
&self.client.state, &self.client.state,
Some(node.node_absolute_position()), Some(node.node_absolute_position()),

View file

@ -1,7 +1,7 @@
use { use {
crate::{ crate::{
backend::{ backend::{
BackendColorSpace, BackendTransferFunction, ConnectorId, Mode, MonitorInfo, BackendColorSpace, BackendEotfs, ConnectorId, Mode, MonitorInfo,
transaction::BackendConnectorTransactionError, transaction::BackendConnectorTransactionError,
}, },
client::ClientId, client::ClientId,
@ -90,7 +90,7 @@ pub struct HeadState {
pub tearing_mode: TearingMode, pub tearing_mode: TearingMode,
pub format: &'static Format, pub format: &'static Format,
pub color_space: BackendColorSpace, pub color_space: BackendColorSpace,
pub transfer_function: BackendTransferFunction, pub eotf: BackendEotfs,
pub supported_formats: RcEq<Vec<&'static Format>>, pub supported_formats: RcEq<Vec<&'static Format>>,
pub brightness: Option<f64>, pub brightness: Option<f64>,
} }
@ -132,7 +132,7 @@ enum HeadOp {
SetVrrMode(VrrMode), SetVrrMode(VrrMode),
SetTearingMode(TearingMode), SetTearingMode(TearingMode),
SetFormat(&'static Format), SetFormat(&'static Format),
SetTransferFunction(BackendTransferFunction), SetEotf(BackendEotfs),
SetColorSpace(BackendColorSpace), SetColorSpace(BackendColorSpace),
SetBrightness(Option<f64>), SetBrightness(Option<f64>),
} }
@ -491,14 +491,10 @@ impl HeadManagers {
} }
} }
pub fn handle_colors_change( pub fn handle_colors_change(&self, color_space: BackendColorSpace, eotf: BackendEotfs) {
&self,
color_space: BackendColorSpace,
transfer_function: BackendTransferFunction,
) {
let state = &mut *self.state.borrow_mut(); let state = &mut *self.state.borrow_mut();
state.color_space = color_space; state.color_space = color_space;
state.transfer_function = transfer_function; state.eotf = eotf;
for head in self.managers.lock().values() { for head in self.managers.lock().values() {
skip_in_transaction!(head); skip_in_transaction!(head);
if let Some(ext) = &head.ext.drm_color_space_info_v1 { if let Some(ext) = &head.ext.drm_color_space_info_v1 {

View file

@ -1,6 +1,6 @@
use { use {
crate::{ crate::{
backend::BackendTransferFunction, backend::BackendEotfs,
cmm::cmm_luminance::Luminance, cmm::cmm_luminance::Luminance,
ifs::head_management::HeadState, ifs::head_management::HeadState,
wire::{ wire::{
@ -27,7 +27,7 @@ impl HeadName {
} }
fn after_transaction(&self, shared: &HeadState, tran: &HeadState) { fn after_transaction(&self, shared: &HeadState, tran: &HeadState) {
if shared.transfer_function != tran.transfer_function { if shared.eotf != tran.eotf {
self.send_implied_default_brightness(shared); self.send_implied_default_brightness(shared);
} }
if shared.brightness != tran.brightness { if shared.brightness != tran.brightness {
@ -36,14 +36,14 @@ impl HeadName {
} }
pub(in super::super) fn send_implied_default_brightness(&self, shared: &HeadState) { pub(in super::super) fn send_implied_default_brightness(&self, shared: &HeadState) {
let lux = match shared.transfer_function { let lux = match shared.eotf {
BackendTransferFunction::Default => shared BackendEotfs::Default => shared
.monitor_info .monitor_info
.as_ref() .as_ref()
.and_then(|m| m.luminance.as_ref()) .and_then(|m| m.luminance.as_ref())
.map(|l| l.max) .map(|l| l.max)
.unwrap_or(Luminance::SRGB.white.0), .unwrap_or(Luminance::SRGB.white.0),
BackendTransferFunction::Pq => Luminance::ST2084_PQ.white.0, BackendEotfs::Pq => Luminance::ST2084_PQ.white.0,
}; };
self.client.event(ImpliedDefaultBrightness { self.client.event(ImpliedDefaultBrightness {
self_id: self.id, self_id: self.id,

View file

@ -32,9 +32,7 @@ impl HeadName {
} }
fn after_transaction(&self, shared: &HeadState, tran: &HeadState) { fn after_transaction(&self, shared: &HeadState, tran: &HeadState) {
if (shared.color_space, shared.transfer_function) if (shared.color_space, shared.eotf) != (tran.color_space, tran.eotf) {
!= (tran.color_space, tran.transfer_function)
{
self.send_state(shared); self.send_state(shared);
} }
} }
@ -42,7 +40,7 @@ impl HeadName {
pub(in super::super) fn send_state(&self, state: &HeadState) { pub(in super::super) fn send_state(&self, state: &HeadState) {
self.client.event(HdmiEotf { self.client.event(HdmiEotf {
self_id: self.id, self_id: self.id,
eotf: state.transfer_function.to_drm() as u32, eotf: state.eotf.to_drm() as u32,
}); });
self.client.event(Colorimetry { self.client.event(Colorimetry {
self_id: self.id, self_id: self.id,

View file

@ -1,6 +1,6 @@
use { use {
crate::{ crate::{
backend::{BackendColorSpace, BackendTransferFunction}, backend::{BackendColorSpace, BackendEotfs},
ifs::head_management::{HeadOp, HeadState}, ifs::head_management::{HeadOp, HeadState},
video::drm::{ video::drm::{
DRM_MODE_COLORIMETRY_BT2020_RGB, DRM_MODE_COLORIMETRY_DEFAULT, HDMI_EOTF_SMPTE_ST2084, DRM_MODE_COLORIMETRY_BT2020_RGB, DRM_MODE_COLORIMETRY_DEFAULT, HDMI_EOTF_SMPTE_ST2084,
@ -41,7 +41,7 @@ impl HeadName {
return; return;
}; };
self.send_supported_eotf(HDMI_EOTF_TRADITIONAL_GAMMA_SDR); self.send_supported_eotf(HDMI_EOTF_TRADITIONAL_GAMMA_SDR);
for tf in &mi.transfer_functions { for tf in &mi.eotfs {
self.send_supported_eotf(tf.to_drm()); self.send_supported_eotf(tf.to_drm());
} }
self.send_supported_colorimetry(DRM_MODE_COLORIMETRY_DEFAULT); self.send_supported_colorimetry(DRM_MODE_COLORIMETRY_DEFAULT);
@ -80,20 +80,20 @@ impl JayHeadExtDrmColorSpaceSetterV1RequestHandler for HeadName {
const DEFAULT: u32 = HDMI_EOTF_TRADITIONAL_GAMMA_SDR as u32; const DEFAULT: u32 = HDMI_EOTF_TRADITIONAL_GAMMA_SDR as u32;
const PQ: u32 = HDMI_EOTF_SMPTE_ST2084 as u32; const PQ: u32 = HDMI_EOTF_SMPTE_ST2084 as u32;
let eotf = match req.eotf { let eotf = match req.eotf {
DEFAULT => BackendTransferFunction::Default, DEFAULT => BackendEotfs::Default,
PQ => BackendTransferFunction::Pq, PQ => BackendEotfs::Pq,
_ => return Err(ErrorName::UnknownEotf(req.eotf)), _ => return Err(ErrorName::UnknownEotf(req.eotf)),
}; };
if eotf != BackendTransferFunction::Default { if eotf != BackendEotfs::Default {
let state = &*self.common.transaction_state.borrow(); let state = &*self.common.transaction_state.borrow();
let Some(mi) = &state.monitor_info else { let Some(mi) = &state.monitor_info else {
return Err(ErrorName::UnsupportedEotf(req.eotf)); return Err(ErrorName::UnsupportedEotf(req.eotf));
}; };
if mi.transfer_functions.not_contains(&eotf) { if mi.eotfs.not_contains(&eotf) {
return Err(ErrorName::UnsupportedEotf(req.eotf)); return Err(ErrorName::UnsupportedEotf(req.eotf));
} }
} }
self.common.push_op(HeadOp::SetTransferFunction(eotf))?; self.common.push_op(HeadOp::SetEotf(eotf))?;
Ok(()) Ok(())
} }

View file

@ -265,7 +265,7 @@ impl JayHeadManagerSessionV1 {
new.non_desktop_override = desired.override_non_desktop; new.non_desktop_override = desired.override_non_desktop;
new.format = desired.format; new.format = desired.format;
new.color_space = desired.color_space; new.color_space = desired.color_space;
new.transfer_function = desired.transfer_function; new.eotf = desired.eotf;
if old == new { if old == new {
continue; continue;
} }
@ -447,8 +447,8 @@ impl JayHeadManagerSessionV1RequestHandler for JayHeadManagerSessionV1 {
state.format = f; state.format = f;
to_send |= FORMAT_INFO; to_send |= FORMAT_INFO;
} }
HeadOp::SetTransferFunction(e) => { HeadOp::SetEotf(e) => {
state.transfer_function = e; state.eotf = e;
to_send |= DRM_COLOR_SPACE_INFO; to_send |= DRM_COLOR_SPACE_INFO;
to_send |= BRIGHTNESS_INFO; to_send |= BRIGHTNESS_INFO;
} }

View file

@ -1,7 +1,7 @@
use { use {
crate::{ crate::{
client::{CAP_JAY_COMPOSITOR, Client, ClientCaps, ClientError}, client::{CAP_JAY_COMPOSITOR, Client, ClientCaps, ClientError},
cmm::cmm_transfer_function::TransferFunction, cmm::cmm_eotf::Eotf,
globals::{Global, GlobalName}, globals::{Global, GlobalName},
leaks::Tracker, leaks::Tracker,
object::{Object, Version}, object::{Object, Version},
@ -97,7 +97,7 @@ impl JayDamageTrackingRequestHandler for JayDamageTracking {
req: SetVisualizerColor, req: SetVisualizerColor,
_slf: &Rc<Self>, _slf: &Rc<Self>,
) -> Result<(), Self::Error> { ) -> Result<(), Self::Error> {
let color = Color::new(TransferFunction::Gamma22, req.r, req.g, req.b) * req.a; let color = Color::new(Eotf::Gamma22, req.r, req.g, req.b) * req.a;
self.client.state.damage_visualizer.set_color(color); self.client.state.damage_visualizer.set_color(color);
Ok(()) Ok(())
} }

View file

@ -1,6 +1,6 @@
use { use {
crate::{ crate::{
backend::{self, BackendColorSpace, BackendTransferFunction}, backend::{self, BackendColorSpace, BackendEotfs},
client::{Client, ClientError}, client::{Client, ClientError},
compositor::MAX_EXTENTS, compositor::MAX_EXTENTS,
format::named_formats, format::named_formats,
@ -170,15 +170,15 @@ impl JayRandr {
}); });
} }
if self.version >= COLORIMETRY_SINCE { if self.version >= COLORIMETRY_SINCE {
for tf in &node.global.transfer_functions { for eotf in &node.global.eotfs {
self.client.event(SupportedTransferFunction { self.client.event(SupportedEotf {
self_id: self.id, self_id: self.id,
transfer_function: tf.name(), eotf: eotf.name(),
}); });
} }
self.client.event(CurrentTransferFunction { self.client.event(CurrentEotf {
self_id: self.id, self_id: self.id,
transfer_function: node.global.btf.get().name(), eotf: node.global.btf.get().name(),
}); });
for cs in &node.global.color_spaces { for cs in &node.global.color_spaces {
self.client.event(SupportedColorSpace { self.client.event(SupportedColorSpace {
@ -484,21 +484,19 @@ impl JayRandrRequestHandler for JayRandr {
)); ));
}; };
let tf = 'tf: { let tf = 'tf: {
for tf in BackendTransferFunction::variants() { for tf in BackendEotfs::variants() {
if tf.name() == req.transfer_function { if tf.name() == req.eotf {
break 'tf tf; break 'tf tf;
} }
} }
return Err(JayRandrError::UnknownTransferFunction( return Err(JayRandrError::UnknownEotf(req.eotf.to_string()));
req.transfer_function.to_string(),
));
}; };
let Some(c) = self.get_connector(req.output) else { let Some(c) = self.get_connector(req.output) else {
return Ok(()); return Ok(());
}; };
let res = c.modify_state(&self.state, |s| { let res = c.modify_state(&self.state, |s| {
s.color_space = cs; s.color_space = cs;
s.transfer_function = tf; s.eotf = tf;
}); });
if let Err(e) = res { if let Err(e) = res {
self.send_error(&format!( self.send_error(&format!(
@ -551,7 +549,7 @@ pub enum JayRandrError {
UnknownFormat(String), UnknownFormat(String),
#[error("Unknown color space {0}")] #[error("Unknown color space {0}")]
UnknownColorSpace(String), UnknownColorSpace(String),
#[error("Unknown transfer function {0}")] #[error("Unknown EOTF {0}")]
UnknownTransferFunction(String), UnknownEotf(String),
} }
efrom!(JayRandrError, ClientError); efrom!(JayRandrError, ClientError);

View file

@ -194,7 +194,7 @@ impl JayScreencast {
let res = buffer.fb.render_node( let res = buffer.fb.render_node(
AcquireSync::Implicit, AcquireSync::Implicit,
ReleaseSync::Implicit, ReleaseSync::Implicit,
self.client.state.color_manager.srgb_srgb(), self.client.state.color_manager.srgb_gamma22(),
&*tl, &*tl,
&self.client.state, &self.client.state,
Some(tl.node_absolute_position()), Some(tl.node_absolute_position()),
@ -341,7 +341,7 @@ impl JayScreencast {
AcquireSync::Implicit, AcquireSync::Implicit,
ReleaseSync::Implicit, ReleaseSync::Implicit,
Transform::None, Transform::None,
self.client.state.color_manager.srgb_srgb(), self.client.state.color_manager.srgb_gamma22(),
on.global.pos.get(), on.global.pos.get(),
render_hardware_cursors, render_hardware_cursors,
x_off, x_off,

View file

@ -2,13 +2,13 @@ mod removed_output;
use { use {
crate::{ crate::{
backend::{self, BackendColorSpace, BackendLuminance, BackendTransferFunction}, backend::{self, BackendColorSpace, BackendEotfs, BackendLuminance},
client::{Client, ClientError, ClientId}, client::{Client, ClientError, ClientId},
cmm::{ cmm::{
cmm_description::ColorDescription, cmm_description::ColorDescription,
cmm_eotf::Eotf,
cmm_luminance::Luminance, cmm_luminance::Luminance,
cmm_primaries::{NamedPrimaries, Primaries}, cmm_primaries::{NamedPrimaries, Primaries},
cmm_transfer_function::TransferFunction,
}, },
damage::DamageMatrix, damage::DamageMatrix,
format::{Format, XRGB8888}, format::{Format, XRGB8888},
@ -76,7 +76,7 @@ pub struct WlOutputGlobal {
pub format: Cell<&'static Format>, pub format: Cell<&'static Format>,
pub width_mm: i32, pub width_mm: i32,
pub height_mm: i32, pub height_mm: i32,
pub transfer_functions: Vec<BackendTransferFunction>, pub eotfs: Vec<BackendEotfs>,
pub color_spaces: Vec<BackendColorSpace>, pub color_spaces: Vec<BackendColorSpace>,
pub primaries: Primaries, pub primaries: Primaries,
pub luminance: Option<BackendLuminance>, pub luminance: Option<BackendLuminance>,
@ -86,7 +86,7 @@ pub struct WlOutputGlobal {
pub persistent: Rc<PersistentOutputState>, pub persistent: Rc<PersistentOutputState>,
pub opt: Rc<OutputGlobalOpt>, pub opt: Rc<OutputGlobalOpt>,
pub damage_matrix: Cell<DamageMatrix>, pub damage_matrix: Cell<DamageMatrix>,
pub btf: Cell<BackendTransferFunction>, pub btf: Cell<BackendEotfs>,
pub bcs: Cell<BackendColorSpace>, pub bcs: Cell<BackendColorSpace>,
pub color_description: CloneCell<Rc<ColorDescription>>, pub color_description: CloneCell<Rc<ColorDescription>>,
pub linear_color_description: CloneCell<Rc<ColorDescription>>, pub linear_color_description: CloneCell<Rc<ColorDescription>>,
@ -179,7 +179,7 @@ impl WlOutputGlobal {
height_mm: i32, height_mm: i32,
output_id: &Rc<OutputId>, output_id: &Rc<OutputId>,
persistent_state: &Rc<PersistentOutputState>, persistent_state: &Rc<PersistentOutputState>,
transfer_functions: Vec<BackendTransferFunction>, eotfs: Vec<BackendEotfs>,
color_spaces: Vec<BackendColorSpace>, color_spaces: Vec<BackendColorSpace>,
primaries: Primaries, primaries: Primaries,
luminance: Option<BackendLuminance>, luminance: Option<BackendLuminance>,
@ -205,7 +205,7 @@ impl WlOutputGlobal {
format: Cell::new(XRGB8888), format: Cell::new(XRGB8888),
width_mm, width_mm,
height_mm, height_mm,
transfer_functions, eotfs,
color_spaces, color_spaces,
primaries, primaries,
luminance, luminance,
@ -215,9 +215,9 @@ impl WlOutputGlobal {
persistent: persistent_state.clone(), persistent: persistent_state.clone(),
opt: Default::default(), opt: Default::default(),
damage_matrix: Default::default(), damage_matrix: Default::default(),
btf: Cell::new(connector_state.transfer_function), btf: Cell::new(connector_state.eotf),
bcs: Cell::new(connector_state.color_space), bcs: Cell::new(connector_state.color_space),
color_description: CloneCell::new(state.color_manager.srgb_srgb().clone()), color_description: CloneCell::new(state.color_manager.srgb_gamma22().clone()),
linear_color_description: CloneCell::new(state.color_manager.srgb_linear().clone()), linear_color_description: CloneCell::new(state.color_manager.srgb_linear().clone()),
color_description_listeners: Default::default(), color_description_listeners: Default::default(),
}; };
@ -345,7 +345,7 @@ impl WlOutputGlobal {
pub fn update_color_description(&self) -> bool { pub fn update_color_description(&self) -> bool {
let mut luminance = Luminance::SRGB; let mut luminance = Luminance::SRGB;
let tf = match self.btf.get() { let tf = match self.btf.get() {
BackendTransferFunction::Default => { BackendEotfs::Default => {
if let Some(brightness) = self.persistent.brightness.get() { if let Some(brightness) = self.persistent.brightness.get() {
let output_max = match self.luminance { let output_max = match self.luminance {
None => 80.0, None => 80.0,
@ -353,14 +353,14 @@ impl WlOutputGlobal {
}; };
luminance.white.0 = luminance.max.0 * brightness / output_max; luminance.white.0 = luminance.max.0 * brightness / output_max;
} }
TransferFunction::Gamma22 Eotf::Gamma22
} }
BackendTransferFunction::Pq => { BackendEotfs::Pq => {
luminance = Luminance::ST2084_PQ; luminance = Luminance::ST2084_PQ;
if let Some(brightness) = self.persistent.brightness.get() { if let Some(brightness) = self.persistent.brightness.get() {
luminance.white.0 = brightness; luminance.white.0 = brightness;
} }
TransferFunction::St2084Pq Eotf::St2084Pq
} }
}; };
let mut target_luminance = luminance.to_target(); let mut target_luminance = luminance.to_target();
@ -386,10 +386,7 @@ impl WlOutputGlobal {
max_cll, max_cll,
max_fall, max_fall,
); );
let cd_linear = self let cd_linear = self.state.color_manager.get_with_tf(&cd, Eotf::Linear);
.state
.color_manager
.get_with_tf(&cd, TransferFunction::Linear);
self.linear_color_description.set(cd_linear.clone()); self.linear_color_description.set(cd_linear.clone());
self.color_description.set(cd.clone()).id != cd.id self.color_description.set(cd.clone()).id != cd.id
} }

View file

@ -1723,7 +1723,7 @@ impl WlSurface {
pub fn color_description(&self) -> Rc<ColorDescription> { pub fn color_description(&self) -> Rc<ColorDescription> {
match self.color_description.get() { match self.color_description.get() {
Some(cd) => cd, Some(cd) => cd,
None => self.client.state.color_manager.srgb_srgb().clone(), None => self.client.state.color_manager.srgb_gamma22().clone(),
} }
} }

View file

@ -138,7 +138,7 @@ impl TestBackend {
non_desktop: false, non_desktop: false,
non_desktop_effective: false, non_desktop_effective: false,
vrr_capable: false, vrr_capable: false,
transfer_functions: vec![], eotfs: vec![],
color_spaces: vec![], color_spaces: vec![],
primaries: Primaries::SRGB, primaries: Primaries::SRGB,
luminance: None, luminance: None,
@ -152,7 +152,7 @@ impl TestBackend {
tearing: false, tearing: false,
format: XRGB8888, format: XRGB8888,
color_space: Default::default(), color_space: Default::default(),
transfer_function: Default::default(), eotf: Default::default(),
}, },
}; };
Self { Self {

View file

@ -1,6 +1,6 @@
use { use {
crate::{ crate::{
cmm::cmm_transfer_function::TransferFunction, cmm::cmm_eotf::Eotf,
it::{ it::{
test_error::TestResult, test_ifs::test_buffer::TestBuffer, test_object::TestObject, test_error::TestResult, test_ifs::test_buffer::TestBuffer, test_object::TestObject,
test_transport::TestTransport, test_transport::TestTransport,
@ -32,7 +32,7 @@ impl TestSinglePixelBufferManager {
destroyed: Cell::new(false), destroyed: Cell::new(false),
}); });
let map = |c: f32| (c as f64 * u32::MAX as f64) as u32; let map = |c: f32| (c as f64 * u32::MAX as f64) as u32;
let [r, g, b, a] = color.to_array(TransferFunction::Gamma22); let [r, g, b, a] = color.to_array(Eotf::Gamma22);
self.tran.send(CreateU32RgbaBuffer { self.tran.send(CreateU32RgbaBuffer {
self_id: self.id, self_id: self.id,
id: obj.id, id: obj.id,

View file

@ -51,7 +51,7 @@ async fn test(run: Rc<TestRun>) -> TestResult {
non_desktop: false, non_desktop: false,
non_desktop_effective: false, non_desktop_effective: false,
vrr_capable: false, vrr_capable: false,
transfer_functions: vec![], eotfs: vec![],
color_spaces: vec![], color_spaces: vec![],
primaries: Primaries::SRGB, primaries: Primaries::SRGB,
luminance: None, luminance: None,
@ -65,7 +65,7 @@ async fn test(run: Rc<TestRun>) -> TestResult {
tearing: false, tearing: false,
format: XRGB8888, format: XRGB8888,
color_space: Default::default(), color_space: Default::default(),
transfer_function: Default::default(), eotf: Default::default(),
}, },
}; };
run.backend run.backend

View file

@ -1,6 +1,6 @@
use { use {
crate::{ crate::{
cmm::cmm_transfer_function::TransferFunction, cmm::cmm_eotf::Eotf,
format::ARGB8888, format::ARGB8888,
gfx_api::{GfxContext, GfxTexture}, gfx_api::{GfxContext, GfxTexture},
pango::{ pango::{
@ -79,7 +79,7 @@ pub fn render(
let data = create_data(font, width, height, scale)?; let data = create_data(font, width, height, scale)?;
data.layout.set_text(text); data.layout.set_text(text);
let font_height = data.layout.pixel_size().1; let font_height = data.layout.pixel_size().1;
let [r, g, b, a] = color.to_array(TransferFunction::Gamma22); let [r, g, b, a] = color.to_array(Eotf::Gamma22);
data.cctx.set_operator(CAIRO_OPERATOR_SOURCE); data.cctx.set_operator(CAIRO_OPERATOR_SOURCE);
data.cctx.set_source_rgba(r as _, g as _, b as _, a as _); data.cctx.set_source_rgba(r as _, g as _, b as _, a as _);
let y = y.unwrap_or((height - font_height) / 2); let y = y.unwrap_or((height - font_height) / 2);

View file

@ -192,7 +192,7 @@ impl GuiElement for Button {
} }
fn render_at(&self, color_manager: &ColorManager, r: &mut RendererBase, x1: f32, y1: f32) { fn render_at(&self, color_manager: &ColorManager, r: &mut RendererBase, x1: f32, y1: f32) {
let srgb_srgb = color_manager.srgb_srgb(); let srgb_srgb = color_manager.srgb_gamma22();
let srgb = &srgb_srgb.linear; let srgb = &srgb_srgb.linear;
let x2 = x1 + self.data.width.get(); let x2 = x1 + self.data.width.get();
let y2 = y1 + self.data.height.get(); let y2 = y1 + self.data.height.get();
@ -331,7 +331,7 @@ impl GuiElement for Label {
AcquireSync::None, AcquireSync::None,
ReleaseSync::None, ReleaseSync::None,
false, false,
color_manager.srgb_srgb(), color_manager.srgb_gamma22(),
); );
} }
} }
@ -644,10 +644,10 @@ impl WindowData {
let res = buf.fb.render_custom( let res = buf.fb.render_custom(
AcquireSync::Implicit, AcquireSync::Implicit,
ReleaseSync::Implicit, ReleaseSync::Implicit,
self.dpy.state.color_manager.srgb_srgb(), self.dpy.state.color_manager.srgb_gamma22(),
self.scale.get(), self.scale.get(),
Some(&Color::from_gray_srgb(0)), Some(&Color::from_gray_srgb(0)),
&self.dpy.state.color_manager.srgb_srgb().linear, &self.dpy.state.color_manager.srgb_gamma22().linear,
None, None,
self.dpy.state.color_manager.srgb_linear(), self.dpy.state.color_manager.srgb_linear(),
&mut |r| { &mut |r| {

View file

@ -79,7 +79,7 @@ impl Renderer<'_> {
} }
let theme = &self.state.theme; let theme = &self.state.theme;
let th = theme.sizes.title_height.get(); let th = theme.sizes.title_height.get();
let srgb_srgb = self.state.color_manager.srgb_srgb(); let srgb_srgb = self.state.color_manager.srgb_gamma22();
let srgb = &srgb_srgb.linear; let srgb = &srgb_srgb.linear;
if let Some(fs) = &fullscreen { if let Some(fs) = &fullscreen {
fs.node_render(self, x, y, None); fs.node_render(self, x, y, None);
@ -135,7 +135,7 @@ impl Renderer<'_> {
AcquireSync::None, AcquireSync::None,
ReleaseSync::None, ReleaseSync::None,
false, false,
self.state.color_manager.srgb_srgb(), self.state.color_manager.srgb_gamma22(),
); );
} }
if let Some(status) = &rd.status if let Some(status) = &rd.status
@ -219,7 +219,7 @@ impl Renderer<'_> {
self.base.fill_boxes( self.base.fill_boxes(
std::slice::from_ref(&pos.at_point(x, y)), std::slice::from_ref(&pos.at_point(x, y)),
&Color::from_srgba_straight(20, 20, 20, 255), &Color::from_srgba_straight(20, 20, 20, 255),
&self.state.color_manager.srgb_srgb().linear, &self.state.color_manager.srgb_gamma22().linear,
); );
if let Some(tex) = placeholder.textures.borrow().get(&self.base.scale) if let Some(tex) = placeholder.textures.borrow().get(&self.base.scale)
&& let Some(texture) = tex.texture() && let Some(texture) = tex.texture()
@ -240,7 +240,7 @@ impl Renderer<'_> {
AcquireSync::None, AcquireSync::None,
ReleaseSync::None, ReleaseSync::None,
false, false,
self.state.color_manager.srgb_srgb(), self.state.color_manager.srgb_gamma22(),
); );
} }
self.render_tl_aux(placeholder.tl_data(), bounds, true); self.render_tl_aux(placeholder.tl_data(), bounds, true);
@ -248,7 +248,7 @@ impl Renderer<'_> {
pub fn render_container(&mut self, container: &ContainerNode, x: i32, y: i32) { pub fn render_container(&mut self, container: &ContainerNode, x: i32, y: i32) {
{ {
let srgb_srgb = self.state.color_manager.srgb_srgb(); let srgb_srgb = self.state.color_manager.srgb_gamma22();
let srgb = &srgb_srgb.linear; let srgb = &srgb_srgb.linear;
let rd = container.render_data.borrow_mut(); let rd = container.render_data.borrow_mut();
let c = self.state.theme.colors.unfocused_title_background.get(); let c = self.state.theme.colors.unfocused_title_background.get();
@ -367,7 +367,7 @@ impl Renderer<'_> {
slice::from_ref(bounds), slice::from_ref(bounds),
&color, &color,
None, None,
&self.state.color_manager.srgb_srgb().linear, &self.state.color_manager.srgb_gamma22().linear,
); );
} }
@ -377,7 +377,7 @@ impl Renderer<'_> {
self.base.fill_boxes( self.base.fill_boxes(
slice::from_ref(rect), slice::from_ref(rect),
&color, &color,
&self.state.color_manager.srgb_srgb().linear, &self.state.color_manager.srgb_gamma22().linear,
); );
} }
@ -482,11 +482,7 @@ impl Renderer<'_> {
}; };
if !rect.is_empty() { if !rect.is_empty() {
let color = Color::from_u32_premultiplied( let color = Color::from_u32_premultiplied(
cd.transfer_function, cd.eotf, color[0], color[1], color[2], color[3],
color[0],
color[1],
color[2],
color[3],
); );
self.base.ops.push(GfxApiOpt::Sync); self.base.ops.push(GfxApiOpt::Sync);
self.base self.base
@ -522,7 +518,7 @@ impl Renderer<'_> {
Rect::new_sized(x + pos.width() - bw, y + bw, bw, pos.height() - bw).unwrap(), Rect::new_sized(x + pos.width() - bw, y + bw, bw, pos.height() - bw).unwrap(),
Rect::new_sized(x + bw, y + pos.height() - bw, pos.width() - 2 * bw, bw).unwrap(), Rect::new_sized(x + bw, y + pos.height() - bw, pos.width() - 2 * bw, bw).unwrap(),
]; ];
let srgb_srgb = self.state.color_manager.srgb_srgb(); let srgb_srgb = self.state.color_manager.srgb_gamma22();
let srgb = &srgb_srgb.linear; let srgb = &srgb_srgb.linear;
self.base.fill_boxes(&borders, &bc, srgb); self.base.fill_boxes(&borders, &bc, srgb);
let title = [Rect::new_sized(x + bw, y + bw, pos.width() - 2 * bw, th).unwrap()]; let title = [Rect::new_sized(x + bw, y + bw, pos.width() - 2 * bw, th).unwrap()];

View file

@ -79,7 +79,7 @@ pub fn take_screenshot(
fb.render_node( fb.render_node(
AcquireSync::Unnecessary, AcquireSync::Unnecessary,
ReleaseSync::Implicit, ReleaseSync::Implicit,
state.color_manager.srgb_srgb(), state.color_manager.srgb_gamma22(),
state.root.deref(), state.root.deref(),
state, state,
Some(state.root.extents.get()), Some(state.root.extents.get()),

View file

@ -476,9 +476,9 @@ impl ConnectorData {
if old.format != s.format { if old.format != s.format {
self.head_managers.handle_format_change(s.format); self.head_managers.handle_format_change(s.format);
} }
if (old.color_space, old.transfer_function) != (s.color_space, s.transfer_function) { if (old.color_space, old.eotf) != (s.color_space, s.eotf) {
self.head_managers self.head_managers
.handle_colors_change(s.color_space, s.transfer_function); .handle_colors_change(s.color_space, s.eotf);
} }
if old.mode != s.mode { if old.mode != s.mode {
self.head_managers.handle_mode_change(s.mode); self.head_managers.handle_mode_change(s.mode);
@ -1290,7 +1290,7 @@ impl State {
AcquireSync::Unnecessary, AcquireSync::Unnecessary,
ReleaseSync::None, ReleaseSync::None,
transform, transform,
self.color_manager.srgb_srgb(), self.color_manager.srgb_gamma22(),
position, position,
true, true,
x_off - capture.rect.x1(), x_off - capture.rect.x1(),

View file

@ -41,7 +41,7 @@ pub fn handle(state: &Rc<State>, connector: &Rc<dyn Connector>) {
tearing: false, tearing: false,
format: XRGB8888, format: XRGB8888,
color_space: Default::default(), color_space: Default::default(),
transfer_function: Default::default(), eotf: Default::default(),
}; };
let id = connector.id(); let id = connector.id();
let name = Rc::new(connector.kernel_id().to_string()); let name = Rc::new(connector.kernel_id().to_string());
@ -67,7 +67,7 @@ pub fn handle(state: &Rc<State>, connector: &Rc<dyn Connector>) {
tearing_mode: Default::default(), tearing_mode: Default::default(),
format: backend_state.format, format: backend_state.format,
color_space: backend_state.color_space, color_space: backend_state.color_space,
transfer_function: backend_state.transfer_function, eotf: backend_state.eotf,
supported_formats: Default::default(), supported_formats: Default::default(),
brightness: None, brightness: None,
}; };
@ -199,7 +199,7 @@ impl ConnectorHandler {
info.height_mm, info.height_mm,
&output_id, &output_id,
&desired_state, &desired_state,
info.transfer_functions.clone(), info.eotfs.clone(),
info.color_spaces.clone(), info.color_spaces.clone(),
info.primaries, info.primaries,
info.luminance, info.luminance,

View file

@ -1,6 +1,6 @@
use { use {
crate::{ crate::{
cmm::cmm_transfer_function::TransferFunction, cmm::cmm_eotf::Eotf,
cpu_worker::{AsyncCpuWork, CpuJob, CpuWork, CpuWorker, PendingJob}, cpu_worker::{AsyncCpuWork, CpuJob, CpuWork, CpuWorker, PendingJob},
format::ARGB8888, format::ARGB8888,
gfx_api::{ gfx_api::{
@ -188,7 +188,7 @@ fn render(
data.layout.set_text(text); data.layout.set_text(text);
} }
let font_height = data.layout.pixel_size().1; let font_height = data.layout.pixel_size().1;
let [r, g, b, a] = color.to_array(TransferFunction::Gamma22); let [r, g, b, a] = color.to_array(Eotf::Gamma22);
data.cctx.set_operator(CAIRO_OPERATOR_SOURCE); data.cctx.set_operator(CAIRO_OPERATOR_SOURCE);
data.cctx.set_source_rgba(r as _, g as _, b as _, a as _); data.cctx.set_source_rgba(r as _, g as _, b as _, a as _);
let y = y.unwrap_or((height - font_height) / 2); let y = y.unwrap_or((height - font_height) / 2);

View file

@ -1,7 +1,7 @@
#![expect(clippy::excessive_precision)] #![expect(clippy::excessive_precision)]
use { use {
crate::{cmm::cmm_transfer_function::TransferFunction, utils::clonecell::CloneCell}, crate::{cmm::cmm_eotf::Eotf, utils::clonecell::CloneCell},
num_traits::Float, num_traits::Float,
std::{cell::Cell, cmp::Ordering, ops::Mul, sync::Arc}, std::{cell::Cell, cmp::Ordering, ops::Mul, sync::Arc},
}; };
@ -68,7 +68,7 @@ impl Color {
a: 1.0, a: 1.0,
}; };
pub fn new(transfer_function: TransferFunction, mut r: f32, mut g: f32, mut b: f32) -> Self { pub fn new(eotf: Eotf, mut r: f32, mut g: f32, mut b: f32) -> Self {
#[inline(always)] #[inline(always)]
fn linear(c: f32) -> f32 { fn linear(c: f32) -> f32 {
c c
@ -111,28 +111,22 @@ impl Color {
b = $tf(b); b = $tf(b);
}}; }};
} }
match transfer_function { match eotf {
TransferFunction::Linear => convert!(linear), Eotf::Linear => convert!(linear),
TransferFunction::St2084Pq => convert!(st2084_pq), Eotf::St2084Pq => convert!(st2084_pq),
TransferFunction::Bt1886 => convert!(gamma24), Eotf::Bt1886 => convert!(gamma24),
TransferFunction::Gamma22 => convert!(gamma22), Eotf::Gamma22 => convert!(gamma22),
TransferFunction::Gamma28 => convert!(gamma28), Eotf::Gamma28 => convert!(gamma28),
TransferFunction::St240 => convert!(st240), Eotf::St240 => convert!(st240),
TransferFunction::Log100 => convert!(log100), Eotf::Log100 => convert!(log100),
TransferFunction::Log316 => convert!(log316), Eotf::Log316 => convert!(log316),
TransferFunction::St428 => convert!(st428), Eotf::St428 => convert!(st428),
} }
Self { r, g, b, a: 1.0 } Self { r, g, b, a: 1.0 }
} }
pub fn new_premultiplied( pub fn new_premultiplied(eotf: Eotf, mut r: f32, mut g: f32, mut b: f32, a: f32) -> Self {
transfer_function: TransferFunction, if eotf == Eotf::Linear {
mut r: f32,
mut g: f32,
mut b: f32,
a: f32,
) -> Self {
if transfer_function == TransferFunction::Linear {
return Self { r, g, b, a }; return Self { r, g, b, a };
} }
if a < 1.0 && a > 0.0 { if a < 1.0 && a > 0.0 {
@ -140,7 +134,7 @@ impl Color {
*c /= a; *c /= a;
} }
} }
let mut c = Self::new(transfer_function, r, g, b); let mut c = Self::new(eotf, r, g, b);
if a < 1.0 { if a < 1.0 {
c = c * a; c = c * a;
} }
@ -156,40 +150,22 @@ impl Color {
} }
pub fn from_srgb(r: u8, g: u8, b: u8) -> Self { pub fn from_srgb(r: u8, g: u8, b: u8) -> Self {
Self::new(TransferFunction::Gamma22, to_f32(r), to_f32(g), to_f32(b)) Self::new(Eotf::Gamma22, to_f32(r), to_f32(g), to_f32(b))
} }
pub fn from_srgba_premultiplied(r: u8, g: u8, b: u8, a: u8) -> Self { pub fn from_srgba_premultiplied(r: u8, g: u8, b: u8, a: u8) -> Self {
Self::new_premultiplied( Self::new_premultiplied(Eotf::Gamma22, to_f32(r), to_f32(g), to_f32(b), to_f32(a))
TransferFunction::Gamma22,
to_f32(r),
to_f32(g),
to_f32(b),
to_f32(a),
)
} }
pub fn from_u32_premultiplied( pub fn from_u32_premultiplied(eotf: Eotf, r: u32, g: u32, b: u32, a: u32) -> Self {
transfer_function: TransferFunction,
r: u32,
g: u32,
b: u32,
a: u32,
) -> Self {
fn to_f32(c: u32) -> f32 { fn to_f32(c: u32) -> f32 {
((c as f64) / (u32::MAX as f64)) as f32 ((c as f64) / (u32::MAX as f64)) as f32
} }
Self::new_premultiplied( Self::new_premultiplied(eotf, to_f32(r), to_f32(g), to_f32(b), to_f32(a))
transfer_function,
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 { pub fn from_srgba_straight(r: u8, g: u8, b: u8, a: u8) -> Self {
let mut c = Self::new(TransferFunction::Gamma22, to_f32(r), to_f32(g), to_f32(b)); let mut c = Self::new(Eotf::Gamma22, to_f32(r), to_f32(g), to_f32(b));
if a < 255 { if a < 255 {
c = c * to_f32(a); c = c * to_f32(a);
} }
@ -197,15 +173,15 @@ impl Color {
} }
pub fn to_srgba_premultiplied(self) -> [u8; 4] { pub fn to_srgba_premultiplied(self) -> [u8; 4] {
let [r, g, b, a] = self.to_array(TransferFunction::Gamma22); let [r, g, b, a] = self.to_array(Eotf::Gamma22);
[to_u8(r), to_u8(g), to_u8(b), to_u8(a)] [to_u8(r), to_u8(g), to_u8(b), to_u8(a)]
} }
pub fn to_array(self, transfer_function: TransferFunction) -> [f32; 4] { pub fn to_array(self, eotf: Eotf) -> [f32; 4] {
self.to_array2(transfer_function, None) self.to_array2(eotf, None)
} }
pub fn to_array2(self, transfer_function: TransferFunction, alpha: Option<f32>) -> [f32; 4] { pub fn to_array2(self, eotf: Eotf, alpha: Option<f32>) -> [f32; 4] {
let mut res = [self.r, self.g, self.b, self.a]; let mut res = [self.r, self.g, self.b, self.a];
fn linear(c: f32) -> f32 { fn linear(c: f32) -> f32 {
c c
@ -254,22 +230,22 @@ impl Color {
} }
}}; }};
} }
if transfer_function != TransferFunction::Linear { if eotf != Eotf::Linear {
if self.a < 1.0 && self.a > 0.0 { if self.a < 1.0 && self.a > 0.0 {
for c in &mut res[..3] { for c in &mut res[..3] {
*c /= self.a; *c /= self.a;
} }
} }
match transfer_function { match eotf {
TransferFunction::Linear => convert!(linear), Eotf::Linear => convert!(linear),
TransferFunction::St2084Pq => convert!(st2084_pq), Eotf::St2084Pq => convert!(st2084_pq),
TransferFunction::Bt1886 => convert!(gamma24), Eotf::Bt1886 => convert!(gamma24),
TransferFunction::Gamma22 => convert!(gamma22), Eotf::Gamma22 => convert!(gamma22),
TransferFunction::Gamma28 => convert!(gamma28), Eotf::Gamma28 => convert!(gamma28),
TransferFunction::St240 => convert!(st240), Eotf::St240 => convert!(st240),
TransferFunction::Log100 => convert!(log100), Eotf::Log100 => convert!(log100),
TransferFunction::Log316 => convert!(log316), Eotf::Log316 => convert!(log316),
TransferFunction::St428 => convert!(st428), Eotf::St428 => convert!(st428),
} }
if self.a < 1.0 { if self.a < 1.0 {
for c in &mut res[..3] { for c in &mut res[..3] {
@ -298,7 +274,7 @@ impl Color {
impl From<jay_config::theme::Color> for Color { impl From<jay_config::theme::Color> for Color {
fn from(f: jay_config::theme::Color) -> Self { fn from(f: jay_config::theme::Color) -> Self {
let [r, g, b, a] = f.to_f32_premultiplied(); let [r, g, b, a] = f.to_f32_premultiplied();
Self::new_premultiplied(TransferFunction::Gamma22, r, g, b, a) Self::new_premultiplied(Eotf::Gamma22, r, g, b, a)
} }
} }

View file

@ -1,8 +1,7 @@
use { use {
crate::{ crate::{
backend::{ backend::{
BackendColorSpace, BackendConnectorState, BackendTransferFunction, HardwareCursor, BackendColorSpace, BackendConnectorState, BackendEotfs, HardwareCursor, KeyState, Mode,
KeyState, Mode,
}, },
client::ClientId, client::ClientId,
cmm::cmm_description::ColorDescription, cmm::cmm_description::ColorDescription,
@ -415,7 +414,7 @@ impl OutputNode {
AcquireSync::Implicit, AcquireSync::Implicit,
ReleaseSync::Implicit, ReleaseSync::Implicit,
self.global.persistent.transform.get(), self.global.persistent.transform.get(),
self.state.color_manager.srgb_srgb(), self.state.color_manager.srgb_gamma22(),
self.global.pos.get(), self.global.pos.get(),
render_hardware_cursors, render_hardware_cursors,
x_off - capture.rect.x1(), x_off - capture.rect.x1(),
@ -928,7 +927,7 @@ impl OutputNode {
} }
pub fn update_state(self: &Rc<Self>, old: BackendConnectorState, state: BackendConnectorState) { pub fn update_state(self: &Rc<Self>, old: BackendConnectorState, state: BackendConnectorState) {
self.update_btf_and_bcs(state.transfer_function, state.color_space); self.update_btf_and_bcs(state.eotf, state.color_space);
if old.vrr != state.vrr { if old.vrr != state.vrr {
self.schedule.set_vrr_enabled(state.vrr); self.schedule.set_vrr_enabled(state.vrr);
} }
@ -938,7 +937,7 @@ impl OutputNode {
self.global.format.set(state.format); self.global.format.set(state.format);
} }
fn update_btf_and_bcs(&self, btf: BackendTransferFunction, bcs: BackendColorSpace) { fn update_btf_and_bcs(&self, btf: BackendEotfs, bcs: BackendColorSpace) {
let old_btf = self.global.btf.replace(btf); let old_btf = self.global.btf.replace(btf);
let old_bcs = self.global.bcs.replace(bcs); let old_bcs = self.global.bcs.replace(bcs);
if (old_btf, old_bcs) == (btf, bcs) { if (old_btf, old_bcs) == (btf, bcs) {

View file

@ -33,7 +33,7 @@ use {
logging::LogLevel, logging::LogLevel,
status::MessageFormat, status::MessageFormat,
theme::Color, theme::Color,
video::{ColorSpace, Format, GfxApi, TearingMode, TransferFunction, Transform, VrrMode}, video::{ColorSpace, Eotf, Format, GfxApi, TearingMode, Transform, VrrMode},
window::{ContentType, TileState, WindowType}, window::{ContentType, TileState, WindowType},
workspace::WorkspaceDisplayOrder, workspace::WorkspaceDisplayOrder,
xwayland::XScalingMode, xwayland::XScalingMode,
@ -347,7 +347,7 @@ pub struct Output {
pub tearing: Option<Tearing>, pub tearing: Option<Tearing>,
pub format: Option<Format>, pub format: Option<Format>,
pub color_space: Option<ColorSpace>, pub color_space: Option<ColorSpace>,
pub transfer_function: Option<TransferFunction>, pub eotf: Option<Eotf>,
pub brightness: Option<Option<f64>>, pub brightness: Option<Option<f64>>,
} }

View file

@ -19,7 +19,7 @@ use {
}, },
}, },
indexmap::IndexMap, indexmap::IndexMap,
jay_config::video::{ColorSpace, TransferFunction, Transform}, jay_config::video::{ColorSpace, Eotf, Transform},
thiserror::Error, thiserror::Error,
}; };
@ -51,7 +51,7 @@ impl Parser for OutputParser<'_> {
let mut ext = Extractor::new(self.cx, span, table); let mut ext = Extractor::new(self.cx, span, table);
let ( let (
(name, match_val, x, y, scale, transform, mode, vrr_val, tearing_val, format_val), (name, match_val, x, y, scale, transform, mode, vrr_val, tearing_val, format_val),
(color_space, transfer_function, brightness_val), (color_space, eotf, brightness_val),
) = ext.extract(( ) = ext.extract((
( (
opt(str("name")), opt(str("name")),
@ -103,17 +103,13 @@ impl Parser for OutputParser<'_> {
} }
}, },
}; };
let transfer_function = match transfer_function { let eotf = match eotf {
None => None, None => None,
Some(tf) => match tf.value { Some(tf) => match tf.value {
"default" => Some(TransferFunction::DEFAULT), "default" => Some(Eotf::DEFAULT),
"pq" => Some(TransferFunction::PQ), "pq" => Some(Eotf::PQ),
_ => { _ => {
log::warn!( log::warn!("Unknown EOTF {}: {}", tf.value, self.cx.error3(tf.span));
"Unknown transfer function {}: {}",
tf.value,
self.cx.error3(tf.span)
);
None None
} }
}, },
@ -193,7 +189,7 @@ impl Parser for OutputParser<'_> {
tearing, tearing,
format, format,
color_space, color_space,
transfer_function, eotf,
brightness, brightness,
}) })
} }

View file

@ -44,7 +44,7 @@ use {
theme::{reset_colors, reset_font, reset_sizes, set_font}, theme::{reset_colors, reset_font, reset_sizes, set_font},
toggle_float_above_fullscreen, toggle_show_bar, toggle_float_above_fullscreen, toggle_show_bar,
video::{ video::{
ColorSpace, Connector, DrmDevice, TransferFunction, connectors, drm_devices, ColorSpace, Connector, DrmDevice, Eotf, connectors, drm_devices,
on_connector_connected, on_connector_disconnected, on_graphics_initialized, on_connector_connected, on_connector_disconnected, on_graphics_initialized,
on_new_connector, on_new_drm_device, set_direct_scanout_enabled, set_gfx_api, on_new_connector, on_new_drm_device, set_direct_scanout_enabled, set_gfx_api,
set_tearing_mode, set_vrr_cursor_hz, set_vrr_mode, set_tearing_mode, set_vrr_cursor_hz, set_vrr_mode,
@ -769,9 +769,9 @@ impl Output {
if let Some(format) = self.format { if let Some(format) = self.format {
c.set_format(format); c.set_format(format);
} }
if self.color_space.is_some() || self.transfer_function.is_some() { if self.color_space.is_some() || self.eotf.is_some() {
let cs = self.color_space.unwrap_or(ColorSpace::DEFAULT); let cs = self.color_space.unwrap_or(ColorSpace::DEFAULT);
let tf = self.transfer_function.unwrap_or(TransferFunction::DEFAULT); let tf = self.eotf.unwrap_or(Eotf::DEFAULT);
c.set_colors(cs, tf); c.set_colors(cs, tf);
} }
if let Some(brightness) = self.brightness { if let Some(brightness) = self.brightness {

View file

@ -1141,6 +1141,14 @@
} }
] ]
}, },
"Eotf": {
"type": "string",
"description": "The EOTF of an output.\n",
"enum": [
"default",
"pq"
]
},
"Exec": { "Exec": {
"description": "Describes how to execute a program.\n\n- Example 1:\n\n ```toml\n [shortcuts]\n ctrl-a = { type = \"exec\", exec = \"alacritty\" }\n ```\n\n- Example 2:\n\n ```toml\n [shortcuts]\n ctrl-a = { type = \"exec\", exec = [\"notify-send\", \"hello world\"] }\n ```\n\n- Example 3:\n\n ```toml\n [shortcuts]\n ctrl-a = { type = \"exec\", exec = { prog = \"notify-send\", args = [\"hello world\"], env.WAYLAND_DISPLAY = \"2\" } }\n ```\n", "description": "Describes how to execute a program.\n\n- Example 1:\n\n ```toml\n [shortcuts]\n ctrl-a = { type = \"exec\", exec = \"alacritty\" }\n ```\n\n- Example 2:\n\n ```toml\n [shortcuts]\n ctrl-a = { type = \"exec\", exec = [\"notify-send\", \"hello world\"] }\n ```\n\n- Example 3:\n\n ```toml\n [shortcuts]\n ctrl-a = { type = \"exec\", exec = { prog = \"notify-send\", args = [\"hello world\"], env.WAYLAND_DISPLAY = \"2\" } }\n ```\n",
"anyOf": [ "anyOf": [
@ -1641,8 +1649,8 @@
"$ref": "#/$defs/ColorSpace" "$ref": "#/$defs/ColorSpace"
}, },
"transfer-function": { "transfer-function": {
"description": "The transfer function of the output.\n", "description": "The EOTF of the output.\n",
"$ref": "#/$defs/TransferFunction" "$ref": "#/$defs/Eotf"
}, },
"brightness": { "brightness": {
"description": "The brightness of the output.\n\nThis setting has no effect unless the vulkan renderer is used.\n", "description": "The brightness of the output.\n\nThis setting has no effect unless the vulkan renderer is used.\n",
@ -1902,14 +1910,6 @@
"floating" "floating"
] ]
}, },
"TransferFunction": {
"type": "string",
"description": "The transfer function of an output.\n",
"enum": [
"default",
"pq"
]
},
"Transform": { "Transform": {
"type": "string", "type": "string",
"description": "An output transformation.", "description": "An output transformation.",

View file

@ -814,7 +814,7 @@ The string should have one of the following values:
The default brightness setting. The default brightness setting.
The behavior depends on the transfer function: The behavior depends on the EOTF:
- `default`: The maximum brightness of the output. - `default`: The maximum brightness of the output.
- `PQ`: 203 cd/m^2 - `PQ`: 203 cd/m^2
@ -2303,6 +2303,25 @@ The table has the following fields:
The numbers should be integers. The numbers should be integers.
<a name="types-Eotf"></a>
### `Eotf`
The EOTF of an output.
Values of this type should be strings.
The string should have one of the following values:
- `default`:
The default EOTF (usually gamma22).
- `pq`:
The PQ EOTF.
<a name="types-Exec"></a> <a name="types-Exec"></a>
### `Exec` ### `Exec`
@ -3517,9 +3536,9 @@ The table has the following fields:
- `transfer-function` (optional): - `transfer-function` (optional):
The transfer function of the output. The EOTF of the output.
The value of this field should be a [TransferFunction](#types-TransferFunction). The value of this field should be a [Eotf](#types-Eotf).
- `brightness` (optional): - `brightness` (optional):
@ -4215,25 +4234,6 @@ The string should have one of the following values:
<a name="types-TransferFunction"></a>
### `TransferFunction`
The transfer function of an output.
Values of this type should be strings.
The string should have one of the following values:
- `default`:
The default transfer function (usually sRGB).
- `pq`:
The PQ transfer function.
<a name="types-Transform"></a> <a name="types-Transform"></a>
### `Transform` ### `Transform`

View file

@ -1956,10 +1956,10 @@ Output:
description: | description: |
The color space of the output. The color space of the output.
transfer-function: transfer-function:
ref: TransferFunction ref: Eotf
required: false required: false
description: | description: |
The transfer function of the output. The EOTF of the output.
brightness: brightness:
ref: Brightness ref: Brightness
required: false required: false
@ -3293,15 +3293,15 @@ ColorSpace:
description: The BT.2020 color space. description: The BT.2020 color space.
TransferFunction: Eotf:
description: | description: |
The transfer function of an output. The EOTF of an output.
kind: string kind: string
values: values:
- value: default - value: default
description: The default transfer function (usually sRGB). description: The default EOTF (usually gamma22).
- value: pq - value: pq
description: The PQ transfer function. description: The PQ EOTF.
Brightness: Brightness:
@ -3317,7 +3317,7 @@ Brightness:
description: | description: |
The default brightness setting. The default brightness setting.
The behavior depends on the transfer function: The behavior depends on the EOTF:
- `default`: The maximum brightness of the output. - `default`: The maximum brightness of the output.
- `PQ`: 203 cd/m^2 - `PQ`: 203 cd/m^2

View file

@ -83,7 +83,7 @@ request set_flip_margin (since = 10) {
request set_colors (since = 15) { request set_colors (since = 15) {
output: str, output: str,
color_space: str, color_space: str,
transfer_function: str, eotf: str,
} }
request set_brightness (since = 16) { request set_brightness (since = 16) {
@ -184,12 +184,12 @@ event current_color_space (since = 15) {
color_space: str, color_space: str,
} }
event supported_transfer_function (since = 15) { event supported_eotf (since = 15) {
transfer_function: str, eotf: str,
} }
event current_transfer_function (since = 15) { event current_eotf (since = 15) {
transfer_function: str, eotf: str,
} }
event brightness_range (since = 16) { event brightness_range (since = 16) {