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},
timer::Timer,
video::{
ColorSpace, Connector, DrmDevice, Format, GfxApi, Mode, TearingMode, TransferFunction,
Transform, VrrMode,
ColorSpace, Connector, DrmDevice, Eotf, Format, GfxApi, Mode, TearingMode, Transform,
VrrMode,
connector_type::{CON_UNKNOWN, ConnectorType},
},
window::{
@ -1042,16 +1042,11 @@ impl ConfigClient {
self.send(&ClientMessage::ConnectorSetFormat { connector, format });
}
pub fn connector_set_colors(
&self,
connector: Connector,
color_space: ColorSpace,
transfer_function: TransferFunction,
) {
pub fn connector_set_colors(&self, connector: Connector, color_space: ColorSpace, eotf: Eotf) {
self.send(&ClientMessage::ConnectorSetColors {
connector,
color_space,
transfer_function,
eotf,
});
}

View file

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

View file

@ -273,26 +273,26 @@ impl Connector {
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
/// sRGB transfer function.
/// gamma22 EOTF.
///
/// 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.
pub fn set_colors(self, color_space: ColorSpace, transfer_function: TransferFunction) {
get!().connector_set_colors(self, color_space, transfer_function);
pub fn set_colors(self, color_space: ColorSpace, eotf: Eotf) {
get!().connector_set_colors(self, color_space, eotf);
}
/// Sets the brightness of the output.
///
/// By default or when `brightness` is `None`, the brightness depends on the
/// transfer function:
/// EOTF:
///
/// - [`TransferFunction::DEFAULT`]: The maximum brightness of the output.
/// - [`TransferFunction::PQ`]: 203 cd/m^2.
/// - [`Eotf::DEFAULT`]: The maximum brightness of the output.
/// - [`Eotf::PQ`]: 203 cd/m^2.
///
/// This should only be used with the PQ transfer function. If the default transfer
/// function is used, you should instead calibrate the hardware directly.
@ -718,13 +718,16 @@ impl ColorSpace {
pub const BT2020: Self = Self(1);
}
/// A transfer function.
/// An electro-optical transfer function (EOTF).
#[derive(Serialize, Deserialize, Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub struct TransferFunction(pub u32);
pub struct Eotf(pub u32);
impl TransferFunction {
/// The default transfer function (usually sRGB).
#[deprecated = "use the Eotf type instead"]
pub type TransferFunction = Eotf;
impl Eotf {
/// The default EOTF (usually gamma22).
pub const DEFAULT: Self = Self(0);
/// The PQ transfer function.
/// The PQ EOTF.
pub const PQ: Self = Self(1);
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,7 +1,7 @@
use {
crate::{
cli::{GlobalArgs, color::parse_color, duration::parse_duration},
cmm::cmm_transfer_function::TransferFunction,
cmm::cmm_eotf::Eotf,
tools::tool_client::{ToolClient, with_tool_client},
wire::jay_damage_tracking::{SetVisualizerColor, SetVisualizerDecay, SetVisualizerEnabled},
},
@ -86,7 +86,7 @@ impl DamageTracking {
}
DamageTrackingCmd::SetColor(c) => {
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 {
self_id: dt,
r,

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,6 +1,6 @@
use {
crate::{
cmm::{cmm_primaries::Primaries, cmm_transfer_function::TransferFunction},
cmm::{cmm_eotf::Eotf, cmm_primaries::Primaries},
theme::Color,
utils::{debug_fn::debug_fn, ordered_float::F64},
},
@ -131,7 +131,7 @@ impl<T, U> Mul<Color> for ColorMatrix<T, U> {
type Output = Color;
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];
if a < 1.0 && a > 0.0 {
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 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 {
color = color * a;
}

View file

@ -652,7 +652,7 @@ fn create_dummy_output(state: &Rc<State>) {
tearing: false,
format: XRGB8888,
color_space: Default::default(),
transfer_function: Default::default(),
eotf: Default::default(),
};
let id = state.connector_ids.next();
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(),
format: XRGB8888,
color_space: backend_state.color_space,
transfer_function: backend_state.transfer_function,
eotf: backend_state.eotf,
supported_formats: Default::default(),
brightness: None,
};

View file

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

View file

@ -397,7 +397,7 @@ fn render_img(image: &InstantiatedCursorImage, renderer: &mut Renderer, x: Fixed
AcquireSync::None,
ReleaseSync::None,
false,
renderer.state.color_manager.srgb_srgb(),
renderer.state.color_manager.srgb_gamma22(),
);
}
}
@ -422,7 +422,7 @@ impl Cursor for StaticCursor {
AcquireSync::None,
ReleaseSync::None,
false,
renderer.state.color_manager.srgb_srgb(),
renderer.state.color_manager.srgb_gamma22(),
);
}
}
@ -465,7 +465,7 @@ impl Cursor for AnimatedCursor {
AcquireSync::None,
ReleaseSync::None,
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 decay_millis = decay.as_millis() as u64 as f32;
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() {
let region = Region::new(entry.rect);
let region = region.subtract_cow(&used);

View file

@ -895,7 +895,7 @@ pub fn create_render_pass(
return GfxRenderPass {
ops: vec![],
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![];
@ -962,7 +962,7 @@ pub fn create_render_pass(
GfxRenderPass {
ops,
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 {
crate::{
cmm::cmm_transfer_function::TransferFunction,
cmm::cmm_eotf::Eotf,
gfx_api::{
AcquireSync, CopyTexture, FramebufferRect, GfxApiOpt, GfxContext, GfxError, GfxTexture,
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) {
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;
unsafe {
(gles.glUseProgram)(ctx.fill_prog.prog);

View file

@ -2,7 +2,7 @@ use {
crate::{
cmm::{
cmm_description::{ColorDescription, LinearColorDescription},
cmm_transfer_function::TransferFunction,
cmm_eotf::Eotf,
},
format::Format,
gfx_api::{
@ -82,7 +82,7 @@ impl Framebuffer {
(gles.glBindFramebuffer)(GL_FRAMEBUFFER, self.gl.fbo);
(gles.glViewport)(0, 0, self.gl.width, self.gl.height);
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.glClear)(GL_COLOR_BUFFER_BIT);
}

View file

@ -6,6 +6,7 @@ mod command;
mod descriptor;
mod descriptor_buffer;
mod device;
mod eotfs;
mod fence;
mod format;
mod image;
@ -18,7 +19,6 @@ mod shaders;
mod shm_image;
mod staging;
mod transfer;
mod transfer_functions;
use {
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) has_alpha_mult: bool,
pub(super) eotf: u32,
pub(super) oetf: u32,
pub(super) inv_eotf: u32,
pub(super) descriptor_set_layouts: ArrayVec<Rc<VulkanDescriptorSetLayout>, 2>,
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.has_alpha_mult as u32).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());
let frag_spec = SpecializationInfo::default()
.map_entries(&frag_spec_entries)

View file

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

View file

@ -1,5 +1,5 @@
#ifndef TRANSFER_FUNCTIONS_GLSL
#define TRANSFER_FUNCTIONS_GLSL
#ifndef EOTFS_GLSL
#define EOTFS_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));
}
vec3 oetf_st2084_pq(vec3 c) {
vec3 inv_eotf_st2084_pq(vec3 c) {
c = clamp(c, 0.0, 1.0);
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));
@ -36,7 +36,7 @@ vec3 eotf_st240(vec3 c) {
);
}
vec3 oetf_st240(vec3 c) {
vec3 inv_eotf_st240(vec3 c) {
return mix(
vec3(4.0) * c,
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)));
}
vec3 oetf_log100(vec3 c) {
vec3 inv_eotf_log100(vec3 c) {
c = clamp(c, 0.0, 1.0);
return mix(
vec3(0.0),
@ -61,7 +61,7 @@ vec3 eotf_log316(vec3 c) {
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);
return mix(
vec3(0.0),
@ -75,7 +75,7 @@ vec3 eotf_st428(vec3 c) {
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);
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) {
switch (oetf) {
vec3 apply_inv_eotf(vec3 c) {
switch (inv_eotf) {
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_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_ST240: return oetf_st240(c);
case TF_LOG100: return oetf_log100(c);
case TF_LOG316: return oetf_log316(c);
case TF_ST428: return oetf_st428(c);
case TF_ST240: return inv_eotf_st240(c);
case TF_LOG100: return inv_eotf_log100(c);
case TF_LOG316: return inv_eotf_log316(c);
case TF_ST428: return inv_eotf_st428(c);
default: return c;
}
}

View file

@ -4,7 +4,7 @@
layout(constant_id = 0) const bool src_has_alpha = false;
layout(constant_id = 1) const bool has_alpha_multiplier = false;
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;
#endif

View file

@ -2,7 +2,7 @@
#extension GL_EXT_samplerless_texture_functions : require
#include "frag_spec_const.glsl"
#include "transfer_functions.glsl"
#include "eotfs.glsl"
#include "out.common.glsl"
layout(set = 0, binding = 0) uniform texture2D in_color;
@ -10,10 +10,10 @@ layout(location = 0) out vec4 out_color;
void main() {
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 = apply_eotf(c.rgb);
c.rgb = apply_oetf(c.rgb);
c.rgb = apply_inv_eotf(c.rgb);
c.rgb *= c.a;
}
out_color = c;

View file

@ -3,7 +3,7 @@
#extension GL_EXT_scalar_block_layout : require
#include "frag_spec_const.glsl"
#include "transfer_functions.glsl"
#include "eotfs.glsl"
#include "tex.common.glsl"
layout(set = 0, binding = 0) uniform sampler sam;
@ -16,7 +16,7 @@ layout(location = 0) out vec4 out_color;
void main() {
vec4 c = textureLod(sampler2D(tex, sam), tex_pos, 0);
if (eotf != oetf || has_matrix) {
if (eotf != inv_eotf || has_matrix) {
vec3 rgb = c.rgb;
if (src_has_alpha) {
rgb /= mix(c.a, 1.0, c.a == 0.0);
@ -25,7 +25,7 @@ void main() {
if (has_matrix) {
rgb = (cm_data.matrix * vec4(rgb, 1.0)).rgb;
}
rgb = apply_oetf(rgb);
rgb = apply_inv_eotf(rgb);
if (src_has_alpha) {
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 {
crate::{
cmm::cmm_transfer_function::TransferFunction,
cmm::cmm_eotf::Eotf,
format::ARGB8888,
gfx_api::{GfxContext, GfxError, GfxTexture},
scale::Scale,
@ -221,7 +221,7 @@ impl PathBuilderExt for PathBuilder {
impl From<crate::theme::Color> for Color {
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;
c.set_red(r / 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] {
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 {
r /= alpha;
g /= alpha;

View file

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

View file

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

View file

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

View file

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

View file

@ -1,6 +1,6 @@
use {
crate::{
backend::BackendTransferFunction,
backend::BackendEotfs,
cmm::cmm_luminance::Luminance,
ifs::head_management::HeadState,
wire::{
@ -27,7 +27,7 @@ impl HeadName {
}
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);
}
if shared.brightness != tran.brightness {
@ -36,14 +36,14 @@ impl HeadName {
}
pub(in super::super) fn send_implied_default_brightness(&self, shared: &HeadState) {
let lux = match shared.transfer_function {
BackendTransferFunction::Default => shared
let lux = match shared.eotf {
BackendEotfs::Default => shared
.monitor_info
.as_ref()
.and_then(|m| m.luminance.as_ref())
.map(|l| l.max)
.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_id: self.id,

View file

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

View file

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

View file

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

View file

@ -1,7 +1,7 @@
use {
crate::{
client::{CAP_JAY_COMPOSITOR, Client, ClientCaps, ClientError},
cmm::cmm_transfer_function::TransferFunction,
cmm::cmm_eotf::Eotf,
globals::{Global, GlobalName},
leaks::Tracker,
object::{Object, Version},
@ -97,7 +97,7 @@ impl JayDamageTrackingRequestHandler for JayDamageTracking {
req: SetVisualizerColor,
_slf: &Rc<Self>,
) -> 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);
Ok(())
}

View file

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

View file

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

View file

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

View file

@ -1723,7 +1723,7 @@ impl WlSurface {
pub fn color_description(&self) -> Rc<ColorDescription> {
match self.color_description.get() {
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_effective: false,
vrr_capable: false,
transfer_functions: vec![],
eotfs: vec![],
color_spaces: vec![],
primaries: Primaries::SRGB,
luminance: None,
@ -152,7 +152,7 @@ impl TestBackend {
tearing: false,
format: XRGB8888,
color_space: Default::default(),
transfer_function: Default::default(),
eotf: Default::default(),
},
};
Self {

View file

@ -1,6 +1,6 @@
use {
crate::{
cmm::cmm_transfer_function::TransferFunction,
cmm::cmm_eotf::Eotf,
it::{
test_error::TestResult, test_ifs::test_buffer::TestBuffer, test_object::TestObject,
test_transport::TestTransport,
@ -32,7 +32,7 @@ impl TestSinglePixelBufferManager {
destroyed: Cell::new(false),
});
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_id: self.id,
id: obj.id,

View file

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

View file

@ -1,6 +1,6 @@
use {
crate::{
cmm::cmm_transfer_function::TransferFunction,
cmm::cmm_eotf::Eotf,
format::ARGB8888,
gfx_api::{GfxContext, GfxTexture},
pango::{
@ -79,7 +79,7 @@ pub fn render(
let data = create_data(font, width, height, scale)?;
data.layout.set_text(text);
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_source_rgba(r as _, g as _, b as _, a as _);
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) {
let srgb_srgb = color_manager.srgb_srgb();
let srgb_srgb = color_manager.srgb_gamma22();
let srgb = &srgb_srgb.linear;
let x2 = x1 + self.data.width.get();
let y2 = y1 + self.data.height.get();
@ -331,7 +331,7 @@ impl GuiElement for Label {
AcquireSync::None,
ReleaseSync::None,
false,
color_manager.srgb_srgb(),
color_manager.srgb_gamma22(),
);
}
}
@ -644,10 +644,10 @@ impl WindowData {
let res = buf.fb.render_custom(
AcquireSync::Implicit,
ReleaseSync::Implicit,
self.dpy.state.color_manager.srgb_srgb(),
self.dpy.state.color_manager.srgb_gamma22(),
self.scale.get(),
Some(&Color::from_gray_srgb(0)),
&self.dpy.state.color_manager.srgb_srgb().linear,
&self.dpy.state.color_manager.srgb_gamma22().linear,
None,
self.dpy.state.color_manager.srgb_linear(),
&mut |r| {

View file

@ -79,7 +79,7 @@ impl Renderer<'_> {
}
let theme = &self.state.theme;
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;
if let Some(fs) = &fullscreen {
fs.node_render(self, x, y, None);
@ -135,7 +135,7 @@ impl Renderer<'_> {
AcquireSync::None,
ReleaseSync::None,
false,
self.state.color_manager.srgb_srgb(),
self.state.color_manager.srgb_gamma22(),
);
}
if let Some(status) = &rd.status
@ -219,7 +219,7 @@ impl Renderer<'_> {
self.base.fill_boxes(
std::slice::from_ref(&pos.at_point(x, y)),
&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)
&& let Some(texture) = tex.texture()
@ -240,7 +240,7 @@ impl Renderer<'_> {
AcquireSync::None,
ReleaseSync::None,
false,
self.state.color_manager.srgb_srgb(),
self.state.color_manager.srgb_gamma22(),
);
}
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) {
{
let srgb_srgb = self.state.color_manager.srgb_srgb();
let srgb_srgb = self.state.color_manager.srgb_gamma22();
let srgb = &srgb_srgb.linear;
let rd = container.render_data.borrow_mut();
let c = self.state.theme.colors.unfocused_title_background.get();
@ -367,7 +367,7 @@ impl Renderer<'_> {
slice::from_ref(bounds),
&color,
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(
slice::from_ref(rect),
&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() {
let color = Color::from_u32_premultiplied(
cd.transfer_function,
color[0],
color[1],
color[2],
color[3],
cd.eotf, color[0], color[1], color[2], color[3],
);
self.base.ops.push(GfxApiOpt::Sync);
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 + 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;
self.base.fill_boxes(&borders, &bc, srgb);
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(
AcquireSync::Unnecessary,
ReleaseSync::Implicit,
state.color_manager.srgb_srgb(),
state.color_manager.srgb_gamma22(),
state.root.deref(),
state,
Some(state.root.extents.get()),

View file

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

View file

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

View file

@ -1,6 +1,6 @@
use {
crate::{
cmm::cmm_transfer_function::TransferFunction,
cmm::cmm_eotf::Eotf,
cpu_worker::{AsyncCpuWork, CpuJob, CpuWork, CpuWorker, PendingJob},
format::ARGB8888,
gfx_api::{
@ -188,7 +188,7 @@ fn render(
data.layout.set_text(text);
}
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_source_rgba(r as _, g as _, b as _, a as _);
let y = y.unwrap_or((height - font_height) / 2);

View file

@ -1,7 +1,7 @@
#![expect(clippy::excessive_precision)]
use {
crate::{cmm::cmm_transfer_function::TransferFunction, utils::clonecell::CloneCell},
crate::{cmm::cmm_eotf::Eotf, utils::clonecell::CloneCell},
num_traits::Float,
std::{cell::Cell, cmp::Ordering, ops::Mul, sync::Arc},
};
@ -68,7 +68,7 @@ impl Color {
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)]
fn linear(c: f32) -> f32 {
c
@ -111,28 +111,22 @@ impl Color {
b = $tf(b);
}};
}
match transfer_function {
TransferFunction::Linear => convert!(linear),
TransferFunction::St2084Pq => convert!(st2084_pq),
TransferFunction::Bt1886 => convert!(gamma24),
TransferFunction::Gamma22 => convert!(gamma22),
TransferFunction::Gamma28 => convert!(gamma28),
TransferFunction::St240 => convert!(st240),
TransferFunction::Log100 => convert!(log100),
TransferFunction::Log316 => convert!(log316),
TransferFunction::St428 => convert!(st428),
match eotf {
Eotf::Linear => convert!(linear),
Eotf::St2084Pq => convert!(st2084_pq),
Eotf::Bt1886 => convert!(gamma24),
Eotf::Gamma22 => convert!(gamma22),
Eotf::Gamma28 => convert!(gamma28),
Eotf::St240 => convert!(st240),
Eotf::Log100 => convert!(log100),
Eotf::Log316 => convert!(log316),
Eotf::St428 => convert!(st428),
}
Self { r, g, b, a: 1.0 }
}
pub fn new_premultiplied(
transfer_function: TransferFunction,
mut r: f32,
mut g: f32,
mut b: f32,
a: f32,
) -> Self {
if transfer_function == TransferFunction::Linear {
pub fn new_premultiplied(eotf: Eotf, mut r: f32, mut g: f32, mut b: f32, a: f32) -> Self {
if eotf == Eotf::Linear {
return Self { r, g, b, a };
}
if a < 1.0 && a > 0.0 {
@ -140,7 +134,7 @@ impl Color {
*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 {
c = c * a;
}
@ -156,40 +150,22 @@ impl Color {
}
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 {
Self::new_premultiplied(
TransferFunction::Gamma22,
to_f32(r),
to_f32(g),
to_f32(b),
to_f32(a),
)
Self::new_premultiplied(Eotf::Gamma22, to_f32(r), to_f32(g), to_f32(b), to_f32(a))
}
pub fn from_u32_premultiplied(
transfer_function: TransferFunction,
r: u32,
g: u32,
b: u32,
a: u32,
) -> Self {
pub fn from_u32_premultiplied(eotf: Eotf, r: u32, g: u32, b: u32, a: u32) -> Self {
fn to_f32(c: u32) -> f32 {
((c as f64) / (u32::MAX as f64)) as f32
}
Self::new_premultiplied(
transfer_function,
to_f32(r),
to_f32(g),
to_f32(b),
to_f32(a),
)
Self::new_premultiplied(eotf, to_f32(r), to_f32(g), to_f32(b), to_f32(a))
}
pub fn from_srgba_straight(r: u8, g: u8, b: u8, a: u8) -> Self {
let mut c = Self::new(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 {
c = c * to_f32(a);
}
@ -197,15 +173,15 @@ impl Color {
}
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)]
}
pub fn to_array(self, transfer_function: TransferFunction) -> [f32; 4] {
self.to_array2(transfer_function, None)
pub fn to_array(self, eotf: Eotf) -> [f32; 4] {
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];
fn linear(c: f32) -> f32 {
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 {
for c in &mut res[..3] {
*c /= self.a;
}
}
match transfer_function {
TransferFunction::Linear => convert!(linear),
TransferFunction::St2084Pq => convert!(st2084_pq),
TransferFunction::Bt1886 => convert!(gamma24),
TransferFunction::Gamma22 => convert!(gamma22),
TransferFunction::Gamma28 => convert!(gamma28),
TransferFunction::St240 => convert!(st240),
TransferFunction::Log100 => convert!(log100),
TransferFunction::Log316 => convert!(log316),
TransferFunction::St428 => convert!(st428),
match eotf {
Eotf::Linear => convert!(linear),
Eotf::St2084Pq => convert!(st2084_pq),
Eotf::Bt1886 => convert!(gamma24),
Eotf::Gamma22 => convert!(gamma22),
Eotf::Gamma28 => convert!(gamma28),
Eotf::St240 => convert!(st240),
Eotf::Log100 => convert!(log100),
Eotf::Log316 => convert!(log316),
Eotf::St428 => convert!(st428),
}
if self.a < 1.0 {
for c in &mut res[..3] {
@ -298,7 +274,7 @@ impl Color {
impl From<jay_config::theme::Color> for Color {
fn from(f: jay_config::theme::Color) -> Self {
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 {
crate::{
backend::{
BackendColorSpace, BackendConnectorState, BackendTransferFunction, HardwareCursor,
KeyState, Mode,
BackendColorSpace, BackendConnectorState, BackendEotfs, HardwareCursor, KeyState, Mode,
},
client::ClientId,
cmm::cmm_description::ColorDescription,
@ -415,7 +414,7 @@ impl OutputNode {
AcquireSync::Implicit,
ReleaseSync::Implicit,
self.global.persistent.transform.get(),
self.state.color_manager.srgb_srgb(),
self.state.color_manager.srgb_gamma22(),
self.global.pos.get(),
render_hardware_cursors,
x_off - capture.rect.x1(),
@ -928,7 +927,7 @@ impl OutputNode {
}
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 {
self.schedule.set_vrr_enabled(state.vrr);
}
@ -938,7 +937,7 @@ impl OutputNode {
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_bcs = self.global.bcs.replace(bcs);
if (old_btf, old_bcs) == (btf, bcs) {

View file

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

View file

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

View file

@ -44,7 +44,7 @@ use {
theme::{reset_colors, reset_font, reset_sizes, set_font},
toggle_float_above_fullscreen, toggle_show_bar,
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_new_connector, on_new_drm_device, set_direct_scanout_enabled, set_gfx_api,
set_tearing_mode, set_vrr_cursor_hz, set_vrr_mode,
@ -769,9 +769,9 @@ impl Output {
if let Some(format) = self.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 tf = self.transfer_function.unwrap_or(TransferFunction::DEFAULT);
let tf = self.eotf.unwrap_or(Eotf::DEFAULT);
c.set_colors(cs, tf);
}
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": {
"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": [
@ -1641,8 +1649,8 @@
"$ref": "#/$defs/ColorSpace"
},
"transfer-function": {
"description": "The transfer function of the output.\n",
"$ref": "#/$defs/TransferFunction"
"description": "The EOTF of the output.\n",
"$ref": "#/$defs/Eotf"
},
"brightness": {
"description": "The brightness of the output.\n\nThis setting has no effect unless the vulkan renderer is used.\n",
@ -1902,14 +1910,6 @@
"floating"
]
},
"TransferFunction": {
"type": "string",
"description": "The transfer function of an output.\n",
"enum": [
"default",
"pq"
]
},
"Transform": {
"type": "string",
"description": "An output transformation.",

View file

@ -814,7 +814,7 @@ The string should have one of the following values:
The default brightness setting.
The behavior depends on the transfer function:
The behavior depends on the EOTF:
- `default`: The maximum brightness of the output.
- `PQ`: 203 cd/m^2
@ -2303,6 +2303,25 @@ The table has the following fields:
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>
### `Exec`
@ -3517,9 +3536,9 @@ The table has the following fields:
- `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):
@ -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>
### `Transform`

View file

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

View file

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