color-management: implement set_tf_power
This commit is contained in:
parent
a2d726e508
commit
c37567f1cd
8 changed files with 121 additions and 28 deletions
|
|
@ -9,4 +9,28 @@ pub enum Eotf {
|
|||
Log100,
|
||||
Log316,
|
||||
St428,
|
||||
Pow(EotfPow),
|
||||
}
|
||||
|
||||
const MUL: u32 = 10_000;
|
||||
const MUL_F32: f32 = MUL as f32;
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)]
|
||||
pub struct EotfPow(pub u32);
|
||||
|
||||
impl EotfPow {
|
||||
pub const MIN: Self = Self(10_000);
|
||||
pub const LINEAR: Self = Self(10_000);
|
||||
pub const GAMMA22: Self = Self(22_000);
|
||||
pub const GAMMA24: Self = Self(24_000);
|
||||
pub const GAMMA28: Self = Self(28_000);
|
||||
pub const MAX: Self = Self(100_000);
|
||||
|
||||
pub fn eotf_f32(self) -> f32 {
|
||||
self.0 as f32 / MUL_F32
|
||||
}
|
||||
|
||||
pub fn inv_eotf_f32(self) -> f32 {
|
||||
MUL_F32 / self.0 as f32
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ 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 const EOTF_POW: u32 = 11;
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Linearize)]
|
||||
pub enum VulkanEotf {
|
||||
|
|
@ -21,6 +22,7 @@ pub enum VulkanEotf {
|
|||
Log100,
|
||||
Log316,
|
||||
St428,
|
||||
Pow,
|
||||
}
|
||||
|
||||
pub trait EotfExt: Sized {
|
||||
|
|
@ -48,6 +50,7 @@ impl EotfExt for Eotf {
|
|||
Log100,
|
||||
Log316,
|
||||
St428,
|
||||
Pow,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -64,6 +67,7 @@ impl VulkanEotf {
|
|||
Self::Log100 => EOTF_LOG100,
|
||||
Self::Log316 => EOTF_LOG316,
|
||||
Self::St428 => EOTF_ST428,
|
||||
Self::Pow => EOTF_POW,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ use {
|
|||
async_engine::{AsyncEngine, SpawnedFuture},
|
||||
cmm::{
|
||||
cmm_description::{ColorDescription, LinearColorDescription, LinearColorDescriptionId},
|
||||
cmm_eotf::{Eotf, EotfPow},
|
||||
cmm_transform::ColorMatrix,
|
||||
},
|
||||
cpu_worker::PendingJob,
|
||||
|
|
@ -2327,21 +2328,48 @@ impl ColorTransforms {
|
|||
|
||||
#[derive(Default)]
|
||||
struct EotfArgsCache {
|
||||
map: AHashMap<(), EotfArg>,
|
||||
map: AHashMap<(EotfPow, bool), EotfArg>,
|
||||
}
|
||||
|
||||
struct EotfArg {
|
||||
_offset: DeviceSize,
|
||||
offset: DeviceSize,
|
||||
}
|
||||
|
||||
impl EotfArgsCache {
|
||||
fn get_offset(
|
||||
&mut self,
|
||||
_desc: &ColorDescription,
|
||||
_inv: bool,
|
||||
_uniform_buffer_offset_mask: DeviceSize,
|
||||
_writer: &mut GenericBufferWriter,
|
||||
desc: &ColorDescription,
|
||||
inv: bool,
|
||||
uniform_buffer_offset_mask: DeviceSize,
|
||||
writer: &mut GenericBufferWriter,
|
||||
) -> Option<DeviceSize> {
|
||||
None
|
||||
let Eotf::Pow(pow) = desc.eotf else {
|
||||
return None;
|
||||
};
|
||||
let ct = match self.map.entry((pow, inv)) {
|
||||
Entry::Occupied(o) => o.into_mut(),
|
||||
Entry::Vacant(e) => {
|
||||
if inv {
|
||||
let data = InvEotfArgs {
|
||||
arg1: pow.inv_eotf_f32(),
|
||||
arg2: 0.0,
|
||||
arg3: 0.0,
|
||||
arg4: 0.0,
|
||||
};
|
||||
let offset = writer.write(uniform_buffer_offset_mask, &data);
|
||||
e.insert(EotfArg { offset })
|
||||
} else {
|
||||
let data = EotfArgs {
|
||||
arg1: pow.eotf_f32(),
|
||||
arg2: 0.0,
|
||||
arg3: 0.0,
|
||||
arg4: 0.0,
|
||||
};
|
||||
let offset = writer.write(uniform_buffer_offset_mask, &data);
|
||||
e.insert(EotfArg { offset })
|
||||
}
|
||||
}
|
||||
};
|
||||
Some(ct.offset)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
#define TF_LOG100 8
|
||||
#define TF_LOG316 9
|
||||
#define TF_ST428 10
|
||||
#define TF_POW 11
|
||||
|
||||
vec3 eotf_st2084_pq(vec3 c) {
|
||||
c = clamp(c, 0.0, 1.0);
|
||||
|
|
@ -92,6 +93,7 @@ vec3 apply_eotf(vec3 c) {
|
|||
case TF_LOG100: return eotf_log100(c);
|
||||
case TF_LOG316: return eotf_log316(c);
|
||||
case TF_ST428: return eotf_st428(c);
|
||||
case TF_POW: return sign(c) * pow(abs(c), vec3(cm_eotf_args.arg1));
|
||||
default: return c;
|
||||
}
|
||||
}
|
||||
|
|
@ -107,6 +109,7 @@ vec3 apply_inv_eotf(vec3 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);
|
||||
case TF_POW: return sign(c) * pow(abs(c), vec3(cm_inv_eotf_args.arg1));
|
||||
default: return c;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ use {
|
|||
ifs::{
|
||||
color_management::{
|
||||
FEATURE_EXTENDED_TARGET_VOLUME, FEATURE_SET_MASTERING_DISPLAY_PRIMARIES,
|
||||
FEATURE_SET_TF_POWER,
|
||||
consts::{
|
||||
FEATURE_PARAMETRIC, FEATURE_SET_LUMINANCES, FEATURE_SET_PRIMARIES,
|
||||
FEATURE_WINDOWS_SCRGB, PRIMARIES_ADOBE_RGB, PRIMARIES_BT2020,
|
||||
|
|
@ -79,6 +80,7 @@ impl WpColorManagerV1 {
|
|||
self.send_supported_feature(FEATURE_SET_PRIMARIES);
|
||||
self.send_supported_feature(FEATURE_SET_LUMINANCES);
|
||||
self.send_supported_feature(FEATURE_SET_MASTERING_DISPLAY_PRIMARIES);
|
||||
self.send_supported_feature(FEATURE_SET_TF_POWER);
|
||||
self.send_supported_feature(FEATURE_EXTENDED_TARGET_VOLUME);
|
||||
self.send_supported_feature(FEATURE_WINDOWS_SCRGB);
|
||||
self.send_supported_tf_named(TRANSFER_FUNCTION_BT1886);
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use {
|
|||
crate::{
|
||||
client::{Client, ClientError},
|
||||
cmm::{
|
||||
cmm_eotf::Eotf,
|
||||
cmm_eotf::{Eotf, EotfPow},
|
||||
cmm_luminance::{Luminance, TargetLuminance},
|
||||
cmm_primaries::{NamedPrimaries, Primaries},
|
||||
},
|
||||
|
|
@ -125,8 +125,21 @@ impl WpImageDescriptionCreatorParamsV1RequestHandler for WpImageDescriptionCreat
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn set_tf_power(&self, _req: SetTfPower, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||
Err(WpImageDescriptionCreatorParamsV1Error::SetTfPowerNotSupported)
|
||||
fn set_tf_power(&self, req: SetTfPower, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||
let pow = EotfPow(req.eexp);
|
||||
if pow < EotfPow::MIN || pow > EotfPow::MAX {
|
||||
return Err(WpImageDescriptionCreatorParamsV1Error::SetTfPowerOutOfBounds);
|
||||
}
|
||||
let tf = match pow {
|
||||
EotfPow::LINEAR => Eotf::Linear,
|
||||
EotfPow::GAMMA22 => Eotf::Gamma22,
|
||||
EotfPow::GAMMA28 => Eotf::Gamma28,
|
||||
_ => Eotf::Pow(pow),
|
||||
};
|
||||
if self.tf.replace(Some(tf)).is_some() {
|
||||
return Err(WpImageDescriptionCreatorParamsV1Error::TfAlreadySet);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_primaries_named(
|
||||
|
|
@ -259,8 +272,8 @@ pub enum WpImageDescriptionCreatorParamsV1Error {
|
|||
ClientError(Box<ClientError>),
|
||||
#[error("{} is not a supported named primary", .0)]
|
||||
UnsupportedPrimaries(u32),
|
||||
#[error("set_tf_power is not supported")]
|
||||
SetTfPowerNotSupported,
|
||||
#[error("The exponent is out of bounds")]
|
||||
SetTfPowerOutOfBounds,
|
||||
#[error("{} is not a supported named EOTF", .0)]
|
||||
UnsupportedTf(u32),
|
||||
#[error("The EOTF has already been set")]
|
||||
|
|
|
|||
|
|
@ -1,7 +1,11 @@
|
|||
use {
|
||||
crate::{
|
||||
client::Client,
|
||||
cmm::{cmm_description::ColorDescription, cmm_eotf::Eotf, cmm_primaries::NamedPrimaries},
|
||||
cmm::{
|
||||
cmm_description::ColorDescription,
|
||||
cmm_eotf::{Eotf, EotfPow},
|
||||
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,
|
||||
|
|
@ -28,17 +32,24 @@ pub struct WpImageDescriptionInfoV1 {
|
|||
|
||||
impl WpImageDescriptionInfoV1 {
|
||||
pub fn send_description(&self, d: &ColorDescription) {
|
||||
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,
|
||||
};
|
||||
'tf: {
|
||||
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,
|
||||
Eotf::Pow(e) => {
|
||||
self.send_tf_power(e);
|
||||
break 'tf;
|
||||
}
|
||||
};
|
||||
self.send_tf_named(tf);
|
||||
}
|
||||
self.send_primaries(&d.linear.primaries);
|
||||
if let Some(n) = d.named_primaries {
|
||||
let n = match n {
|
||||
|
|
@ -55,7 +66,6 @@ impl WpImageDescriptionInfoV1 {
|
|||
};
|
||||
self.send_primaries_named(n);
|
||||
}
|
||||
self.send_tf_named(tf);
|
||||
self.send_luminances(&d.linear.luminance);
|
||||
self.send_target_primaries(&d.linear.target_primaries);
|
||||
self.send_target_luminances(&d.linear.target_luminance);
|
||||
|
|
@ -103,11 +113,10 @@ impl WpImageDescriptionInfoV1 {
|
|||
});
|
||||
}
|
||||
|
||||
#[expect(dead_code)]
|
||||
pub fn send_tf_power(&self, eexp: f64) {
|
||||
pub fn send_tf_power(&self, e: EotfPow) {
|
||||
self.client.event(TfPower {
|
||||
self_id: self.id,
|
||||
eexp: (eexp * 10_000.0) as u32,
|
||||
eexp: e.0,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
10
src/theme.rs
10
src/theme.rs
|
|
@ -121,6 +121,11 @@ impl Color {
|
|||
Eotf::Log100 => convert!(log100),
|
||||
Eotf::Log316 => convert!(log316),
|
||||
Eotf::St428 => convert!(st428),
|
||||
Eotf::Pow(n) => {
|
||||
let e = n.eotf_f32();
|
||||
let pow = |c: f32| -> f32 { c.signum() * c.abs().powf(e) };
|
||||
convert!(pow)
|
||||
}
|
||||
}
|
||||
Self { r, g, b, a: 1.0 }
|
||||
}
|
||||
|
|
@ -246,6 +251,11 @@ impl Color {
|
|||
Eotf::Log100 => convert!(log100),
|
||||
Eotf::Log316 => convert!(log316),
|
||||
Eotf::St428 => convert!(st428),
|
||||
Eotf::Pow(n) => {
|
||||
let e = n.inv_eotf_f32();
|
||||
let pow = |c: f32| -> f32 { c.signum() * c.abs().powf(e) };
|
||||
convert!(pow)
|
||||
}
|
||||
}
|
||||
if self.a < 1.0 {
|
||||
for c in &mut res[..3] {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue