Merge pull request #593 from mahkoh/jorth/color-management-fixes
Various color management fixes
This commit is contained in:
commit
0e51b9469b
75 changed files with 893 additions and 784 deletions
|
|
@ -28,7 +28,7 @@ use {
|
|||
theme::{Color, colors::Colorable, sized::Resizable},
|
||||
timer::Timer,
|
||||
video::{
|
||||
ColorSpace, Connector, DrmDevice, Format, GfxApi, Mode, TearingMode, TransferFunction,
|
||||
BlendSpace, ColorSpace, Connector, DrmDevice, Eotf, Format, GfxApi, Mode, TearingMode,
|
||||
Transform, VrrMode,
|
||||
connector_type::{CON_UNKNOWN, ConnectorType},
|
||||
},
|
||||
|
|
@ -1042,16 +1042,18 @@ 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,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn connector_set_blend_space(&self, connector: Connector, blend_space: BlendSpace) {
|
||||
self.send(&ClientMessage::ConnectorSetBlendSpace {
|
||||
connector,
|
||||
blend_space,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ use {
|
|||
theme::{Color, colors::Colorable, sized::Resizable},
|
||||
timer::Timer,
|
||||
video::{
|
||||
ColorSpace, Connector, DrmDevice, Format, GfxApi, TearingMode, TransferFunction,
|
||||
BlendSpace, ColorSpace, Connector, DrmDevice, Eotf, Format, GfxApi, TearingMode,
|
||||
Transform, VrrMode, connector_type::ConnectorType,
|
||||
},
|
||||
window::{ContentType, TileState, Window, WindowMatcher, WindowType},
|
||||
|
|
@ -555,7 +555,7 @@ pub enum ClientMessage<'a> {
|
|||
ConnectorSetColors {
|
||||
connector: Connector,
|
||||
color_space: ColorSpace,
|
||||
transfer_function: TransferFunction,
|
||||
eotf: Eotf,
|
||||
},
|
||||
ConnectorSetBrightness {
|
||||
connector: Connector,
|
||||
|
|
@ -764,6 +764,10 @@ pub enum ClientMessage<'a> {
|
|||
SetWorkspaceDisplayOrder {
|
||||
order: WorkspaceDisplayOrder,
|
||||
},
|
||||
ConnectorSetBlendSpace {
|
||||
connector: Connector,
|
||||
blend_space: BlendSpace,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
|
|
|
|||
|
|
@ -273,26 +273,33 @@ 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 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.
|
||||
///
|
||||
/// 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 +725,29 @@ 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);
|
||||
}
|
||||
|
||||
/// 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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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")]
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ use {
|
|||
AcquireSync, BufferResv, GfxApiOpt, GfxRenderPass, GfxTexture, ReleaseSync, SyncFile,
|
||||
create_render_pass,
|
||||
},
|
||||
ifs::wl_output::BlendSpace,
|
||||
rect::Region,
|
||||
theme::Color,
|
||||
time::Time,
|
||||
|
|
@ -202,6 +203,10 @@ impl MetalConnector {
|
|||
|
||||
let cd = node.global.color_description.get();
|
||||
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() {
|
||||
node.schedule.commit_cursor();
|
||||
|
|
@ -218,7 +223,7 @@ impl MetalConnector {
|
|||
let mut present_fb = None;
|
||||
let mut direct_scanout_id = None;
|
||||
if let Some(latched) = &latched {
|
||||
let fb = self.prepare_present_fb(&cd, &linear_cd, buffer, &plane, latched, true)?;
|
||||
let fb = self.prepare_present_fb(&cd, blend_cd, buffer, &plane, latched, true)?;
|
||||
direct_scanout_id = fb.direct_scanout_data.as_ref().map(|d| d.dma_buf_id);
|
||||
present_fb = Some(fb);
|
||||
}
|
||||
|
|
@ -247,7 +252,7 @@ impl MetalConnector {
|
|||
{
|
||||
let fb = self.prepare_present_fb(
|
||||
&cd,
|
||||
&linear_cd,
|
||||
blend_cd,
|
||||
buffer,
|
||||
&plane,
|
||||
latched.as_ref().unwrap(),
|
||||
|
|
@ -621,6 +626,7 @@ impl MetalConnector {
|
|||
&self,
|
||||
pass: &GfxRenderPass,
|
||||
plane: &Rc<MetalPlane>,
|
||||
blend_cd: &Rc<ColorDescription>,
|
||||
cd: &Rc<ColorDescription>,
|
||||
) -> Option<DirectScanoutData> {
|
||||
let ct = 'ct: {
|
||||
|
|
@ -642,6 +648,10 @@ impl MetalConnector {
|
|||
// Direct scanout requires embeddable color descriptions.
|
||||
return None;
|
||||
}
|
||||
if !ct.opaque && !ct.cd.embeds_into(blend_cd) {
|
||||
// Blending changes the appearance of translucent buffers.
|
||||
return None;
|
||||
}
|
||||
if ct.alpha.is_some() {
|
||||
// Direct scanout with alpha factor is not supported.
|
||||
return None;
|
||||
|
|
@ -796,7 +806,7 @@ impl MetalConnector {
|
|||
fn prepare_present_fb(
|
||||
&self,
|
||||
cd: &Rc<ColorDescription>,
|
||||
linear_cd: &Rc<ColorDescription>,
|
||||
blend_cd: &Rc<ColorDescription>,
|
||||
buffer: &RenderBuffer,
|
||||
plane: &Rc<MetalPlane>,
|
||||
latched: &Latched,
|
||||
|
|
@ -813,7 +823,7 @@ impl MetalConnector {
|
|||
&& self.dev.is_render_device();
|
||||
let mut direct_scanout_data = None;
|
||||
if try_direct_scanout {
|
||||
direct_scanout_data = self.prepare_direct_scanout(&latched.pass, plane, cd);
|
||||
direct_scanout_data = self.prepare_direct_scanout(&latched.pass, plane, blend_cd, cd);
|
||||
}
|
||||
let direct_scanout_active = direct_scanout_data.is_some();
|
||||
if self.direct_scanout_active.replace(direct_scanout_active) != direct_scanout_active {
|
||||
|
|
@ -837,7 +847,7 @@ impl MetalConnector {
|
|||
&latched.pass,
|
||||
&latched.damage,
|
||||
buffer.blend_buffer.as_ref(),
|
||||
linear_cd,
|
||||
blend_cd,
|
||||
)
|
||||
.map_err(MetalError::RenderFrame)?;
|
||||
sync_file = buffer.copy_to_dev(cd, sf)?;
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
|
|
|
|||
|
|
@ -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::Srgb);
|
||||
let [r, g, b, a] = color.to_array(Eotf::Gamma22);
|
||||
tc.send(SetVisualizerColor {
|
||||
self_id: dt,
|
||||
r,
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
use {
|
||||
crate::{
|
||||
backend::{BackendColorSpace, BackendTransferFunction},
|
||||
backend::{BackendColorSpace, BackendEotfs},
|
||||
cli::GlobalArgs,
|
||||
format::{Format, XRGB8888},
|
||||
ifs::wl_output::BlendSpace,
|
||||
scale::Scale,
|
||||
tools::tool_client::{Handle, ToolClient, with_tool_client},
|
||||
utils::{errorfmt::ErrorFmt, transform_ext::TransformExt},
|
||||
|
|
@ -164,6 +165,8 @@ pub enum OutputCommand {
|
|||
Colors(ColorsSettings),
|
||||
/// Change the output brightness.
|
||||
Brightness(BrightnessArgs),
|
||||
/// Change the blend space.
|
||||
BlendSpace(BlendSpaceArgs),
|
||||
}
|
||||
|
||||
#[derive(ValueEnum, Debug, Clone)]
|
||||
|
|
@ -333,14 +336,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 +360,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 +378,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.
|
||||
|
|
@ -407,6 +410,26 @@ fn parse_brightness(s: &str) -> Result<Brightness, 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) {
|
||||
with_tool_client(global.log_level.into(), |tc| async move {
|
||||
let idle = Rc::new(Randr { tc: tc.clone() });
|
||||
|
|
@ -462,10 +485,11 @@ 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>,
|
||||
pub blend_space: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
|
|
@ -713,15 +737,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,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -746,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;
|
||||
}
|
||||
|
|
@ -957,19 +988,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);
|
||||
|
|
@ -980,6 +1009,9 @@ impl Randr {
|
|||
if let Some(lux) = o.brightness {
|
||||
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 {
|
||||
println!(" modes:");
|
||||
for mode in &o.modes {
|
||||
|
|
@ -1130,19 +1162,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();
|
||||
|
|
@ -1156,6 +1186,12 @@ impl Randr {
|
|||
let output = c.output.as_mut().unwrap();
|
||||
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;
|
||||
data.borrow_mut().clone()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,15 +1,13 @@
|
|||
use linearize::Linearize;
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Linearize)]
|
||||
pub enum TransferFunction {
|
||||
Srgb,
|
||||
pub enum Eotf {
|
||||
Linear,
|
||||
St2084Pq,
|
||||
Bt1886,
|
||||
Gamma22,
|
||||
Gamma28,
|
||||
St240,
|
||||
ExtSrgb,
|
||||
Log100,
|
||||
Log316,
|
||||
St428,
|
||||
|
|
@ -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::Srgb,
|
||||
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));
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ use {
|
|||
HeadManagers, HeadState, jay_head_manager_session_v1::handle_jay_head_manager_done,
|
||||
},
|
||||
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_surface::{
|
||||
NoneSurfaceExt, xdg_surface::handle_xdg_surface_configure_events,
|
||||
|
|
@ -636,6 +636,7 @@ fn create_dummy_output(state: &Rc<State>) {
|
|||
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 {
|
||||
width: 0,
|
||||
|
|
@ -652,7 +653,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 +681,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,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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::{
|
||||
|
|
@ -17,6 +17,7 @@ use {
|
|||
},
|
||||
format::config_formats,
|
||||
ifs::{
|
||||
wl_output::BlendSpace,
|
||||
wl_seat::{SeatId, WlSeatGlobal},
|
||||
wp_content_type_v1::ContentTypeExt,
|
||||
},
|
||||
|
|
@ -69,9 +70,9 @@ 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,
|
||||
BlendSpace as ConfigBlendSpace, ColorSpace, Connector, DrmDevice, Eotf as ConfigEotf,
|
||||
Format as ConfigFormat, GfxApi, TearingMode as ConfigTearingMode, Transform,
|
||||
VrrMode as ConfigVrrMode,
|
||||
},
|
||||
window::{TileState, Window, WindowMatcher},
|
||||
workspace::WorkspaceDisplayOrder,
|
||||
|
|
@ -1285,28 +1286,43 @@ 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(())
|
||||
}
|
||||
|
||||
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(
|
||||
&self,
|
||||
connector: Connector,
|
||||
|
|
@ -2365,7 +2381,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::Srgb);
|
||||
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 +2946,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,
|
||||
|
|
@ -3118,6 +3134,12 @@ impl ConfigProxyHandler {
|
|||
ClientMessage::SeatCopyMark { seat, src, dst } => self
|
||||
.handle_seat_copy_mark(seat, src, dst)
|
||||
.wrn("seat_copy_mark")?,
|
||||
ClientMessage::ConnectorSetBlendSpace {
|
||||
connector,
|
||||
blend_space,
|
||||
} => self
|
||||
.handle_connector_set_blend_space(connector, blend_space)
|
||||
.wrn("connector_set_blend_space")?,
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -3211,8 +3233,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")]
|
||||
|
|
@ -3227,6 +3249,8 @@ enum CphError {
|
|||
WindowMatcherDoesNotExist(WindowMatcher),
|
||||
#[error("Could not modify the connector state")]
|
||||
ModifyConnectorState(#[source] BackendConnectorTransactionError),
|
||||
#[error("Unknown blend space {0:?}")]
|
||||
UnknownBlendSpace(ConfigBlendSpace),
|
||||
}
|
||||
|
||||
trait WithRequestName {
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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::Srgb);
|
||||
let [r, g, b, a] = color.to_array(Eotf::Gamma22);
|
||||
let gles = ctx.ctx.dpy.gles;
|
||||
unsafe {
|
||||
(gles.glUseProgram)(ctx.fill_prog.prog);
|
||||
|
|
|
|||
|
|
@ -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::Srgb);
|
||||
let [r, g, b, a] = c.to_array(Eotf::Gamma22);
|
||||
(gles.glClearColor)(r, g, b, a);
|
||||
(gles.glClear)(GL_COLOR_BUFFER_BIT);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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::{
|
||||
|
|
|
|||
|
|
@ -120,33 +120,6 @@ impl VulkanDevice {
|
|||
}))
|
||||
}
|
||||
|
||||
pub(super) fn create_out_descriptor_set_layout(
|
||||
self: &Rc<Self>,
|
||||
db: &descriptor_buffer::Device,
|
||||
) -> Result<Rc<VulkanDescriptorSetLayout>, VulkanError> {
|
||||
let binding = DescriptorSetLayoutBinding::default()
|
||||
.stage_flags(ShaderStageFlags::FRAGMENT)
|
||||
.descriptor_count(1)
|
||||
.descriptor_type(DescriptorType::SAMPLED_IMAGE);
|
||||
let create_info = DescriptorSetLayoutCreateInfo::default()
|
||||
.bindings(slice::from_ref(&binding))
|
||||
.flags(DescriptorSetLayoutCreateFlags::DESCRIPTOR_BUFFER_EXT);
|
||||
let layout = unsafe { self.device.create_descriptor_set_layout(&create_info, None) };
|
||||
let layout = layout.map_err(VulkanError::CreateDescriptorSetLayout)?;
|
||||
let size = self.get_descriptor_set_size(db, layout);
|
||||
let mut offsets = ArrayVec::new();
|
||||
unsafe {
|
||||
offsets.push(db.get_descriptor_set_layout_binding_offset(layout, 0));
|
||||
}
|
||||
Ok(Rc::new(VulkanDescriptorSetLayout {
|
||||
device: self.clone(),
|
||||
layout,
|
||||
size,
|
||||
offsets,
|
||||
_sampler: None,
|
||||
}))
|
||||
}
|
||||
|
||||
fn get_descriptor_set_size(
|
||||
&self,
|
||||
db: &descriptor_buffer::Device,
|
||||
|
|
|
|||
31
src/gfx_apis/vulkan/eotfs.rs
Normal file
31
src/gfx_apis/vulkan/eotfs.rs
Normal 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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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},
|
||||
|
|
@ -27,10 +28,9 @@ use {
|
|||
shaders::{
|
||||
FILL_FRAG, FILL_VERT, FillPushConstants, LEGACY_FILL_FRAG, LEGACY_FILL_VERT,
|
||||
LEGACY_TEX_FRAG, LEGACY_TEX_VERT, LegacyFillPushConstants, LegacyTexPushConstants,
|
||||
OUT_FRAG, OUT_VERT, OutPushConstants, TEX_FRAG, TEX_VERT, TexColorManagementData,
|
||||
TexPushConstants, TexVertex, VulkanShader,
|
||||
OUT_FRAG, OUT_VERT, OutColorManagementData, 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>>,
|
||||
|
|
@ -181,6 +179,7 @@ pub(super) struct Memory {
|
|||
uniform_buffer_writer: GenericBufferWriter,
|
||||
uniform_buffer_descriptor_cache: Option<Box<[u8]>>,
|
||||
blend_buffer_descriptor_buffer_offset: DeviceAddress,
|
||||
blend_buffer_color_management_data_address: Option<DeviceSize>,
|
||||
}
|
||||
|
||||
type Point = [[f32; 2]; 4];
|
||||
|
|
@ -247,20 +246,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 {
|
||||
|
|
@ -300,7 +299,7 @@ impl VulkanDevice {
|
|||
let out_descriptor_set_layout = self
|
||||
.descriptor_buffer
|
||||
.as_ref()
|
||||
.map(|db| self.create_out_descriptor_set_layout(db))
|
||||
.map(|_| self.create_tex_resource_descriptor_set_layout())
|
||||
.transpose()?;
|
||||
let gfx_command_buffers = self.create_command_pool(self.graphics_queue_idx)?;
|
||||
let transfer_command_buffers = self
|
||||
|
|
@ -417,8 +416,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 +436,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 +462,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 +489,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,
|
||||
};
|
||||
|
|
@ -504,12 +503,13 @@ impl VulkanRenderer {
|
|||
format: vk::Format,
|
||||
bb_cd: &ColorDescription,
|
||||
fb_cd: &ColorDescription,
|
||||
has_color_management_data: bool,
|
||||
) -> 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,9 +525,9 @@ 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,
|
||||
has_color_management_data,
|
||||
})?;
|
||||
pipelines.set(key, out.clone());
|
||||
Ok(out)
|
||||
|
|
@ -568,6 +568,20 @@ impl VulkanRenderer {
|
|||
memory.blend_buffer_descriptor_buffer_offset = resource_writer.next_offset();
|
||||
let mut writer = resource_writer.add_set(layout);
|
||||
writer.write(layout.offsets[0], &bb.sampled_image_descriptor);
|
||||
if let Some(addr) = memory.blend_buffer_color_management_data_address {
|
||||
let uniform_buffer = DescriptorAddressInfoEXT::default()
|
||||
.address(addr)
|
||||
.range(size_of::<OutColorManagementData>() as _);
|
||||
let info = DescriptorGetInfoEXT::default()
|
||||
.ty(DescriptorType::UNIFORM_BUFFER)
|
||||
.data(DescriptorDataEXT {
|
||||
p_uniform_buffer: &uniform_buffer,
|
||||
});
|
||||
unsafe {
|
||||
db.get_descriptor(&info, uniform_buffer_descriptor_cache);
|
||||
}
|
||||
writer.write(layout.offsets[1], uniform_buffer_descriptor_cache);
|
||||
}
|
||||
}
|
||||
let tex_descriptor_set_layout = &self.tex_descriptor_set_layouts[1];
|
||||
for pass in RenderPass::variants() {
|
||||
|
|
@ -725,7 +739,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);
|
||||
|
|
@ -818,6 +832,26 @@ impl VulkanRenderer {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn create_blend_cm_data(
|
||||
&self,
|
||||
bb: Option<&VulkanImage>,
|
||||
bb_cd: &ColorDescription,
|
||||
fb_cd: &ColorDescription,
|
||||
) {
|
||||
zone!("create_blend_cm_data");
|
||||
let memory = &mut *self.memory.borrow_mut();
|
||||
memory.blend_buffer_color_management_data_address = None;
|
||||
if bb.is_none() {
|
||||
return;
|
||||
}
|
||||
memory.blend_buffer_color_management_data_address = memory.color_transforms.get_offset(
|
||||
&bb_cd.linear,
|
||||
fb_cd,
|
||||
self.device.uniform_buffer_offset_mask,
|
||||
&mut memory.uniform_buffer_writer,
|
||||
);
|
||||
}
|
||||
|
||||
fn create_data_buffer(&self) -> Result<(), VulkanError> {
|
||||
if self.device.descriptor_buffer.is_none() {
|
||||
return Ok(());
|
||||
|
|
@ -883,6 +917,9 @@ impl VulkanRenderer {
|
|||
}
|
||||
}
|
||||
}
|
||||
if let Some(addr) = &mut memory.blend_buffer_color_management_data_address {
|
||||
*addr += buffer.buffer.address;
|
||||
}
|
||||
memory.used_buffers.push(buffer);
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -1047,7 +1084,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 && {
|
||||
|
|
@ -1299,7 +1336,12 @@ impl VulkanRenderer {
|
|||
zone!("blend_buffer_copy");
|
||||
let memory = &*self.memory.borrow();
|
||||
let db = self.device.descriptor_buffer.as_ref().unwrap();
|
||||
let pipeline = self.get_or_create_out_pipeline(fb.format.vk_format, bb_cd, fb_cd)?;
|
||||
let pipeline = self.get_or_create_out_pipeline(
|
||||
fb.format.vk_format,
|
||||
bb_cd,
|
||||
fb_cd,
|
||||
memory.blend_buffer_color_management_data_address.is_some(),
|
||||
)?;
|
||||
let push = OutPushConstants {
|
||||
vertices: memory.out_address,
|
||||
};
|
||||
|
|
@ -1852,7 +1894,21 @@ impl VulkanRenderer {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn elide_blend_buffer(&self, blend_buffer: &mut Option<Rc<VulkanImage>>) {
|
||||
fn elide_blend_buffer1(
|
||||
&self,
|
||||
blend_buffer: &mut Option<Rc<VulkanImage>>,
|
||||
bb_cd: &ColorDescription,
|
||||
fb_cd: &ColorDescription,
|
||||
) {
|
||||
if blend_buffer.is_none() {
|
||||
return;
|
||||
}
|
||||
if bb_cd.embeds_into(fb_cd) {
|
||||
*blend_buffer = None;
|
||||
}
|
||||
}
|
||||
|
||||
fn elide_blend_buffer2(&self, blend_buffer: &mut Option<Rc<VulkanImage>>) {
|
||||
if blend_buffer.is_none() {
|
||||
return;
|
||||
}
|
||||
|
|
@ -1876,11 +1932,13 @@ impl VulkanRenderer {
|
|||
bb_cd: &Rc<ColorDescription>,
|
||||
) -> Result<(), VulkanError> {
|
||||
self.check_defunct()?;
|
||||
self.elide_blend_buffer1(&mut blend_buffer, bb_cd, fb_cd);
|
||||
self.create_regions(fb, opts, clear, region, blend_buffer.as_deref())?;
|
||||
self.elide_blend_buffer(&mut blend_buffer);
|
||||
self.elide_blend_buffer2(&mut blend_buffer);
|
||||
let bb = blend_buffer.as_deref();
|
||||
let buf = self.gfx_command_buffers.allocate()?;
|
||||
self.convert_ops(opts, bb_cd, fb_cd)?;
|
||||
self.create_blend_cm_data(bb, bb_cd, fb_cd);
|
||||
self.create_data_buffer()?;
|
||||
self.create_uniform_buffer()?;
|
||||
self.collect_memory();
|
||||
|
|
|
|||
|
|
@ -69,6 +69,14 @@ pub struct TexColorManagementData {
|
|||
|
||||
unsafe impl Packed for TexColorManagementData {}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[repr(C, align(16))]
|
||||
pub struct OutColorManagementData {
|
||||
pub matrix: [[f32; 4]; 4],
|
||||
}
|
||||
|
||||
unsafe impl Packed for OutColorManagementData {}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[repr(C)]
|
||||
pub struct LegacyTexPushConstants {
|
||||
|
|
|
|||
113
src/gfx_apis/vulkan/shaders/eotfs.glsl
Normal file
113
src/gfx_apis/vulkan/shaders/eotfs.glsl
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
#ifndef EOTFS_GLSL
|
||||
#define EOTFS_GLSL
|
||||
|
||||
#include "frag_spec_const.glsl"
|
||||
|
||||
#define TF_LINEAR 1
|
||||
#define TF_ST2084_PQ 2
|
||||
#define TF_GAMMA24 3
|
||||
#define TF_GAMMA22 4
|
||||
#define TF_GAMMA28 5
|
||||
#define TF_ST240 6
|
||||
#define TF_LOG100 8
|
||||
#define TF_LOG316 9
|
||||
#define TF_ST428 10
|
||||
|
||||
vec3 eotf_st2084_pq(vec3 c) {
|
||||
c = clamp(c, 0.0, 1.0);
|
||||
vec3 cp = pow(c, vec3(1.0 / 78.84375));
|
||||
vec3 num = max(cp - vec3(0.8359375), 0.0);
|
||||
vec3 den = vec3(18.8515625) - vec3(18.6875) * cp;
|
||||
return pow(num / den, vec3(1.0 / 0.1593017578125));
|
||||
}
|
||||
|
||||
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));
|
||||
return pow(num / den, vec3(78.84375));
|
||||
}
|
||||
|
||||
vec3 eotf_st240(vec3 c) {
|
||||
return mix(
|
||||
c * vec3(1.0 / 4.0),
|
||||
pow((c + vec3(0.1115)) * vec3(1.0 / 1.1115), vec3(1.0 / 0.45)),
|
||||
greaterThanEqual(c, vec3(0.0913))
|
||||
);
|
||||
}
|
||||
|
||||
vec3 inv_eotf_st240(vec3 c) {
|
||||
return mix(
|
||||
vec3(4.0) * c,
|
||||
vec3(1.1115) * pow(c, vec3(0.45)) - vec3(0.1115),
|
||||
greaterThanEqual(c, vec3(0.0228))
|
||||
);
|
||||
}
|
||||
|
||||
vec3 eotf_log100(vec3 c) {
|
||||
return pow(vec3(10), vec3(2.0) * (c - vec3(1.0)));
|
||||
}
|
||||
|
||||
vec3 inv_eotf_log100(vec3 c) {
|
||||
c = clamp(c, 0.0, 1.0);
|
||||
return mix(
|
||||
vec3(0.0),
|
||||
vec3(1.0) + log2(c) / vec3(log2(10)) / vec3(2.0),
|
||||
greaterThanEqual(c, vec3(0.01))
|
||||
);
|
||||
}
|
||||
|
||||
vec3 eotf_log316(vec3 c) {
|
||||
return pow(vec3(10), vec3(2.5) * (c - vec3(1.0)));
|
||||
}
|
||||
|
||||
vec3 inv_eotf_log316(vec3 c) {
|
||||
c = clamp(c, 0.0, 1.0);
|
||||
return mix(
|
||||
vec3(0.0),
|
||||
vec3(1.0) + log2(c) / vec3(log2(10)) / vec3(2.5),
|
||||
greaterThanEqual(c, vec3(sqrt(10) / 1000.0))
|
||||
);
|
||||
}
|
||||
|
||||
vec3 eotf_st428(vec3 c) {
|
||||
c = max(c, 0.0);
|
||||
return pow(c, vec3(2.6)) * vec3(52.37 / 48.0);
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
vec3 apply_eotf(vec3 c) {
|
||||
switch (eotf) {
|
||||
case TF_LINEAR: return c;
|
||||
case TF_ST2084_PQ: return eotf_st2084_pq(c);
|
||||
case TF_GAMMA24: return sign(c) * pow(abs(c), vec3(2.4));
|
||||
case TF_GAMMA22: return sign(c) * pow(abs(c), vec3(2.2));
|
||||
case TF_GAMMA28: return sign(c) * pow(abs(c), vec3(2.8));
|
||||
case TF_ST240: return eotf_st240(c);
|
||||
case TF_LOG100: return eotf_log100(c);
|
||||
case TF_LOG316: return eotf_log316(c);
|
||||
case TF_ST428: return eotf_st428(c);
|
||||
default: return c;
|
||||
}
|
||||
}
|
||||
|
||||
vec3 apply_inv_eotf(vec3 c) {
|
||||
switch (inv_eotf) {
|
||||
case TF_LINEAR: return 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 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;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -1,20 +1,30 @@
|
|||
#version 450
|
||||
|
||||
#extension GL_EXT_samplerless_texture_functions : require
|
||||
#extension GL_EXT_scalar_block_layout : 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;
|
||||
layout(set = 0, binding = 1, row_major, std430) uniform ColorManagementData {
|
||||
mat4x4 matrix;
|
||||
} cm_data;
|
||||
layout(location = 0) out vec4 out_color;
|
||||
|
||||
void main() {
|
||||
vec4 c = texelFetch(in_color, ivec2(gl_FragCoord.xy), 0);
|
||||
if (eotf != oetf) {
|
||||
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 *= c.a;
|
||||
if (eotf != inv_eotf || has_matrix) {
|
||||
vec3 rgb = c.rgb;
|
||||
rgb /= mix(c.a, 1.0, c.a == 0.0);
|
||||
rgb = apply_eotf(rgb);
|
||||
if (has_matrix) {
|
||||
rgb = (cm_data.matrix * vec4(rgb, 1.0)).rgb;
|
||||
}
|
||||
rgb = apply_inv_eotf(rgb);
|
||||
rgb *= c.a;
|
||||
c.rgb = rgb;
|
||||
}
|
||||
out_color = c;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,177 +0,0 @@
|
|||
#ifndef TRANSFER_FUNCTIONS_GLSL
|
||||
#define TRANSFER_FUNCTIONS_GLSL
|
||||
|
||||
#include "frag_spec_const.glsl"
|
||||
|
||||
#define TF_SRGB 0
|
||||
#define TF_LINEAR 1
|
||||
#define TF_ST2084_PQ 2
|
||||
#define TF_BT1886 3
|
||||
#define TF_GAMMA22 4
|
||||
#define TF_GAMMA28 5
|
||||
#define TF_ST240 6
|
||||
#define TF_EXT_SRGB 7
|
||||
#define TF_LOG100 8
|
||||
#define TF_LOG316 9
|
||||
#define TF_ST428 10
|
||||
|
||||
vec3 eotf_srgb(vec3 c) {
|
||||
return mix(
|
||||
c * vec3(1.0 / 12.92),
|
||||
pow((c + vec3(0.055)) / vec3(1.055), vec3(2.4)),
|
||||
greaterThan(c, vec3(0.04045))
|
||||
);
|
||||
}
|
||||
|
||||
vec3 oetf_srgb(vec3 c) {
|
||||
c = clamp(c, 0.0, 1.0);
|
||||
return mix(
|
||||
c * vec3(12.92),
|
||||
vec3(1.055) * pow(c, vec3(1/2.4)) - vec3(0.055),
|
||||
greaterThan(c, vec3(0.0031308))
|
||||
);
|
||||
}
|
||||
|
||||
vec3 eotf_ext_srgb(vec3 c) {
|
||||
return mix(
|
||||
-pow((c - vec3(0.055)) / vec3(-1.055), vec3(2.4)),
|
||||
mix(
|
||||
c * vec3(1.0 / 12.92),
|
||||
pow((c + vec3(0.055)) / vec3(1.055), vec3(2.4)),
|
||||
greaterThan(c, vec3(0.04045))
|
||||
),
|
||||
greaterThan(c, vec3(-0.04045))
|
||||
);
|
||||
}
|
||||
|
||||
vec3 oetf_ext_srgb(vec3 c) {
|
||||
c = clamp(c, -0.6038, 7.5913);
|
||||
return mix(
|
||||
vec3(-1.055) * pow(-c, vec3(1/2.4)) + vec3(0.055),
|
||||
mix(
|
||||
c * vec3(12.92),
|
||||
vec3(1.055) * pow(c, vec3(1/2.4)) - vec3(0.055),
|
||||
greaterThan(c, vec3(0.0031308))
|
||||
),
|
||||
greaterThan(c, vec3(-0.0031308))
|
||||
);
|
||||
}
|
||||
|
||||
vec3 eotf_st2084_pq(vec3 c) {
|
||||
c = clamp(c, 0.0, 1.0);
|
||||
vec3 cp = pow(c, vec3(1.0 / 78.84375));
|
||||
vec3 num = max(cp - vec3(0.8359375), 0.0);
|
||||
vec3 den = vec3(18.8515625) - vec3(18.6875) * cp;
|
||||
return pow(num / den, vec3(1.0 / 0.1593017578125));
|
||||
}
|
||||
|
||||
vec3 oetf_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));
|
||||
return pow(num / den, vec3(78.84375));
|
||||
}
|
||||
|
||||
vec3 eotf_bt1886(vec3 c) {
|
||||
return mix(
|
||||
c * vec3(1.0 / 4.5),
|
||||
pow((c + vec3(0.099)) * vec3(1.0 / 1.099), vec3(1.0 / 0.45)),
|
||||
greaterThanEqual(c, vec3(0.081))
|
||||
);
|
||||
}
|
||||
|
||||
vec3 oetf_bt1886(vec3 c) {
|
||||
return mix(
|
||||
vec3(4.5) * c,
|
||||
vec3(1.099) * pow(c, vec3(0.45)) - vec3(0.099),
|
||||
greaterThanEqual(c, vec3(0.018))
|
||||
);
|
||||
}
|
||||
|
||||
vec3 eotf_st240(vec3 c) {
|
||||
return mix(
|
||||
c * vec3(1.0 / 4.0),
|
||||
pow((c + vec3(0.1115)) * vec3(1.0 / 1.1115), vec3(1.0 / 0.45)),
|
||||
greaterThanEqual(c, vec3(0.0913))
|
||||
);
|
||||
}
|
||||
|
||||
vec3 oetf_st240(vec3 c) {
|
||||
return mix(
|
||||
vec3(4.0) * c,
|
||||
vec3(1.1115) * pow(c, vec3(0.45)) - vec3(0.1115),
|
||||
greaterThanEqual(c, vec3(0.0228))
|
||||
);
|
||||
}
|
||||
|
||||
vec3 eotf_log100(vec3 c) {
|
||||
return pow(vec3(10), vec3(2.0) * (c - vec3(1.0)));
|
||||
}
|
||||
|
||||
vec3 oetf_log100(vec3 c) {
|
||||
c = clamp(c, 0.0, 1.0);
|
||||
return mix(
|
||||
vec3(0.0),
|
||||
vec3(1.0) + log2(c) / vec3(log2(10)) / vec3(2.0),
|
||||
greaterThanEqual(c, vec3(0.01))
|
||||
);
|
||||
}
|
||||
|
||||
vec3 eotf_log316(vec3 c) {
|
||||
return pow(vec3(10), vec3(2.5) * (c - vec3(1.0)));
|
||||
}
|
||||
|
||||
vec3 oetf_log316(vec3 c) {
|
||||
c = clamp(c, 0.0, 1.0);
|
||||
return mix(
|
||||
vec3(0.0),
|
||||
vec3(1.0) + log2(c) / vec3(log2(10)) / vec3(2.5),
|
||||
greaterThanEqual(c, vec3(sqrt(10) / 1000.0))
|
||||
);
|
||||
}
|
||||
|
||||
vec3 eotf_st428(vec3 c) {
|
||||
c = max(c, 0.0);
|
||||
return pow(c, vec3(2.6)) * vec3(52.37 / 48.0);
|
||||
}
|
||||
|
||||
vec3 oetf_st428(vec3 c) {
|
||||
c = max(c, 0.0);
|
||||
return pow(vec3(48.0) * c / vec3(52.37), vec3(1.0 / 2.6));
|
||||
}
|
||||
|
||||
vec3 apply_eotf(vec3 c) {
|
||||
switch (eotf) {
|
||||
case TF_SRGB: return eotf_srgb(c);
|
||||
case TF_LINEAR: return c;
|
||||
case TF_ST2084_PQ: return eotf_st2084_pq(c);
|
||||
case TF_BT1886: return eotf_bt1886(c);
|
||||
case TF_GAMMA22: return pow(max(c, 0.0), vec3(2.2));
|
||||
case TF_GAMMA28: return pow(max(c, 0.0), vec3(2.8));
|
||||
case TF_ST240: return eotf_st240(c);
|
||||
case TF_EXT_SRGB: return eotf_ext_srgb(c);
|
||||
case TF_LOG100: return eotf_log100(c);
|
||||
case TF_LOG316: return eotf_log316(c);
|
||||
case TF_ST428: return eotf_st428(c);
|
||||
default: return c;
|
||||
}
|
||||
}
|
||||
|
||||
vec3 apply_oetf(vec3 c) {
|
||||
switch (oetf) {
|
||||
case TF_SRGB: return oetf_srgb(c);
|
||||
case TF_LINEAR: return c;
|
||||
case TF_ST2084_PQ: return oetf_st2084_pq(c);
|
||||
case TF_BT1886: return oetf_bt1886(c);
|
||||
case TF_GAMMA22: return pow(max(c, 0.0), vec3(1.0 / 2.2));
|
||||
case TF_GAMMA28: return pow(max(c, 0.0), vec3(1.0 / 2.8));
|
||||
case TF_ST240: return oetf_st240(c);
|
||||
case TF_EXT_SRGB: return oetf_ext_srgb(c);
|
||||
case TF_LOG100: return oetf_log100(c);
|
||||
case TF_LOG316: return oetf_log316(c);
|
||||
case TF_ST428: return oetf_st428(c);
|
||||
default: return c;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
use crate::cmm::cmm_transfer_function::TransferFunction;
|
||||
|
||||
pub const TF_SRGB: u32 = 0;
|
||||
pub const TF_LINEAR: u32 = 1;
|
||||
pub const TF_ST2084_PQ: u32 = 2;
|
||||
pub const TF_BT1887: u32 = 3;
|
||||
pub const TF_GAMMA22: u32 = 4;
|
||||
pub const TF_GAMMA28: u32 = 5;
|
||||
pub const TF_ST240: u32 = 6;
|
||||
pub const TF_EXT_SRGB: u32 = 7;
|
||||
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::Srgb => TF_SRGB,
|
||||
TransferFunction::Linear => TF_LINEAR,
|
||||
TransferFunction::St2084Pq => TF_ST2084_PQ,
|
||||
TransferFunction::Bt1886 => TF_BT1887,
|
||||
TransferFunction::Gamma22 => TF_GAMMA22,
|
||||
TransferFunction::Gamma28 => TF_GAMMA28,
|
||||
TransferFunction::St240 => TF_ST240,
|
||||
TransferFunction::ExtSrgb => TF_EXT_SRGB,
|
||||
TransferFunction::Log100 => TF_LOG100,
|
||||
TransferFunction::Log316 => TF_LOG316,
|
||||
TransferFunction::St428 => TF_ST428,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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::Srgb);
|
||||
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::Srgb);
|
||||
let [mut r, mut g, mut b, alpha] = srgb.to_array(Eotf::Gamma22);
|
||||
if alpha < 1.0 {
|
||||
r /= alpha;
|
||||
g /= alpha;
|
||||
|
|
|
|||
|
|
@ -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::Srgb,
|
||||
TRANSFER_FUNCTION_EXT_SRGB => TransferFunction::ExtSrgb,
|
||||
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,
|
||||
|
|
|
|||
|
|
@ -1,18 +1,14 @@
|
|||
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,
|
||||
PRIMARIES_NTSC, PRIMARIES_PAL, PRIMARIES_PAL_M, TRANSFER_FUNCTION_BT1886,
|
||||
TRANSFER_FUNCTION_EXT_LINEAR, TRANSFER_FUNCTION_EXT_SRGB, TRANSFER_FUNCTION_GAMMA22,
|
||||
PRIMARIES_NTSC, PRIMARIES_PAL, PRIMARIES_PAL_M, PRIMARIES_SRGB,
|
||||
TRANSFER_FUNCTION_BT1886, TRANSFER_FUNCTION_EXT_LINEAR, TRANSFER_FUNCTION_GAMMA22,
|
||||
TRANSFER_FUNCTION_GAMMA28, TRANSFER_FUNCTION_LOG_100, TRANSFER_FUNCTION_LOG_316,
|
||||
TRANSFER_FUNCTION_ST240, TRANSFER_FUNCTION_ST428, TRANSFER_FUNCTION_ST2084_PQ,
|
||||
consts::{PRIMARIES_SRGB, TRANSFER_FUNCTION_SRGB},
|
||||
},
|
||||
leaks::Tracker,
|
||||
object::{Object, Version},
|
||||
|
|
@ -32,18 +28,16 @@ pub struct WpImageDescriptionInfoV1 {
|
|||
|
||||
impl WpImageDescriptionInfoV1 {
|
||||
pub fn send_description(&self, d: &ColorDescription) {
|
||||
let tf = match d.transfer_function {
|
||||
TransferFunction::Srgb => TRANSFER_FUNCTION_SRGB,
|
||||
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::ExtSrgb => TRANSFER_FUNCTION_EXT_SRGB,
|
||||
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 {
|
||||
|
|
|
|||
|
|
@ -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()),
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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(())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ impl Global for JayCompositorGlobal {
|
|||
}
|
||||
|
||||
fn version(&self) -> u32 {
|
||||
20
|
||||
21
|
||||
}
|
||||
|
||||
fn required_caps(&self) -> ClientCaps {
|
||||
|
|
|
|||
|
|
@ -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::Srgb, 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(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
use {
|
||||
crate::{
|
||||
backend::{self, BackendColorSpace, BackendTransferFunction},
|
||||
backend::{self, BackendColorSpace, BackendEotfs},
|
||||
client::{Client, ClientError},
|
||||
compositor::MAX_EXTENTS,
|
||||
format::named_formats,
|
||||
ifs::wl_output,
|
||||
leaks::Tracker,
|
||||
object::{Object, Version},
|
||||
scale::Scale,
|
||||
|
|
@ -34,6 +35,7 @@ const FORMAT_SINCE: Version = Version(8);
|
|||
const FLIP_MARGIN_SINCE: Version = Version(10);
|
||||
const COLORIMETRY_SINCE: Version = Version(15);
|
||||
const BRIGHTNESS_SINCE: Version = Version(16);
|
||||
const BLEND_SPACE_SINCE: Version = Version(21);
|
||||
|
||||
impl JayRandr {
|
||||
pub fn new(id: JayRandrId, client: &Rc<Client>, version: Version) -> Self {
|
||||
|
|
@ -170,15 +172,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 {
|
||||
|
|
@ -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) {
|
||||
|
|
@ -484,21 +492,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!(
|
||||
|
|
@ -528,6 +534,23 @@ impl JayRandrRequestHandler for JayRandr {
|
|||
c.set_brightness(None);
|
||||
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! {
|
||||
|
|
@ -551,7 +574,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);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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},
|
||||
|
|
@ -30,6 +30,7 @@ use {
|
|||
},
|
||||
ahash::AHashMap,
|
||||
jay_config::video::Transform,
|
||||
linearize::Linearize,
|
||||
std::{
|
||||
cell::{Cell, RefCell},
|
||||
collections::hash_map::Entry,
|
||||
|
|
@ -76,7 +77,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 +87,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>>,
|
||||
|
|
@ -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 transform: Cell<Transform>,
|
||||
pub scale: Cell<crate::scale::Scale>,
|
||||
|
|
@ -123,6 +139,7 @@ pub struct PersistentOutputState {
|
|||
pub vrr_cursor_hz: Cell<Option<f64>>,
|
||||
pub tearing_mode: Cell<&'static TearingMode>,
|
||||
pub brightness: Cell<Option<f64>>,
|
||||
pub blend_space: Cell<BlendSpace>,
|
||||
}
|
||||
|
||||
impl Default for PersistentOutputState {
|
||||
|
|
@ -135,6 +152,7 @@ impl Default for PersistentOutputState {
|
|||
vrr_cursor_hz: Default::default(),
|
||||
tearing_mode: Cell::new(&TearingMode::Never),
|
||||
brightness: Default::default(),
|
||||
blend_space: Cell::new(BlendSpace::Srgb),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -179,7 +197,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 +223,7 @@ impl WlOutputGlobal {
|
|||
format: Cell::new(XRGB8888),
|
||||
width_mm,
|
||||
height_mm,
|
||||
transfer_functions,
|
||||
eotfs,
|
||||
color_spaces,
|
||||
primaries,
|
||||
luminance,
|
||||
|
|
@ -215,9 +233,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 +363,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 +371,14 @@ impl WlOutputGlobal {
|
|||
};
|
||||
luminance.white.0 = luminance.max.0 * brightness / output_max;
|
||||
}
|
||||
TransferFunction::Srgb
|
||||
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 +404,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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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::Srgb);
|
||||
let [r, g, b, a] = color.to_array(Eotf::Gamma22);
|
||||
self.tran.send(CreateU32RgbaBuffer {
|
||||
self_id: self.id,
|
||||
id: obj.id,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -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::Srgb);
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -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| {
|
||||
|
|
|
|||
|
|
@ -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()];
|
||||
|
|
|
|||
|
|
@ -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()),
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use {
|
|||
ifs::{
|
||||
head_management::{HeadManagers, HeadState},
|
||||
jay_tray_v1::JayTrayV1Global,
|
||||
wl_output::{PersistentOutputState, WlOutputGlobal},
|
||||
wl_output::{BlendSpace, PersistentOutputState, WlOutputGlobal},
|
||||
},
|
||||
output_schedule::OutputSchedule,
|
||||
state::{ConnectorData, OutputData, State},
|
||||
|
|
@ -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,
|
||||
};
|
||||
|
|
@ -183,6 +183,7 @@ impl ConnectorHandler {
|
|||
vrr_cursor_hz: Cell::new(self.state.default_vrr_cursor_hz.get()),
|
||||
tearing_mode: Cell::new(self.state.default_tearing_mode.get()),
|
||||
brightness: Cell::new(None),
|
||||
blend_space: Cell::new(BlendSpace::Srgb),
|
||||
});
|
||||
self.state
|
||||
.persistent_output_states
|
||||
|
|
@ -199,7 +200,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,
|
||||
|
|
|
|||
|
|
@ -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::Srgb);
|
||||
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);
|
||||
|
|
|
|||
161
src/theme.rs
161
src/theme.rs
|
|
@ -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,14 +68,7 @@ impl Color {
|
|||
a: 1.0,
|
||||
};
|
||||
|
||||
pub fn new(transfer_function: TransferFunction, mut r: f32, mut g: f32, mut b: f32) -> Self {
|
||||
fn srgb(c: f32) -> f32 {
|
||||
if c <= 0.04045 {
|
||||
c / 12.92
|
||||
} else {
|
||||
((c + 0.055) / 1.055).powf(2.4)
|
||||
}
|
||||
}
|
||||
pub fn new(eotf: Eotf, mut r: f32, mut g: f32, mut b: f32) -> Self {
|
||||
#[inline(always)]
|
||||
fn linear(c: f32) -> f32 {
|
||||
c
|
||||
|
|
@ -86,23 +79,6 @@ impl Color {
|
|||
let den = 18.8515625 - 18.6875 * cp;
|
||||
(num / den).powf(1.0 / 0.1593017578125)
|
||||
}
|
||||
fn ext_srgb(c: f32) -> f32 {
|
||||
let c = c.clamp(-0.6038, 7.5913);
|
||||
if c <= -0.0031308 {
|
||||
-1.055 * (-c).powf(1.0 / 2.4) + 0.055
|
||||
} else if c <= 0.0031308 {
|
||||
c * 12.92
|
||||
} else {
|
||||
1.055 * c.powf(1.0 / 2.4) - 0.055
|
||||
}
|
||||
}
|
||||
fn bt1886(c: f32) -> f32 {
|
||||
if c < 0.081 {
|
||||
c / 4.5
|
||||
} else {
|
||||
((c + 0.099) / 1.099).powf(1.0 / 0.45)
|
||||
}
|
||||
}
|
||||
fn st240(c: f32) -> f32 {
|
||||
if c < 0.0913 {
|
||||
c / 4.0
|
||||
|
|
@ -120,10 +96,13 @@ impl Color {
|
|||
c.powf(2.6) * 52.37 / 48.0
|
||||
}
|
||||
fn gamma22(c: f32) -> f32 {
|
||||
c.powf(2.2)
|
||||
c.signum() * c.abs().powf(2.2)
|
||||
}
|
||||
fn gamma24(c: f32) -> f32 {
|
||||
c.signum() * c.abs().powf(2.4)
|
||||
}
|
||||
fn gamma28(c: f32) -> f32 {
|
||||
c.powf(2.8)
|
||||
c.signum() * c.abs().powf(2.8)
|
||||
}
|
||||
macro_rules! convert {
|
||||
($tf:ident) => {{
|
||||
|
|
@ -132,30 +111,22 @@ impl Color {
|
|||
b = $tf(b);
|
||||
}};
|
||||
}
|
||||
match transfer_function {
|
||||
TransferFunction::Srgb => convert!(srgb),
|
||||
TransferFunction::Linear => convert!(linear),
|
||||
TransferFunction::St2084Pq => convert!(st2084_pq),
|
||||
TransferFunction::Bt1886 => convert!(bt1886),
|
||||
TransferFunction::Gamma22 => convert!(gamma22),
|
||||
TransferFunction::Gamma28 => convert!(gamma28),
|
||||
TransferFunction::St240 => convert!(st240),
|
||||
TransferFunction::ExtSrgb => convert!(ext_srgb),
|
||||
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 {
|
||||
|
|
@ -163,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;
|
||||
}
|
||||
|
|
@ -179,40 +150,22 @@ impl Color {
|
|||
}
|
||||
|
||||
pub fn from_srgb(r: u8, g: u8, b: u8) -> Self {
|
||||
Self::new(TransferFunction::Srgb, 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::Srgb,
|
||||
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::Srgb, 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);
|
||||
}
|
||||
|
|
@ -220,23 +173,16 @@ impl Color {
|
|||
}
|
||||
|
||||
pub fn to_srgba_premultiplied(self) -> [u8; 4] {
|
||||
let [r, g, b, a] = self.to_array(TransferFunction::Srgb);
|
||||
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 srgb(c: f32) -> f32 {
|
||||
if c <= 0.0031308 {
|
||||
c * 12.92
|
||||
} else {
|
||||
1.055 * c.powf(1.0 / 2.4) - 0.055
|
||||
}
|
||||
}
|
||||
fn linear(c: f32) -> f32 {
|
||||
c
|
||||
}
|
||||
|
|
@ -246,22 +192,6 @@ impl Color {
|
|||
let den = 1.0 + 18.6875 * c.powf(0.1593017578125);
|
||||
(num / den).powf(78.84375)
|
||||
}
|
||||
fn ext_srgb(c: f32) -> f32 {
|
||||
if c < -0.04045 {
|
||||
-((c - 0.055) / -1.055).powf(2.4)
|
||||
} else if c < 0.04045 {
|
||||
c / 12.92
|
||||
} else {
|
||||
((c + 0.055) / 1.055).powf(2.4)
|
||||
}
|
||||
}
|
||||
fn bt1886(c: f32) -> f32 {
|
||||
if c < 0.018 {
|
||||
4.5 * c
|
||||
} else {
|
||||
1.099 * c.powf(0.45) - 0.099
|
||||
}
|
||||
}
|
||||
fn st240(c: f32) -> f32 {
|
||||
if c < 0.0228 {
|
||||
4.0 * c
|
||||
|
|
@ -285,10 +215,13 @@ impl Color {
|
|||
(48.0 * c / 52.37).powf(1.0 / 2.6)
|
||||
}
|
||||
fn gamma22(c: f32) -> f32 {
|
||||
c.powf(1.0 / 2.2)
|
||||
c.signum() * c.abs().powf(1.0 / 2.2)
|
||||
}
|
||||
fn gamma24(c: f32) -> f32 {
|
||||
c.signum() * c.abs().powf(1.0 / 2.4)
|
||||
}
|
||||
fn gamma28(c: f32) -> f32 {
|
||||
c.powf(1.0 / 2.8)
|
||||
c.signum() * c.abs().powf(1.0 / 2.8)
|
||||
}
|
||||
macro_rules! convert {
|
||||
($tf:ident) => {{
|
||||
|
|
@ -297,24 +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::Srgb => convert!(srgb),
|
||||
TransferFunction::Linear => convert!(linear),
|
||||
TransferFunction::St2084Pq => convert!(st2084_pq),
|
||||
TransferFunction::Bt1886 => convert!(bt1886),
|
||||
TransferFunction::Gamma22 => convert!(gamma22),
|
||||
TransferFunction::Gamma28 => convert!(gamma28),
|
||||
TransferFunction::St240 => convert!(st240),
|
||||
TransferFunction::ExtSrgb => convert!(ext_srgb),
|
||||
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] {
|
||||
|
|
@ -343,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::Srgb, r, g, b, a)
|
||||
Self::new_premultiplied(Eotf::Gamma22, r, g, b, a)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -335,7 +335,7 @@ impl ToolClient {
|
|||
self_id: s.registry,
|
||||
name: s.jay_compositor.0,
|
||||
interface: JayCompositor.name(),
|
||||
version: s.jay_compositor.1.min(20),
|
||||
version: s.jay_compositor.1.min(21),
|
||||
id: id.into(),
|
||||
});
|
||||
self.jay_compositor.set(Some(id));
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
@ -14,7 +13,7 @@ use {
|
|||
jay_output::JayOutput,
|
||||
jay_screencast::JayScreencast,
|
||||
wl_buffer::WlBufferStorage,
|
||||
wl_output::WlOutputGlobal,
|
||||
wl_output::{BlendSpace, WlOutputGlobal},
|
||||
wl_seat::{
|
||||
BTN_LEFT, NodeSeatState, SeatId, WlSeatGlobal, collect_kb_foci2,
|
||||
tablet::{TabletTool, TabletToolChanges, TabletToolId},
|
||||
|
|
@ -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) {
|
||||
|
|
@ -972,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(
|
||||
&self,
|
||||
stack: &LinkedList<Rc<dyn StackedNode>>,
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ use {
|
|||
logging::LogLevel,
|
||||
status::MessageFormat,
|
||||
theme::Color,
|
||||
video::{ColorSpace, Format, GfxApi, TearingMode, TransferFunction, Transform, VrrMode},
|
||||
video::{BlendSpace, ColorSpace, Eotf, Format, GfxApi, TearingMode, Transform, VrrMode},
|
||||
window::{ContentType, TileState, WindowType},
|
||||
workspace::WorkspaceDisplayOrder,
|
||||
xwayland::XScalingMode,
|
||||
|
|
@ -347,8 +347,9 @@ 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>>,
|
||||
pub blend_space: Option<BlendSpace>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ use {
|
|||
},
|
||||
},
|
||||
indexmap::IndexMap,
|
||||
jay_config::video::{ColorSpace, TransferFunction, Transform},
|
||||
jay_config::video::{BlendSpace, 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, blend_space),
|
||||
) = ext.extract((
|
||||
(
|
||||
opt(str("name")),
|
||||
|
|
@ -69,6 +69,7 @@ impl Parser for OutputParser<'_> {
|
|||
recover(opt(str("color-space"))),
|
||||
recover(opt(str("transfer-function"))),
|
||||
opt(val("brightness")),
|
||||
recover(opt(str("blend-space"))),
|
||||
),
|
||||
))?;
|
||||
let transform = match transform {
|
||||
|
|
@ -103,17 +104,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
|
||||
}
|
||||
},
|
||||
|
|
@ -181,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 {
|
||||
name: name.despan().map(|v| v.to_string()),
|
||||
match_: match_val.parse_map(&mut OutputMatchParser(self.cx))?,
|
||||
|
|
@ -193,8 +205,9 @@ impl Parser for OutputParser<'_> {
|
|||
tearing,
|
||||
format,
|
||||
color_space,
|
||||
transfer_function,
|
||||
eotf,
|
||||
brightness,
|
||||
blend_space,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,14 +769,17 @@ 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 {
|
||||
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": {
|
||||
"description": "The brightness setting of an output.\n",
|
||||
"anyOf": [
|
||||
|
|
@ -1141,6 +1149,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,12 +1657,16 @@
|
|||
"$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",
|
||||
"$ref": "#/$defs/Brightness"
|
||||
},
|
||||
"blend-space": {
|
||||
"description": "The blend space of the output.\n\nThe default is `srgb`.\n",
|
||||
"$ref": "#/$defs/BlendSpace"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
|
|
@ -1902,14 +1922,6 @@
|
|||
"floating"
|
||||
]
|
||||
},
|
||||
"TransferFunction": {
|
||||
"type": "string",
|
||||
"description": "The transfer function of an output.\n",
|
||||
"enum": [
|
||||
"default",
|
||||
"pq"
|
||||
]
|
||||
},
|
||||
"Transform": {
|
||||
"type": "string",
|
||||
"description": "An output transformation.",
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
|
||||
<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>
|
||||
### `Brightness`
|
||||
|
||||
|
|
@ -814,7 +833,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 +2322,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 +3555,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):
|
||||
|
||||
|
|
@ -3529,6 +3567,14 @@ The table has the following fields:
|
|||
|
||||
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>
|
||||
### `OutputMatch`
|
||||
|
|
@ -4215,25 +4261,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`
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -1967,6 +1967,13 @@ Output:
|
|||
The brightness of the output.
|
||||
|
||||
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:
|
||||
|
|
@ -3293,15 +3300,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 +3324,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
|
||||
|
|
@ -4029,3 +4036,14 @@ WorkspaceDisplayOrder:
|
|||
description: Workspaces are not sorted and can be manually dragged.
|
||||
- value: sorted
|
||||
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.
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
@ -95,6 +95,11 @@ request unset_brightness (since = 16) {
|
|||
output: str,
|
||||
}
|
||||
|
||||
request set_blend_space (since = 21) {
|
||||
output: str,
|
||||
blend_space: str,
|
||||
}
|
||||
|
||||
# events
|
||||
|
||||
event global {
|
||||
|
|
@ -184,12 +189,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) {
|
||||
|
|
@ -201,3 +206,7 @@ event brightness_range (since = 16) {
|
|||
event brightness (since = 16) {
|
||||
lux: pod(f64),
|
||||
}
|
||||
|
||||
event blend_space (since = 21) {
|
||||
blend_space: str,
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue