cmm: enable using the display primaries in SDR mode
This commit is contained in:
parent
2b7b3b5310
commit
67760e270e
19 changed files with 259 additions and 21 deletions
|
|
@ -1124,6 +1124,13 @@ impl ConfigClient {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn connector_set_use_native_gamut(&self, connector: Connector, use_native_gamut: bool) {
|
||||||
|
self.send(&ClientMessage::ConnectorSetUseNativeGamut {
|
||||||
|
connector,
|
||||||
|
use_native_gamut,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
pub fn connector_get_scale(&self, connector: Connector) -> f64 {
|
pub fn connector_get_scale(&self, connector: Connector) -> f64 {
|
||||||
let res = self.send_with_response(&ClientMessage::ConnectorGetScale { connector });
|
let res = self.send_with_response(&ClientMessage::ConnectorGetScale { connector });
|
||||||
get_response!(res, 1.0, ConnectorGetScale { scale });
|
get_response!(res, 1.0, ConnectorGetScale { scale });
|
||||||
|
|
|
||||||
|
|
@ -816,6 +816,10 @@ pub enum ClientMessage<'a> {
|
||||||
position: BarPosition,
|
position: BarPosition,
|
||||||
},
|
},
|
||||||
GetBarPosition,
|
GetBarPosition,
|
||||||
|
ConnectorSetUseNativeGamut {
|
||||||
|
connector: Connector,
|
||||||
|
use_native_gamut: bool,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
|
|
||||||
|
|
@ -338,6 +338,26 @@ impl Connector {
|
||||||
pub fn connector_in_direction(self, direction: Direction) -> Connector {
|
pub fn connector_in_direction(self, direction: Direction) -> Connector {
|
||||||
get!(Connector(0)).get_connector_in_direction(self, direction)
|
get!(Connector(0)).get_connector_in_direction(self, direction)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Configures whether the display primaries are used.
|
||||||
|
///
|
||||||
|
/// By default, Jay pretends that the display uses sRGB primaries. This is also how
|
||||||
|
/// most other systems behave. In reality, most displays use a much larger gamut. For
|
||||||
|
/// example, they advertise that they support 95% of the DCI-P3 gamut. If the display
|
||||||
|
/// is interpreting colors in their native gamut, then colors will appear more
|
||||||
|
/// saturated than their specification.
|
||||||
|
///
|
||||||
|
/// If this is set to `true`, Jay assumes that the display uses the primaries
|
||||||
|
/// advertised in its EDID. This might produce more accurate colors while also
|
||||||
|
/// allowing color-managed applications to use the full gamut of the display.
|
||||||
|
///
|
||||||
|
/// This setting has no effect when the display is explicitly operating in a wide
|
||||||
|
/// color space.
|
||||||
|
///
|
||||||
|
/// The default is `false`.
|
||||||
|
pub fn set_use_native_gamut(self, use_native_gamut: bool) {
|
||||||
|
get!().connector_set_use_native_gamut(self, use_native_gamut);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns all available DRM devices.
|
/// Returns all available DRM devices.
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,14 @@ use {
|
||||||
crate::{
|
crate::{
|
||||||
backend::{BackendColorSpace, BackendEotfs},
|
backend::{BackendColorSpace, BackendEotfs},
|
||||||
cli::GlobalArgs,
|
cli::GlobalArgs,
|
||||||
|
cmm::cmm_primaries::Primaries,
|
||||||
format::{Format, XRGB8888},
|
format::{Format, XRGB8888},
|
||||||
ifs::wl_output::BlendSpace,
|
ifs::wl_output::BlendSpace,
|
||||||
scale::Scale,
|
scale::Scale,
|
||||||
tools::tool_client::{Handle, ToolClient, with_tool_client},
|
tools::tool_client::{Handle, ToolClient, with_tool_client},
|
||||||
utils::{errorfmt::ErrorFmt, transform_ext::TransformExt},
|
utils::{
|
||||||
|
debug_fn::debug_fn, errorfmt::ErrorFmt, ordered_float::F64, transform_ext::TransformExt,
|
||||||
|
},
|
||||||
wire::{JayRandrId, jay_compositor, jay_randr},
|
wire::{JayRandrId, jay_compositor, jay_randr},
|
||||||
},
|
},
|
||||||
clap::{
|
clap::{
|
||||||
|
|
@ -167,6 +170,30 @@ pub enum OutputCommand {
|
||||||
Brightness(BrightnessArgs),
|
Brightness(BrightnessArgs),
|
||||||
/// Change the blend space.
|
/// Change the blend space.
|
||||||
BlendSpace(BlendSpaceArgs),
|
BlendSpace(BlendSpaceArgs),
|
||||||
|
/// Change whether the display primaries are used.
|
||||||
|
UseNativeGamut(UseNativeGamutArgs),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Args, Debug, Clone)]
|
||||||
|
pub struct UseNativeGamutArgs {
|
||||||
|
/// Configures whether the display primaries are used.
|
||||||
|
///
|
||||||
|
/// By default, Jay pretends that the display uses sRGB primaries. This is also how
|
||||||
|
/// most other systems behave. In reality, most displays use a much larger gamut. For
|
||||||
|
/// example, they advertise that they support 95% of the DCI-P3 gamut. If the display
|
||||||
|
/// is interpreting colors in their native gamut, then colors will appear more
|
||||||
|
/// saturated than their specification.
|
||||||
|
///
|
||||||
|
/// If this is set to `true`, Jay assumes that the display uses the primaries
|
||||||
|
/// advertised in its EDID. This might produce more accurate colors while also
|
||||||
|
/// allowing color-managed applications to use the full gamut of the display.
|
||||||
|
///
|
||||||
|
/// This setting has no effect when the display is explicitly operating in a wide
|
||||||
|
/// color space.
|
||||||
|
///
|
||||||
|
/// The default is `false`.
|
||||||
|
#[arg(action = clap::ArgAction::Set)]
|
||||||
|
pub use_native_gamut: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(ValueEnum, Debug, Clone)]
|
#[derive(ValueEnum, Debug, Clone)]
|
||||||
|
|
@ -499,6 +526,8 @@ struct Output {
|
||||||
pub brightness_range: Option<(f64, f64)>,
|
pub brightness_range: Option<(f64, f64)>,
|
||||||
pub brightness: Option<f64>,
|
pub brightness: Option<f64>,
|
||||||
pub blend_space: Option<String>,
|
pub blend_space: Option<String>,
|
||||||
|
pub native_gamut: Option<Primaries>,
|
||||||
|
pub use_native_gamut: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
|
@ -789,6 +818,19 @@ impl Randr {
|
||||||
blend_space: &a.blend_space,
|
blend_space: &a.blend_space,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
OutputCommand::UseNativeGamut(a) => {
|
||||||
|
self.handle_error(randr, move |msg| {
|
||||||
|
eprintln!(
|
||||||
|
"Could not change whether the compositor uses the native gamut: {}",
|
||||||
|
msg,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
tc.send(jay_randr::SetUseNativeGamut {
|
||||||
|
self_id: randr,
|
||||||
|
output: &args.output,
|
||||||
|
use_native_gamut: a.use_native_gamut as _,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
tc.round_trip().await;
|
tc.round_trip().await;
|
||||||
}
|
}
|
||||||
|
|
@ -1024,6 +1066,25 @@ impl Randr {
|
||||||
if let Some(bs) = &o.blend_space {
|
if let Some(bs) = &o.blend_space {
|
||||||
println!(" blend space: {bs}");
|
println!(" blend space: {bs}");
|
||||||
}
|
}
|
||||||
|
if let Some(p) = &o.native_gamut {
|
||||||
|
println!(
|
||||||
|
" native gamut:{}",
|
||||||
|
debug_fn(|f| {
|
||||||
|
if o.use_native_gamut {
|
||||||
|
f.write_str(" (used for default color space)")?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
println!(
|
||||||
|
" red: {:.6} {:.6} green: {:.6} {:.6}",
|
||||||
|
p.r.0.0, p.r.1.0, p.g.0.0, p.g.1.0
|
||||||
|
);
|
||||||
|
println!(
|
||||||
|
" blue: {:.6} {:.6} white: {:.6} {:.6}",
|
||||||
|
p.b.0.0, p.b.1.0, p.wp.0.0, p.wp.1.0
|
||||||
|
);
|
||||||
|
}
|
||||||
if o.modes.is_not_empty() && modes {
|
if o.modes.is_not_empty() && modes {
|
||||||
println!(" modes:");
|
println!(" modes:");
|
||||||
for mode in &o.modes {
|
for mode in &o.modes {
|
||||||
|
|
@ -1204,6 +1265,24 @@ impl Randr {
|
||||||
let output = c.output.as_mut().unwrap();
|
let output = c.output.as_mut().unwrap();
|
||||||
output.blend_space = Some(msg.blend_space.to_string());
|
output.blend_space = Some(msg.blend_space.to_string());
|
||||||
});
|
});
|
||||||
|
jay_randr::NativeGamut::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();
|
||||||
|
let primaries = Primaries {
|
||||||
|
r: (F64(msg.r_x), F64(msg.r_y)),
|
||||||
|
g: (F64(msg.g_x), F64(msg.g_y)),
|
||||||
|
b: (F64(msg.b_x), F64(msg.b_y)),
|
||||||
|
wp: (F64(msg.w_x), F64(msg.w_y)),
|
||||||
|
};
|
||||||
|
output.native_gamut = Some(primaries);
|
||||||
|
});
|
||||||
|
jay_randr::UseNativeGamut::handle(tc, randr, data.clone(), |data, _| {
|
||||||
|
let mut data = data.borrow_mut();
|
||||||
|
let c = data.connectors.last_mut().unwrap();
|
||||||
|
let output = c.output.as_mut().unwrap();
|
||||||
|
output.use_native_gamut = true;
|
||||||
|
});
|
||||||
tc.round_trip().await;
|
tc.round_trip().await;
|
||||||
data.borrow_mut().clone()
|
data.borrow_mut().clone()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ use {
|
||||||
HeadManagers, HeadState, jay_head_manager_session_v1::handle_jay_head_manager_done,
|
HeadManagers, HeadState, jay_head_manager_session_v1::handle_jay_head_manager_done,
|
||||||
},
|
},
|
||||||
jay_screencast::{perform_screencast_realloc, perform_toplevel_screencasts},
|
jay_screencast::{perform_screencast_realloc, perform_toplevel_screencasts},
|
||||||
wl_output::{BlendSpace, OutputId, PersistentOutputState, WlOutputGlobal},
|
wl_output::{OutputId, PersistentOutputState, WlOutputGlobal},
|
||||||
wl_seat::handle_position_hint_requests,
|
wl_seat::handle_position_hint_requests,
|
||||||
wl_surface::{
|
wl_surface::{
|
||||||
NoneSurfaceExt, xdg_surface::handle_xdg_surface_configure_events,
|
NoneSurfaceExt, xdg_surface::handle_xdg_surface_configure_events,
|
||||||
|
|
@ -629,16 +629,7 @@ fn create_dummy_output(state: &Rc<State>) {
|
||||||
model: "jay-dummy-output".to_string(),
|
model: "jay-dummy-output".to_string(),
|
||||||
serial_number: "".to_string(),
|
serial_number: "".to_string(),
|
||||||
});
|
});
|
||||||
let persistent_state = Rc::new(PersistentOutputState {
|
let persistent_state = Rc::new(PersistentOutputState::default());
|
||||||
transform: Default::default(),
|
|
||||||
scale: Default::default(),
|
|
||||||
pos: Default::default(),
|
|
||||||
vrr_mode: Cell::new(VrrMode::NEVER),
|
|
||||||
vrr_cursor_hz: Default::default(),
|
|
||||||
tearing_mode: Cell::new(&TearingMode::Never),
|
|
||||||
brightness: Cell::new(None),
|
|
||||||
blend_space: Cell::new(BlendSpace::Srgb),
|
|
||||||
});
|
|
||||||
let mode = backend::Mode {
|
let mode = backend::Mode {
|
||||||
width: 0,
|
width: 0,
|
||||||
height: 0,
|
height: 0,
|
||||||
|
|
|
||||||
|
|
@ -1353,6 +1353,16 @@ impl ConfigProxyHandler {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle_connector_set_use_native_gamut(
|
||||||
|
&self,
|
||||||
|
connector: Connector,
|
||||||
|
use_native_gamut: bool,
|
||||||
|
) -> Result<(), CphError> {
|
||||||
|
let connector = self.get_output_node(connector)?;
|
||||||
|
connector.set_use_native_gamut(use_native_gamut);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn handle_set_float_above_fullscreen(&self, above: bool) {
|
fn handle_set_float_above_fullscreen(&self, above: bool) {
|
||||||
self.state.float_above_fullscreen.set(above);
|
self.state.float_above_fullscreen.set(above);
|
||||||
for seat in self.state.globals.seats.lock().values() {
|
for seat in self.state.globals.seats.lock().values() {
|
||||||
|
|
@ -3316,6 +3326,12 @@ impl ConfigProxyHandler {
|
||||||
ClientMessage::SeatEnableUnicodeInput { seat } => self
|
ClientMessage::SeatEnableUnicodeInput { seat } => self
|
||||||
.handle_seat_enable_unicode_input(seat)
|
.handle_seat_enable_unicode_input(seat)
|
||||||
.wrn("seat_enable_unicode_input")?,
|
.wrn("seat_enable_unicode_input")?,
|
||||||
|
ClientMessage::ConnectorSetUseNativeGamut {
|
||||||
|
connector,
|
||||||
|
use_native_gamut,
|
||||||
|
} => self
|
||||||
|
.handle_connector_set_use_native_gamut(connector, use_native_gamut)
|
||||||
|
.wrn("connector_set_use_native_gamut")?,
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,7 @@ impl Global for JayCompositorGlobal {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn version(&self) -> u32 {
|
fn version(&self) -> u32 {
|
||||||
22
|
23
|
||||||
}
|
}
|
||||||
|
|
||||||
fn required_caps(&self) -> ClientCaps {
|
fn required_caps(&self) -> ClientCaps {
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@ const FLIP_MARGIN_SINCE: Version = Version(10);
|
||||||
const COLORIMETRY_SINCE: Version = Version(15);
|
const COLORIMETRY_SINCE: Version = Version(15);
|
||||||
const BRIGHTNESS_SINCE: Version = Version(16);
|
const BRIGHTNESS_SINCE: Version = Version(16);
|
||||||
const BLEND_SPACE_SINCE: Version = Version(21);
|
const BLEND_SPACE_SINCE: Version = Version(21);
|
||||||
|
const NATIVE_GAMUT_SINCE: Version = Version(23);
|
||||||
|
|
||||||
impl JayRandr {
|
impl JayRandr {
|
||||||
pub fn new(id: JayRandrId, client: &Rc<Client>, version: Version) -> Self {
|
pub fn new(id: JayRandrId, client: &Rc<Client>, version: Version) -> Self {
|
||||||
|
|
@ -215,6 +216,23 @@ impl JayRandr {
|
||||||
blend_space: node.global.persistent.blend_space.get().name(),
|
blend_space: node.global.persistent.blend_space.get().name(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if self.version >= NATIVE_GAMUT_SINCE {
|
||||||
|
let p = &node.global.primaries;
|
||||||
|
self.client.event(NativeGamut {
|
||||||
|
self_id: self.id,
|
||||||
|
r_x: p.r.0.0,
|
||||||
|
r_y: p.r.1.0,
|
||||||
|
g_x: p.g.0.0,
|
||||||
|
g_y: p.g.1.0,
|
||||||
|
b_x: p.b.0.0,
|
||||||
|
b_y: p.b.1.0,
|
||||||
|
w_x: p.wp.0.0,
|
||||||
|
w_y: p.wp.1.0,
|
||||||
|
});
|
||||||
|
if node.global.persistent.use_native_gamut.get() {
|
||||||
|
self.client.event(UseNativeGamut { self_id: self.id });
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_error(&self, msg: &str) {
|
fn send_error(&self, msg: &str) {
|
||||||
|
|
@ -551,6 +569,18 @@ impl JayRandrRequestHandler for JayRandr {
|
||||||
c.set_blend_space(space);
|
c.set_blend_space(space);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn set_use_native_gamut(
|
||||||
|
&self,
|
||||||
|
req: SetUseNativeGamut<'_>,
|
||||||
|
_slf: &Rc<Self>,
|
||||||
|
) -> Result<(), Self::Error> {
|
||||||
|
let Some(c) = self.get_output_node(req.output) else {
|
||||||
|
return Ok(());
|
||||||
|
};
|
||||||
|
c.set_use_native_gamut(req.use_native_gamut != 0);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object_base! {
|
object_base! {
|
||||||
|
|
|
||||||
|
|
@ -140,6 +140,7 @@ pub struct PersistentOutputState {
|
||||||
pub tearing_mode: Cell<&'static TearingMode>,
|
pub tearing_mode: Cell<&'static TearingMode>,
|
||||||
pub brightness: Cell<Option<f64>>,
|
pub brightness: Cell<Option<f64>>,
|
||||||
pub blend_space: Cell<BlendSpace>,
|
pub blend_space: Cell<BlendSpace>,
|
||||||
|
pub use_native_gamut: Cell<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for PersistentOutputState {
|
impl Default for PersistentOutputState {
|
||||||
|
|
@ -153,6 +154,7 @@ impl Default for PersistentOutputState {
|
||||||
tearing_mode: Cell::new(&TearingMode::Never),
|
tearing_mode: Cell::new(&TearingMode::Never),
|
||||||
brightness: Default::default(),
|
brightness: Default::default(),
|
||||||
blend_space: Cell::new(BlendSpace::Srgb),
|
blend_space: Cell::new(BlendSpace::Srgb),
|
||||||
|
use_native_gamut: Cell::new(false),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -384,18 +386,25 @@ impl WlOutputGlobal {
|
||||||
let target_primaries;
|
let target_primaries;
|
||||||
match self.bcs.get() {
|
match self.bcs.get() {
|
||||||
BackendColorSpace::Default => {
|
BackendColorSpace::Default => {
|
||||||
named_primaries = NamedPrimaries::Srgb;
|
if self.persistent.use_native_gamut.get()
|
||||||
primaries = named_primaries.primaries();
|
&& self.primaries != NamedPrimaries::Srgb.primaries()
|
||||||
|
{
|
||||||
|
named_primaries = None;
|
||||||
|
primaries = self.primaries;
|
||||||
|
} else {
|
||||||
|
named_primaries = Some(NamedPrimaries::Srgb);
|
||||||
|
primaries = NamedPrimaries::Srgb.primaries();
|
||||||
|
}
|
||||||
target_primaries = primaries;
|
target_primaries = primaries;
|
||||||
}
|
}
|
||||||
BackendColorSpace::Bt2020 => {
|
BackendColorSpace::Bt2020 => {
|
||||||
named_primaries = NamedPrimaries::Bt2020;
|
named_primaries = Some(NamedPrimaries::Bt2020);
|
||||||
primaries = named_primaries.primaries();
|
primaries = NamedPrimaries::Bt2020.primaries();
|
||||||
target_primaries = self.primaries;
|
target_primaries = self.primaries;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let cd = self.state.color_manager.get_description(
|
let cd = self.state.color_manager.get_description(
|
||||||
Some(named_primaries),
|
named_primaries,
|
||||||
primaries,
|
primaries,
|
||||||
luminance,
|
luminance,
|
||||||
tf,
|
tf,
|
||||||
|
|
|
||||||
|
|
@ -184,6 +184,7 @@ impl ConnectorHandler {
|
||||||
tearing_mode: Cell::new(self.state.default_tearing_mode.get()),
|
tearing_mode: Cell::new(self.state.default_tearing_mode.get()),
|
||||||
brightness: Cell::new(None),
|
brightness: Cell::new(None),
|
||||||
blend_space: Cell::new(BlendSpace::Srgb),
|
blend_space: Cell::new(BlendSpace::Srgb),
|
||||||
|
use_native_gamut: Cell::new(false),
|
||||||
});
|
});
|
||||||
self.state
|
self.state
|
||||||
.persistent_output_states
|
.persistent_output_states
|
||||||
|
|
|
||||||
|
|
@ -335,7 +335,7 @@ impl ToolClient {
|
||||||
self_id: s.registry,
|
self_id: s.registry,
|
||||||
name: s.jay_compositor.0,
|
name: s.jay_compositor.0,
|
||||||
interface: JayCompositor.name(),
|
interface: JayCompositor.name(),
|
||||||
version: s.jay_compositor.1.min(22),
|
version: s.jay_compositor.1.min(23),
|
||||||
id: id.into(),
|
id: id.into(),
|
||||||
});
|
});
|
||||||
self.jay_compositor.set(Some(id));
|
self.jay_compositor.set(Some(id));
|
||||||
|
|
|
||||||
|
|
@ -1005,6 +1005,17 @@ impl OutputNode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_use_native_gamut(&self, use_native_gamut: bool) {
|
||||||
|
let old = self
|
||||||
|
.global
|
||||||
|
.persistent
|
||||||
|
.use_native_gamut
|
||||||
|
.replace(use_native_gamut);
|
||||||
|
if old != use_native_gamut {
|
||||||
|
self.update_color_description();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_blend_space(&self, blend_space: BlendSpace) {
|
pub fn set_blend_space(&self, blend_space: BlendSpace) {
|
||||||
let old = self.global.persistent.blend_space.replace(blend_space);
|
let old = self.global.persistent.blend_space.replace(blend_space);
|
||||||
if old != blend_space {
|
if old != blend_space {
|
||||||
|
|
|
||||||
|
|
@ -366,6 +366,7 @@ pub struct Output {
|
||||||
pub eotf: Option<Eotf>,
|
pub eotf: Option<Eotf>,
|
||||||
pub brightness: Option<Option<f64>>,
|
pub brightness: Option<Option<f64>>,
|
||||||
pub blend_space: Option<BlendSpace>,
|
pub blend_space: Option<BlendSpace>,
|
||||||
|
pub use_native_gamut: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ use {
|
||||||
config::{
|
config::{
|
||||||
Output,
|
Output,
|
||||||
context::Context,
|
context::Context,
|
||||||
extractor::{Extractor, ExtractorError, fltorint, opt, recover, s32, str, val},
|
extractor::{Extractor, ExtractorError, bol, fltorint, opt, recover, s32, str, val},
|
||||||
parser::{DataType, ParseResult, Parser, UnexpectedDataType},
|
parser::{DataType, ParseResult, Parser, UnexpectedDataType},
|
||||||
parsers::{
|
parsers::{
|
||||||
format::FormatParser,
|
format::FormatParser,
|
||||||
|
|
@ -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, eotf, brightness_val, blend_space),
|
(color_space, eotf, brightness_val, blend_space, use_native_gamut),
|
||||||
) = ext.extract((
|
) = ext.extract((
|
||||||
(
|
(
|
||||||
opt(str("name")),
|
opt(str("name")),
|
||||||
|
|
@ -70,6 +70,7 @@ impl Parser for OutputParser<'_> {
|
||||||
recover(opt(str("transfer-function"))),
|
recover(opt(str("transfer-function"))),
|
||||||
opt(val("brightness")),
|
opt(val("brightness")),
|
||||||
recover(opt(str("blend-space"))),
|
recover(opt(str("blend-space"))),
|
||||||
|
recover(opt(bol("use-native-gamut"))),
|
||||||
),
|
),
|
||||||
))?;
|
))?;
|
||||||
let transform = match transform {
|
let transform = match transform {
|
||||||
|
|
@ -208,6 +209,7 @@ impl Parser for OutputParser<'_> {
|
||||||
eotf,
|
eotf,
|
||||||
brightness,
|
brightness,
|
||||||
blend_space,
|
blend_space,
|
||||||
|
use_native_gamut: use_native_gamut.despan(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -862,6 +862,9 @@ impl Output {
|
||||||
if let Some(bs) = self.blend_space {
|
if let Some(bs) = self.blend_space {
|
||||||
c.set_blend_space(bs);
|
c.set_blend_space(bs);
|
||||||
}
|
}
|
||||||
|
if let Some(use_native_gamut) = self.use_native_gamut {
|
||||||
|
c.set_use_native_gamut(use_native_gamut);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1744,6 +1744,10 @@
|
||||||
"blend-space": {
|
"blend-space": {
|
||||||
"description": "The blend space of the output.\n\nThe default is `srgb`.\n",
|
"description": "The blend space of the output.\n\nThe default is `srgb`.\n",
|
||||||
"$ref": "#/$defs/BlendSpace"
|
"$ref": "#/$defs/BlendSpace"
|
||||||
|
},
|
||||||
|
"use-native-gamut": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Configures whether the display primaries are used.\n\nBy default, Jay pretends that the display uses sRGB primaries. This is also how\nmost other systems behave. In reality, most displays use a much larger gamut. For\nexample, they advertise that they support 95% of the DCI-P3 gamut. If the display\nis interpreting colors in their native gamut, then colors will appear more\nsaturated than their specification.\n\nIf this is set to `true`, Jay assumes that the display uses the primaries\nadvertised in its EDID. This might produce more accurate colors while also\nallowing color-managed applications to use the full gamut of the display.\n\nThis setting has no effect when the display is explicitly operating in a wide\ncolor space.\n\nThe default is `false`.\n"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": [
|
||||||
|
|
|
||||||
|
|
@ -3836,6 +3836,27 @@ The table has the following fields:
|
||||||
|
|
||||||
The value of this field should be a [BlendSpace](#types-BlendSpace).
|
The value of this field should be a [BlendSpace](#types-BlendSpace).
|
||||||
|
|
||||||
|
- `use-native-gamut` (optional):
|
||||||
|
|
||||||
|
Configures whether the display primaries are used.
|
||||||
|
|
||||||
|
By default, Jay pretends that the display uses sRGB primaries. This is also how
|
||||||
|
most other systems behave. In reality, most displays use a much larger gamut. For
|
||||||
|
example, they advertise that they support 95% of the DCI-P3 gamut. If the display
|
||||||
|
is interpreting colors in their native gamut, then colors will appear more
|
||||||
|
saturated than their specification.
|
||||||
|
|
||||||
|
If this is set to `true`, Jay assumes that the display uses the primaries
|
||||||
|
advertised in its EDID. This might produce more accurate colors while also
|
||||||
|
allowing color-managed applications to use the full gamut of the display.
|
||||||
|
|
||||||
|
This setting has no effect when the display is explicitly operating in a wide
|
||||||
|
color space.
|
||||||
|
|
||||||
|
The default is `false`.
|
||||||
|
|
||||||
|
The value of this field should be a boolean.
|
||||||
|
|
||||||
|
|
||||||
<a name="types-OutputMatch"></a>
|
<a name="types-OutputMatch"></a>
|
||||||
### `OutputMatch`
|
### `OutputMatch`
|
||||||
|
|
|
||||||
|
|
@ -2069,6 +2069,26 @@ Output:
|
||||||
The blend space of the output.
|
The blend space of the output.
|
||||||
|
|
||||||
The default is `srgb`.
|
The default is `srgb`.
|
||||||
|
use-native-gamut:
|
||||||
|
kind: boolean
|
||||||
|
required: false
|
||||||
|
description: |
|
||||||
|
Configures whether the display primaries are used.
|
||||||
|
|
||||||
|
By default, Jay pretends that the display uses sRGB primaries. This is also how
|
||||||
|
most other systems behave. In reality, most displays use a much larger gamut. For
|
||||||
|
example, they advertise that they support 95% of the DCI-P3 gamut. If the display
|
||||||
|
is interpreting colors in their native gamut, then colors will appear more
|
||||||
|
saturated than their specification.
|
||||||
|
|
||||||
|
If this is set to `true`, Jay assumes that the display uses the primaries
|
||||||
|
advertised in its EDID. This might produce more accurate colors while also
|
||||||
|
allowing color-managed applications to use the full gamut of the display.
|
||||||
|
|
||||||
|
This setting has no effect when the display is explicitly operating in a wide
|
||||||
|
color space.
|
||||||
|
|
||||||
|
The default is `false`.
|
||||||
|
|
||||||
|
|
||||||
Transform:
|
Transform:
|
||||||
|
|
|
||||||
|
|
@ -100,6 +100,11 @@ request set_blend_space (since = 21) {
|
||||||
blend_space: str,
|
blend_space: str,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
request set_use_native_gamut (since = 23) {
|
||||||
|
output: str,
|
||||||
|
use_native_gamut: u32,
|
||||||
|
}
|
||||||
|
|
||||||
# events
|
# events
|
||||||
|
|
||||||
event global {
|
event global {
|
||||||
|
|
@ -210,3 +215,17 @@ event brightness (since = 16) {
|
||||||
event blend_space (since = 21) {
|
event blend_space (since = 21) {
|
||||||
blend_space: str,
|
blend_space: str,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
event native_gamut (since = 23) {
|
||||||
|
r_x: pod(f64),
|
||||||
|
r_y: pod(f64),
|
||||||
|
g_x: pod(f64),
|
||||||
|
g_y: pod(f64),
|
||||||
|
b_x: pod(f64),
|
||||||
|
b_y: pod(f64),
|
||||||
|
w_x: pod(f64),
|
||||||
|
w_y: pod(f64),
|
||||||
|
}
|
||||||
|
|
||||||
|
event use_native_gamut (since = 23) {
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue