config: make the blend space configurable
This commit is contained in:
parent
991b212120
commit
39c770f6e2
20 changed files with 257 additions and 15 deletions
|
|
@ -28,8 +28,8 @@ use {
|
||||||
theme::{Color, colors::Colorable, sized::Resizable},
|
theme::{Color, colors::Colorable, sized::Resizable},
|
||||||
timer::Timer,
|
timer::Timer,
|
||||||
video::{
|
video::{
|
||||||
ColorSpace, Connector, DrmDevice, Eotf, Format, GfxApi, Mode, TearingMode, Transform,
|
BlendSpace, ColorSpace, Connector, DrmDevice, Eotf, Format, GfxApi, Mode, TearingMode,
|
||||||
VrrMode,
|
Transform, VrrMode,
|
||||||
connector_type::{CON_UNKNOWN, ConnectorType},
|
connector_type::{CON_UNKNOWN, ConnectorType},
|
||||||
},
|
},
|
||||||
window::{
|
window::{
|
||||||
|
|
@ -1050,6 +1050,13 @@ impl ConfigClient {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn connector_set_blend_space(&self, connector: Connector, blend_space: BlendSpace) {
|
||||||
|
self.send(&ClientMessage::ConnectorSetBlendSpace {
|
||||||
|
connector,
|
||||||
|
blend_space,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
pub fn connector_set_brightness(&self, connector: Connector, brightness: Option<f64>) {
|
pub fn connector_set_brightness(&self, connector: Connector, brightness: Option<f64>) {
|
||||||
self.send(&ClientMessage::ConnectorSetBrightness {
|
self.send(&ClientMessage::ConnectorSetBrightness {
|
||||||
connector,
|
connector,
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,8 @@ use {
|
||||||
theme::{Color, colors::Colorable, sized::Resizable},
|
theme::{Color, colors::Colorable, sized::Resizable},
|
||||||
timer::Timer,
|
timer::Timer,
|
||||||
video::{
|
video::{
|
||||||
ColorSpace, Connector, DrmDevice, Eotf, Format, GfxApi, TearingMode, Transform,
|
BlendSpace, ColorSpace, Connector, DrmDevice, Eotf, Format, GfxApi, TearingMode,
|
||||||
VrrMode, connector_type::ConnectorType,
|
Transform, VrrMode, connector_type::ConnectorType,
|
||||||
},
|
},
|
||||||
window::{ContentType, TileState, Window, WindowMatcher, WindowType},
|
window::{ContentType, TileState, Window, WindowMatcher, WindowType},
|
||||||
workspace::WorkspaceDisplayOrder,
|
workspace::WorkspaceDisplayOrder,
|
||||||
|
|
@ -764,6 +764,10 @@ pub enum ClientMessage<'a> {
|
||||||
SetWorkspaceDisplayOrder {
|
SetWorkspaceDisplayOrder {
|
||||||
order: WorkspaceDisplayOrder,
|
order: WorkspaceDisplayOrder,
|
||||||
},
|
},
|
||||||
|
ConnectorSetBlendSpace {
|
||||||
|
connector: Connector,
|
||||||
|
blend_space: BlendSpace,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
|
|
||||||
|
|
@ -286,6 +286,13 @@ impl Connector {
|
||||||
get!().connector_set_colors(self, color_space, eotf);
|
get!().connector_set_colors(self, color_space, eotf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets the space in which blending is performed for this output.
|
||||||
|
///
|
||||||
|
/// The default is [`BlendSpace::SRGB`]
|
||||||
|
pub fn set_blend_space(self, blend_space: BlendSpace) {
|
||||||
|
get!().connector_set_blend_space(self, blend_space);
|
||||||
|
}
|
||||||
|
|
||||||
/// Sets the brightness of the output.
|
/// Sets the brightness of the output.
|
||||||
///
|
///
|
||||||
/// By default or when `brightness` is `None`, the brightness depends on the
|
/// By default or when `brightness` is `None`, the brightness depends on the
|
||||||
|
|
@ -731,3 +738,16 @@ impl Eotf {
|
||||||
/// The PQ EOTF.
|
/// The PQ EOTF.
|
||||||
pub const PQ: Self = Self(1);
|
pub const PQ: Self = Self(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A space in which color blending is performed.
|
||||||
|
#[derive(Serialize, Deserialize, Copy, Clone, Debug, Eq, PartialEq, Hash)]
|
||||||
|
pub struct BlendSpace(pub u32);
|
||||||
|
|
||||||
|
impl BlendSpace {
|
||||||
|
/// The sRGB blend space with sRGB primaries and gamma22 transfer function. This is
|
||||||
|
/// the classic desktop blend space.
|
||||||
|
pub const SRGB: Self = Self(0);
|
||||||
|
/// The linear blend space performs blending in linear space, which is more physically
|
||||||
|
/// correct but leads to much lighter output when blending light and dark colors.
|
||||||
|
pub const LINEAR: Self = Self(1);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ use {
|
||||||
AcquireSync, BufferResv, GfxApiOpt, GfxRenderPass, GfxTexture, ReleaseSync, SyncFile,
|
AcquireSync, BufferResv, GfxApiOpt, GfxRenderPass, GfxTexture, ReleaseSync, SyncFile,
|
||||||
create_render_pass,
|
create_render_pass,
|
||||||
},
|
},
|
||||||
|
ifs::wl_output::BlendSpace,
|
||||||
rect::Region,
|
rect::Region,
|
||||||
theme::Color,
|
theme::Color,
|
||||||
time::Time,
|
time::Time,
|
||||||
|
|
@ -201,7 +202,11 @@ impl MetalConnector {
|
||||||
let buffer = &buffers[next_buffer_idx];
|
let buffer = &buffers[next_buffer_idx];
|
||||||
|
|
||||||
let cd = node.global.color_description.get();
|
let cd = node.global.color_description.get();
|
||||||
let blend_cd = self.state.color_manager.srgb_gamma22();
|
let linear_cd = node.global.linear_color_description.get();
|
||||||
|
let blend_cd = match node.global.persistent.blend_space.get() {
|
||||||
|
BlendSpace::Linear => &linear_cd,
|
||||||
|
BlendSpace::Srgb => self.state.color_manager.srgb_gamma22(),
|
||||||
|
};
|
||||||
|
|
||||||
if self.has_damage.get() > 0 || self.cursor_damage.get() {
|
if self.has_damage.get() > 0 || self.cursor_damage.get() {
|
||||||
node.schedule.commit_cursor();
|
node.schedule.commit_cursor();
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ use {
|
||||||
backend::{BackendColorSpace, BackendEotfs},
|
backend::{BackendColorSpace, BackendEotfs},
|
||||||
cli::GlobalArgs,
|
cli::GlobalArgs,
|
||||||
format::{Format, XRGB8888},
|
format::{Format, XRGB8888},
|
||||||
|
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::{errorfmt::ErrorFmt, transform_ext::TransformExt},
|
||||||
|
|
@ -164,6 +165,8 @@ pub enum OutputCommand {
|
||||||
Colors(ColorsSettings),
|
Colors(ColorsSettings),
|
||||||
/// Change the output brightness.
|
/// Change the output brightness.
|
||||||
Brightness(BrightnessArgs),
|
Brightness(BrightnessArgs),
|
||||||
|
/// Change the blend space.
|
||||||
|
BlendSpace(BlendSpaceArgs),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(ValueEnum, Debug, Clone)]
|
#[derive(ValueEnum, Debug, Clone)]
|
||||||
|
|
@ -407,6 +410,26 @@ fn parse_brightness(s: &str) -> Result<Brightness, ParseBrightnessError> {
|
||||||
.map_err(|_| ParseBrightnessError)
|
.map_err(|_| ParseBrightnessError)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Args, Debug, Clone)]
|
||||||
|
pub struct BlendSpaceArgs {
|
||||||
|
/// The space to blend translucent surfaces in.
|
||||||
|
#[clap(value_parser = PossibleValuesParser::new(blend_space_possible_values()))]
|
||||||
|
blend_space: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn blend_space_possible_values() -> Vec<PossibleValue> {
|
||||||
|
let mut res = vec![];
|
||||||
|
for bs in BlendSpace::variants() {
|
||||||
|
use BlendSpace::*;
|
||||||
|
let help = match bs {
|
||||||
|
Linear => "Linear space, more accurate but brighter",
|
||||||
|
Srgb => "sRGB space, the classic desktop blend space",
|
||||||
|
};
|
||||||
|
res.push(PossibleValue::new(bs.name()).help(help));
|
||||||
|
}
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
pub fn main(global: GlobalArgs, args: RandrArgs) {
|
pub fn main(global: GlobalArgs, args: RandrArgs) {
|
||||||
with_tool_client(global.log_level.into(), |tc| async move {
|
with_tool_client(global.log_level.into(), |tc| async move {
|
||||||
let idle = Rc::new(Randr { tc: tc.clone() });
|
let idle = Rc::new(Randr { tc: tc.clone() });
|
||||||
|
|
@ -466,6 +489,7 @@ struct Output {
|
||||||
pub current_eotf: Option<String>,
|
pub current_eotf: Option<String>,
|
||||||
pub brightness_range: Option<(f64, f64)>,
|
pub brightness_range: Option<(f64, f64)>,
|
||||||
pub brightness: Option<f64>,
|
pub brightness: Option<f64>,
|
||||||
|
pub blend_space: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
|
@ -743,6 +767,16 @@ impl Randr {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
OutputCommand::BlendSpace(a) => {
|
||||||
|
self.handle_error(randr, move |msg| {
|
||||||
|
eprintln!("Could not set the blend space: {}", msg);
|
||||||
|
});
|
||||||
|
tc.send(jay_randr::SetBlendSpace {
|
||||||
|
self_id: randr,
|
||||||
|
output: &args.output,
|
||||||
|
blend_space: &a.blend_space,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
tc.round_trip().await;
|
tc.round_trip().await;
|
||||||
}
|
}
|
||||||
|
|
@ -975,6 +1009,9 @@ impl Randr {
|
||||||
if let Some(lux) = o.brightness {
|
if let Some(lux) = o.brightness {
|
||||||
println!(" brightness: {:>10.4} cd/m^2", lux);
|
println!(" brightness: {:>10.4} cd/m^2", lux);
|
||||||
}
|
}
|
||||||
|
if let Some(bs) = &o.blend_space {
|
||||||
|
println!(" blend space: {bs}");
|
||||||
|
}
|
||||||
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 {
|
||||||
|
|
@ -1149,6 +1186,12 @@ impl Randr {
|
||||||
let output = c.output.as_mut().unwrap();
|
let output = c.output.as_mut().unwrap();
|
||||||
output.brightness = Some(msg.lux);
|
output.brightness = Some(msg.lux);
|
||||||
});
|
});
|
||||||
|
jay_randr::BlendSpace::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.blend_space = Some(msg.blend_space.to_string());
|
||||||
|
});
|
||||||
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::{OutputId, PersistentOutputState, WlOutputGlobal},
|
wl_output::{BlendSpace, 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,
|
||||||
|
|
@ -636,6 +636,7 @@ fn create_dummy_output(state: &Rc<State>) {
|
||||||
vrr_cursor_hz: Default::default(),
|
vrr_cursor_hz: Default::default(),
|
||||||
tearing_mode: Cell::new(&TearingMode::Never),
|
tearing_mode: Cell::new(&TearingMode::Never),
|
||||||
brightness: Cell::new(None),
|
brightness: Cell::new(None),
|
||||||
|
blend_space: Cell::new(BlendSpace::Srgb),
|
||||||
});
|
});
|
||||||
let mode = backend::Mode {
|
let mode = backend::Mode {
|
||||||
width: 0,
|
width: 0,
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ use {
|
||||||
},
|
},
|
||||||
format::config_formats,
|
format::config_formats,
|
||||||
ifs::{
|
ifs::{
|
||||||
|
wl_output::BlendSpace,
|
||||||
wl_seat::{SeatId, WlSeatGlobal},
|
wl_seat::{SeatId, WlSeatGlobal},
|
||||||
wp_content_type_v1::ContentTypeExt,
|
wp_content_type_v1::ContentTypeExt,
|
||||||
},
|
},
|
||||||
|
|
@ -69,8 +70,9 @@ use {
|
||||||
theme::{colors::Colorable, sized::Resizable},
|
theme::{colors::Colorable, sized::Resizable},
|
||||||
timer::Timer as JayTimer,
|
timer::Timer as JayTimer,
|
||||||
video::{
|
video::{
|
||||||
ColorSpace, Connector, DrmDevice, Eotf as ConfigEotf, Format as ConfigFormat, GfxApi,
|
BlendSpace as ConfigBlendSpace, ColorSpace, Connector, DrmDevice, Eotf as ConfigEotf,
|
||||||
TearingMode as ConfigTearingMode, Transform, VrrMode as ConfigVrrMode,
|
Format as ConfigFormat, GfxApi, TearingMode as ConfigTearingMode, Transform,
|
||||||
|
VrrMode as ConfigVrrMode,
|
||||||
},
|
},
|
||||||
window::{TileState, Window, WindowMatcher},
|
window::{TileState, Window, WindowMatcher},
|
||||||
workspace::WorkspaceDisplayOrder,
|
workspace::WorkspaceDisplayOrder,
|
||||||
|
|
@ -1306,6 +1308,21 @@ impl ConfigProxyHandler {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle_connector_set_blend_space(
|
||||||
|
&self,
|
||||||
|
connector: Connector,
|
||||||
|
blend_space: ConfigBlendSpace,
|
||||||
|
) -> Result<(), CphError> {
|
||||||
|
let blend_space = match blend_space {
|
||||||
|
ConfigBlendSpace::SRGB => BlendSpace::Srgb,
|
||||||
|
ConfigBlendSpace::LINEAR => BlendSpace::Linear,
|
||||||
|
_ => return Err(CphError::UnknownBlendSpace(blend_space)),
|
||||||
|
};
|
||||||
|
let connector = self.get_output_node(connector)?;
|
||||||
|
connector.set_blend_space(blend_space);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn handle_connector_set_brightness(
|
fn handle_connector_set_brightness(
|
||||||
&self,
|
&self,
|
||||||
connector: Connector,
|
connector: Connector,
|
||||||
|
|
@ -3117,6 +3134,12 @@ impl ConfigProxyHandler {
|
||||||
ClientMessage::SeatCopyMark { seat, src, dst } => self
|
ClientMessage::SeatCopyMark { seat, src, dst } => self
|
||||||
.handle_seat_copy_mark(seat, src, dst)
|
.handle_seat_copy_mark(seat, src, dst)
|
||||||
.wrn("seat_copy_mark")?,
|
.wrn("seat_copy_mark")?,
|
||||||
|
ClientMessage::ConnectorSetBlendSpace {
|
||||||
|
connector,
|
||||||
|
blend_space,
|
||||||
|
} => self
|
||||||
|
.handle_connector_set_blend_space(connector, blend_space)
|
||||||
|
.wrn("connector_set_blend_space")?,
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -3226,6 +3249,8 @@ enum CphError {
|
||||||
WindowMatcherDoesNotExist(WindowMatcher),
|
WindowMatcherDoesNotExist(WindowMatcher),
|
||||||
#[error("Could not modify the connector state")]
|
#[error("Could not modify the connector state")]
|
||||||
ModifyConnectorState(#[source] BackendConnectorTransactionError),
|
ModifyConnectorState(#[source] BackendConnectorTransactionError),
|
||||||
|
#[error("Unknown blend space {0:?}")]
|
||||||
|
UnknownBlendSpace(ConfigBlendSpace),
|
||||||
}
|
}
|
||||||
|
|
||||||
trait WithRequestName {
|
trait WithRequestName {
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,7 @@ impl Global for JayCompositorGlobal {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn version(&self) -> u32 {
|
fn version(&self) -> u32 {
|
||||||
20
|
21
|
||||||
}
|
}
|
||||||
|
|
||||||
fn required_caps(&self) -> ClientCaps {
|
fn required_caps(&self) -> ClientCaps {
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ use {
|
||||||
client::{Client, ClientError},
|
client::{Client, ClientError},
|
||||||
compositor::MAX_EXTENTS,
|
compositor::MAX_EXTENTS,
|
||||||
format::named_formats,
|
format::named_formats,
|
||||||
|
ifs::wl_output,
|
||||||
leaks::Tracker,
|
leaks::Tracker,
|
||||||
object::{Object, Version},
|
object::{Object, Version},
|
||||||
scale::Scale,
|
scale::Scale,
|
||||||
|
|
@ -34,6 +35,7 @@ const FORMAT_SINCE: Version = Version(8);
|
||||||
const FLIP_MARGIN_SINCE: Version = Version(10);
|
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);
|
||||||
|
|
||||||
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 {
|
||||||
|
|
@ -207,6 +209,12 @@ impl JayRandr {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if self.version >= BLEND_SPACE_SINCE {
|
||||||
|
self.client.event(BlendSpace {
|
||||||
|
self_id: self.id,
|
||||||
|
blend_space: node.global.persistent.blend_space.get().name(),
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_error(&self, msg: &str) {
|
fn send_error(&self, msg: &str) {
|
||||||
|
|
@ -526,6 +534,23 @@ impl JayRandrRequestHandler for JayRandr {
|
||||||
c.set_brightness(None);
|
c.set_brightness(None);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn set_blend_space(&self, req: SetBlendSpace<'_>, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
let space = 'space: {
|
||||||
|
for space in wl_output::BlendSpace::variants() {
|
||||||
|
if space.name() == req.blend_space {
|
||||||
|
break 'space space;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.send_error(&format!("Unknown blend space: {}", req.blend_space));
|
||||||
|
return Ok(());
|
||||||
|
};
|
||||||
|
let Some(c) = self.get_output_node(req.output) else {
|
||||||
|
return Ok(());
|
||||||
|
};
|
||||||
|
c.set_blend_space(space);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object_base! {
|
object_base! {
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ use {
|
||||||
},
|
},
|
||||||
ahash::AHashMap,
|
ahash::AHashMap,
|
||||||
jay_config::video::Transform,
|
jay_config::video::Transform,
|
||||||
|
linearize::Linearize,
|
||||||
std::{
|
std::{
|
||||||
cell::{Cell, RefCell},
|
cell::{Cell, RefCell},
|
||||||
collections::hash_map::Entry,
|
collections::hash_map::Entry,
|
||||||
|
|
@ -115,6 +116,21 @@ impl OutputGlobalOpt {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, Eq, PartialEq, Linearize)]
|
||||||
|
pub enum BlendSpace {
|
||||||
|
Linear,
|
||||||
|
Srgb,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BlendSpace {
|
||||||
|
pub fn name(self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
BlendSpace::Linear => "linear",
|
||||||
|
BlendSpace::Srgb => "srgb",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct PersistentOutputState {
|
pub struct PersistentOutputState {
|
||||||
pub transform: Cell<Transform>,
|
pub transform: Cell<Transform>,
|
||||||
pub scale: Cell<crate::scale::Scale>,
|
pub scale: Cell<crate::scale::Scale>,
|
||||||
|
|
@ -123,6 +139,7 @@ pub struct PersistentOutputState {
|
||||||
pub vrr_cursor_hz: Cell<Option<f64>>,
|
pub vrr_cursor_hz: Cell<Option<f64>>,
|
||||||
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>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for PersistentOutputState {
|
impl Default for PersistentOutputState {
|
||||||
|
|
@ -135,6 +152,7 @@ impl Default for PersistentOutputState {
|
||||||
vrr_cursor_hz: Default::default(),
|
vrr_cursor_hz: Default::default(),
|
||||||
tearing_mode: Cell::new(&TearingMode::Never),
|
tearing_mode: Cell::new(&TearingMode::Never),
|
||||||
brightness: Default::default(),
|
brightness: Default::default(),
|
||||||
|
blend_space: Cell::new(BlendSpace::Srgb),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ use {
|
||||||
ifs::{
|
ifs::{
|
||||||
head_management::{HeadManagers, HeadState},
|
head_management::{HeadManagers, HeadState},
|
||||||
jay_tray_v1::JayTrayV1Global,
|
jay_tray_v1::JayTrayV1Global,
|
||||||
wl_output::{PersistentOutputState, WlOutputGlobal},
|
wl_output::{BlendSpace, PersistentOutputState, WlOutputGlobal},
|
||||||
},
|
},
|
||||||
output_schedule::OutputSchedule,
|
output_schedule::OutputSchedule,
|
||||||
state::{ConnectorData, OutputData, State},
|
state::{ConnectorData, OutputData, State},
|
||||||
|
|
@ -183,6 +183,7 @@ impl ConnectorHandler {
|
||||||
vrr_cursor_hz: Cell::new(self.state.default_vrr_cursor_hz.get()),
|
vrr_cursor_hz: Cell::new(self.state.default_vrr_cursor_hz.get()),
|
||||||
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),
|
||||||
});
|
});
|
||||||
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(20),
|
version: s.jay_compositor.1.min(21),
|
||||||
id: id.into(),
|
id: id.into(),
|
||||||
});
|
});
|
||||||
self.jay_compositor.set(Some(id));
|
self.jay_compositor.set(Some(id));
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ use {
|
||||||
jay_output::JayOutput,
|
jay_output::JayOutput,
|
||||||
jay_screencast::JayScreencast,
|
jay_screencast::JayScreencast,
|
||||||
wl_buffer::WlBufferStorage,
|
wl_buffer::WlBufferStorage,
|
||||||
wl_output::WlOutputGlobal,
|
wl_output::{BlendSpace, WlOutputGlobal},
|
||||||
wl_seat::{
|
wl_seat::{
|
||||||
BTN_LEFT, NodeSeatState, SeatId, WlSeatGlobal, collect_kb_foci2,
|
BTN_LEFT, NodeSeatState, SeatId, WlSeatGlobal, collect_kb_foci2,
|
||||||
tablet::{TabletTool, TabletToolChanges, TabletToolId},
|
tablet::{TabletTool, TabletToolChanges, TabletToolId},
|
||||||
|
|
@ -971,6 +971,12 @@ impl OutputNode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_blend_space(&self, blend_space: BlendSpace) {
|
||||||
|
let old = self.global.persistent.blend_space.replace(blend_space);
|
||||||
|
if old != blend_space {
|
||||||
|
self.state.damage(self.global.position());
|
||||||
|
}
|
||||||
|
}
|
||||||
fn find_stacked_at(
|
fn find_stacked_at(
|
||||||
&self,
|
&self,
|
||||||
stack: &LinkedList<Rc<dyn StackedNode>>,
|
stack: &LinkedList<Rc<dyn StackedNode>>,
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ use {
|
||||||
logging::LogLevel,
|
logging::LogLevel,
|
||||||
status::MessageFormat,
|
status::MessageFormat,
|
||||||
theme::Color,
|
theme::Color,
|
||||||
video::{ColorSpace, Eotf, Format, GfxApi, TearingMode, Transform, VrrMode},
|
video::{BlendSpace, ColorSpace, Eotf, Format, GfxApi, TearingMode, Transform, VrrMode},
|
||||||
window::{ContentType, TileState, WindowType},
|
window::{ContentType, TileState, WindowType},
|
||||||
workspace::WorkspaceDisplayOrder,
|
workspace::WorkspaceDisplayOrder,
|
||||||
xwayland::XScalingMode,
|
xwayland::XScalingMode,
|
||||||
|
|
@ -349,6 +349,7 @@ pub struct Output {
|
||||||
pub color_space: Option<ColorSpace>,
|
pub color_space: Option<ColorSpace>,
|
||||||
pub eotf: Option<Eotf>,
|
pub eotf: Option<Eotf>,
|
||||||
pub brightness: Option<Option<f64>>,
|
pub brightness: Option<Option<f64>>,
|
||||||
|
pub blend_space: Option<BlendSpace>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ use {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
indexmap::IndexMap,
|
indexmap::IndexMap,
|
||||||
jay_config::video::{ColorSpace, Eotf, Transform},
|
jay_config::video::{BlendSpace, ColorSpace, Eotf, Transform},
|
||||||
thiserror::Error,
|
thiserror::Error,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -51,7 +51,7 @@ impl Parser for OutputParser<'_> {
|
||||||
let mut ext = Extractor::new(self.cx, span, table);
|
let mut ext = Extractor::new(self.cx, span, table);
|
||||||
let (
|
let (
|
||||||
(name, match_val, x, y, scale, transform, mode, vrr_val, tearing_val, format_val),
|
(name, match_val, x, y, scale, transform, mode, vrr_val, tearing_val, format_val),
|
||||||
(color_space, eotf, brightness_val),
|
(color_space, eotf, brightness_val, blend_space),
|
||||||
) = ext.extract((
|
) = ext.extract((
|
||||||
(
|
(
|
||||||
opt(str("name")),
|
opt(str("name")),
|
||||||
|
|
@ -69,6 +69,7 @@ impl Parser for OutputParser<'_> {
|
||||||
recover(opt(str("color-space"))),
|
recover(opt(str("color-space"))),
|
||||||
recover(opt(str("transfer-function"))),
|
recover(opt(str("transfer-function"))),
|
||||||
opt(val("brightness")),
|
opt(val("brightness")),
|
||||||
|
recover(opt(str("blend-space"))),
|
||||||
),
|
),
|
||||||
))?;
|
))?;
|
||||||
let transform = match transform {
|
let transform = match transform {
|
||||||
|
|
@ -177,6 +178,21 @@ impl Parser for OutputParser<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
let blend_space = match blend_space {
|
||||||
|
None => None,
|
||||||
|
Some(bs) => match bs.value {
|
||||||
|
"linear" => Some(BlendSpace::LINEAR),
|
||||||
|
"srgb" => Some(BlendSpace::SRGB),
|
||||||
|
_ => {
|
||||||
|
log::warn!(
|
||||||
|
"Unknown blend space {}: {}",
|
||||||
|
bs.value,
|
||||||
|
self.cx.error3(bs.span)
|
||||||
|
);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
Ok(Output {
|
Ok(Output {
|
||||||
name: name.despan().map(|v| v.to_string()),
|
name: name.despan().map(|v| v.to_string()),
|
||||||
match_: match_val.parse_map(&mut OutputMatchParser(self.cx))?,
|
match_: match_val.parse_map(&mut OutputMatchParser(self.cx))?,
|
||||||
|
|
@ -191,6 +207,7 @@ impl Parser for OutputParser<'_> {
|
||||||
color_space,
|
color_space,
|
||||||
eotf,
|
eotf,
|
||||||
brightness,
|
brightness,
|
||||||
|
blend_space,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -777,6 +777,9 @@ impl Output {
|
||||||
if let Some(brightness) = self.brightness {
|
if let Some(brightness) = self.brightness {
|
||||||
c.set_brightness(brightness);
|
c.set_brightness(brightness);
|
||||||
}
|
}
|
||||||
|
if let Some(bs) = self.blend_space {
|
||||||
|
c.set_blend_space(bs);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -572,6 +572,14 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"BlendSpace": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "A color blend space.\n",
|
||||||
|
"enum": [
|
||||||
|
"srgb",
|
||||||
|
"linear"
|
||||||
|
]
|
||||||
|
},
|
||||||
"Brightness": {
|
"Brightness": {
|
||||||
"description": "The brightness setting of an output.\n",
|
"description": "The brightness setting of an output.\n",
|
||||||
"anyOf": [
|
"anyOf": [
|
||||||
|
|
@ -1655,6 +1663,10 @@
|
||||||
"brightness": {
|
"brightness": {
|
||||||
"description": "The brightness of the output.\n\nThis setting has no effect unless the vulkan renderer is used.\n",
|
"description": "The brightness of the output.\n\nThis setting has no effect unless the vulkan renderer is used.\n",
|
||||||
"$ref": "#/$defs/Brightness"
|
"$ref": "#/$defs/Brightness"
|
||||||
|
},
|
||||||
|
"blend-space": {
|
||||||
|
"description": "The blend space of the output.\n\nThe default is `srgb`.\n",
|
||||||
|
"$ref": "#/$defs/BlendSpace"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": [
|
||||||
|
|
|
||||||
|
|
@ -797,6 +797,25 @@ This table is a tagged union. The variant is determined by the `type` field. It
|
||||||
The value of this field should be a string.
|
The value of this field should be a string.
|
||||||
|
|
||||||
|
|
||||||
|
<a name="types-BlendSpace"></a>
|
||||||
|
### `BlendSpace`
|
||||||
|
|
||||||
|
A color blend space.
|
||||||
|
|
||||||
|
Values of this type should be strings.
|
||||||
|
|
||||||
|
The string should have one of the following values:
|
||||||
|
|
||||||
|
- `srgb`:
|
||||||
|
|
||||||
|
The sRGB blend space. This is the classic desktop blend space.
|
||||||
|
|
||||||
|
- `linear`:
|
||||||
|
|
||||||
|
Linear color space. This is the physically correct blend space.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a name="types-Brightness"></a>
|
<a name="types-Brightness"></a>
|
||||||
### `Brightness`
|
### `Brightness`
|
||||||
|
|
||||||
|
|
@ -3548,6 +3567,14 @@ The table has the following fields:
|
||||||
|
|
||||||
The value of this field should be a [Brightness](#types-Brightness).
|
The value of this field should be a [Brightness](#types-Brightness).
|
||||||
|
|
||||||
|
- `blend-space` (optional):
|
||||||
|
|
||||||
|
The blend space of the output.
|
||||||
|
|
||||||
|
The default is `srgb`.
|
||||||
|
|
||||||
|
The value of this field should be a [BlendSpace](#types-BlendSpace).
|
||||||
|
|
||||||
|
|
||||||
<a name="types-OutputMatch"></a>
|
<a name="types-OutputMatch"></a>
|
||||||
### `OutputMatch`
|
### `OutputMatch`
|
||||||
|
|
|
||||||
|
|
@ -1967,6 +1967,13 @@ Output:
|
||||||
The brightness of the output.
|
The brightness of the output.
|
||||||
|
|
||||||
This setting has no effect unless the vulkan renderer is used.
|
This setting has no effect unless the vulkan renderer is used.
|
||||||
|
blend-space:
|
||||||
|
ref: BlendSpace
|
||||||
|
required: false
|
||||||
|
description: |
|
||||||
|
The blend space of the output.
|
||||||
|
|
||||||
|
The default is `srgb`.
|
||||||
|
|
||||||
|
|
||||||
Transform:
|
Transform:
|
||||||
|
|
@ -4029,3 +4036,14 @@ WorkspaceDisplayOrder:
|
||||||
description: Workspaces are not sorted and can be manually dragged.
|
description: Workspaces are not sorted and can be manually dragged.
|
||||||
- value: sorted
|
- value: sorted
|
||||||
description: Workspaces are sorted alphabetically and cannot be manually dragged.
|
description: Workspaces are sorted alphabetically and cannot be manually dragged.
|
||||||
|
|
||||||
|
|
||||||
|
BlendSpace:
|
||||||
|
kind: string
|
||||||
|
description: |
|
||||||
|
A color blend space.
|
||||||
|
values:
|
||||||
|
- value: srgb
|
||||||
|
description: The sRGB blend space. This is the classic desktop blend space.
|
||||||
|
- value: linear
|
||||||
|
description: Linear color space. This is the physically correct blend space.
|
||||||
|
|
|
||||||
|
|
@ -95,6 +95,11 @@ request unset_brightness (since = 16) {
|
||||||
output: str,
|
output: str,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
request set_blend_space (since = 21) {
|
||||||
|
output: str,
|
||||||
|
blend_space: str,
|
||||||
|
}
|
||||||
|
|
||||||
# events
|
# events
|
||||||
|
|
||||||
event global {
|
event global {
|
||||||
|
|
@ -201,3 +206,7 @@ event brightness_range (since = 16) {
|
||||||
event brightness (since = 16) {
|
event brightness (since = 16) {
|
||||||
lux: pod(f64),
|
lux: pod(f64),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
event blend_space (since = 21) {
|
||||||
|
blend_space: str,
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue