Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  tf.rs

  Sprache: Rust
 

// Copyright (c) the JPEG XL Project Authors. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

use crate::util::{eval_rational_poly, eval_rational_poly_simd};
use jxl_simd::{F32SimdVec, SimdDescriptor, SimdMask};

/// Converts the linear samples with the sRGB transfer curve (SIMD version).
// Max error ~5e-7
#[inline(always)]
pub fn linear_to_srgb_simd<D: SimdDescriptor>(d: D, samples: &mut [f32]) {
    #[allow(clippy::excessive_precision)]
    const P: [f32; 5] = [
        -5.135152395e-4,
        5.287254571e-3,
        3.903842876e-1,
        1.474205315,
        7.352629620e-1,
    ];

    #[allow(clippy::excessive_precision)]
    const Q: [f32; 5] = [
        1.004519624e-2,
        3.036675394e-1,
        1.340816930,
        9.258482155e-1,
        2.424867759e-2,
    ];

    for vec in samples.chunks_exact_mut(D::F32Vec::LEN) {
        let x = D::F32Vec::load(d, vec);
        let a = x.abs();
        D::F32Vec::splat(d, 0.0031308)
            .gt(a)
            .if_then_else_f32(
                a * D::F32Vec::splat(d, 12.92),
                eval_rational_poly_simd(d, a.sqrt(), P, Q),
            )
            .copysign(x)
            .store(vec);
    }
}

/// Converts samples in sRGB transfer curve to linear. Inverse of `linear_to_srgb`.
pub fn srgb_to_linear(samples: &mut [f32]) {
    #[allow(clippy::excessive_precision)]
    const P: [f32; 5] = [
        2.200248328e-4,
        1.043637593e-2,
        1.624820318e-1,
        7.961564959e-1,
        8.210152774e-1,
    ];

    #[allow(clippy::excessive_precision)]
    const Q: [f32; 5] = [
        2.631846970e-1,
        1.076976492,
        4.987528350e-1,
        -5.512498495e-2,
        6.521209011e-3,
    ];

    for x in samples {
        let a = x.abs();
        *x = if a <= 0.04045 {
            a / 12.92
        } else {
            eval_rational_poly(a, P, Q)
        }
        .copysign(*x);
    }
}

#[inline(always)]
pub fn srgb_to_linear_simd<D: SimdDescriptor>(d: D, samples: &mut [f32]) {
    #[allow(clippy::excessive_precision)]
    const P: [f32; 5] = [
        2.200248328e-4,
        1.043637593e-2,
        1.624820318e-1,
        7.961564959e-1,
        8.210152774e-1,
    ];

    #[allow(clippy::excessive_precision)]
    const Q: [f32; 5] = [
        2.631846970e-1,
        1.076976492,
        4.987528350e-1,
        -5.512498495e-2,
        6.521209011e-3,
    ];

    for vec in samples.chunks_exact_mut(D::F32Vec::LEN) {
        let x = D::F32Vec::load(d, vec);
        let a = x.abs();
        D::F32Vec::splat(d, 0.04045)
            .gt(a)
            .if_then_else_f32(
                a / D::F32Vec::splat(d, 12.92),
                eval_rational_poly_simd(d, a, P, Q),
            )
            .copysign(x)
            .store(vec);
    }
}

/// Converts the linear samples with the BT.709 transfer curve (SIMD version).
// Rational polynomial approximation of 1.099 * x^0.45 - 0.099 on sqrt(x).
// Max error ~3e-7
#[inline(always)]
pub fn linear_to_bt709_simd<D: SimdDescriptor>(d: D, samples: &mut [f32]) {
    // Coefficients for rational polynomial P(y)/Q(y) where y = sqrt(x)
    // Approximates 1.099 * y^0.9 - 0.099 on [sqrt(0.018), 1]
    #[allow(clippy::excessive_precision)]
    const P: [f32; 5] = [
        -9.625309705734253e-2,
        -2.2635456919670105e-1,
        1.935774803161621e1,
        5.897886276245117e1,
        2.3947298049926758e1,
    ];

    #[allow(clippy::excessive_precision)]
    const Q: [f32; 5] = [
        1.0,
        1.877663230895996e1,
        5.5292449951171875e1,
        2.6565317153930664e1,
        3.269049823284149e-1,
    ];

    for vec in samples.chunks_exact_mut(D::F32Vec::LEN) {
        let x = D::F32Vec::load(d, vec);
        let a = x.abs();
        D::F32Vec::splat(d, 0.018)
            .gt(a)
            .if_then_else_f32(
                a * D::F32Vec::splat(d, 4.5),
                eval_rational_poly_simd(d, a.sqrt(), P, Q),
            )
            .copysign(x)
            .store(vec);
    }
}

/// Converts samples in BT.709 transfer curve to linear. Inverse of `linear_to_bt709_simd`.
pub fn bt709_to_linear(samples: &mut [f32]) {
    for s in samples {
        let a = s.abs();
        *s = if a <= 0.081 {
            a / 4.5
        } else {
            crate::util::fast_powf(a.mul_add(1.0 / 1.0990.099 / 1.099), 1.0 / 0.45)
        }
        .copysign(*s);
    }
}

/// Converts samples in BT.709 transfer curve to linear (SIMD version).
#[inline(always)]
pub fn bt709_to_linear_simd<D: SimdDescriptor>(d: D, xsize: usize, samples: &mut [f32]) {
    let threshold = D::F32Vec::splat(d, 0.081);
    let inv_4_5 = D::F32Vec::splat(d, 1.0 / 4.5);
    let scale = D::F32Vec::splat(d, 1.0 / 1.099);
    let offset = D::F32Vec::splat(d, 0.099 / 1.099);
    let exp = D::F32Vec::splat(d, 1.0 / 0.45);

    for vec in samples
        .chunks_exact_mut(D::F32Vec::LEN)
        .take(xsize.div_ceil(D::F32Vec::LEN))
    {
        let x = D::F32Vec::load(d, vec);
        let a = x.abs();
        let linear_part = a * inv_4_5;
        let gamma_part = crate::util::fast_powf_simd(d, a.mul_add(scale, offset), exp);
        threshold
            .gt(a)
            .if_then_else_f32(linear_part, gamma_part)
            .copysign(x)
            .store(vec);
    }
}

const PQ_M1: f64 = 2610.0 / 16384.0;
const PQ_M2: f64 = (2523.0 / 4096.0) * 128.0;
const PQ_C1: f64 = 3424.0 / 4096.0;
const PQ_C2: f64 = (2413.0 / 4096.0) * 32.0;
const PQ_C3: f64 = (2392.0 / 4096.0) * 32.0;

/// Converts linear sample to PQ signal using PQ inverse EOTF, where linear sample value of 1.0
/// represents `intensity_target` display nits.
///
/// This version uses original EOTF using double precision arithmetic internally.
pub fn linear_to_pq_precise(intensity_target: f32, samples: &mut [f32]) {
    let mult = intensity_target as f64 * 10000f64.recip();

    for s in samples {
        if *s == 0.0 {
            continue;
        }

        let a = s.abs() as f64;
        let xp = (a * mult).powf(PQ_M1);
        let num = PQ_C1 + xp * PQ_C2;
        let den = 1.0 + xp * PQ_C3;
        let e = (num / den).powf(PQ_M2);
        *s = (e as f32).copysign(*s);
    }
}

/// Converts PQ signal to linear sample using PQ EOTF, where linear sample value of 1.0 represents
/// `intensity_target` display nits.
///
/// This version uses original EOTF using double precision arithmetic internally.
pub fn pq_to_linear_precise(intensity_target: f32, samples: &mut [f32]) {
    let mult = 10000.0 / intensity_target as f64;

    for s in samples {
        if *s == 0.0 {
            continue;
        }

        let a = s.abs() as f64;
        let xp = a.powf(PQ_M2.recip());
        let num = (xp - PQ_C1).max(0.0);
        let den = PQ_C2 - PQ_C3 * xp;
        let y = (num / den).powf(PQ_M1.recip());
        *s = ((y * mult) as f32).copysign(*s);
    }
}

const PQ_EOTF_P: [f32; 5] = [
    2.6297566e-4,
    -6.235531e-3,
    7.386023e-1,
    2.6455317,
    5.500349e-1,
];
const PQ_EOTF_Q: [f32; 5] = [
    4.213501e2,
    -4.2873682e2,
    1.7436467e2,
    -3.3907887e1,
    2.6771877,
];

const PQ_INV_EOTF_P: [f32; 5] = [1.351392e-2, -1.0957785.522776e1, 1.492516e2, 4.838434e1];
const PQ_INV_EOTF_Q: [f32; 5] = [1.0124162.016708e1, 9.26371e1, 1.120607e2, 2.590418e1];
const PQ_INV_EOTF_P_SMALL: [f32; 5] = [
    9.863406e-6,
    3.881234e-1,
    1.352821e2,
    6.889862e4,
    -2.864824e5,
];
const PQ_INV_EOTF_Q_SMALL: [f32; 5] =
    [3.371868e1, 1.477719e3, 1.608477e4, -4.389884e4, -2.072546e5];

/// Converts linear sample to PQ signal using PQ inverse EOTF, where linear sample value of 1.0
/// represents `intensity_target` display nits.
///
/// This version uses approximate curve using rational polynomial.
// Max error: ~7e-7 at intensity_target = 10000
pub fn linear_to_pq(intensity_target: f32, samples: &mut [f32]) {
    let y_mult = intensity_target * 10000f32.recip();

    for s in samples {
        let a = s.abs();
        let a_scaled = a * y_mult;
        let a_1_4 = a_scaled.sqrt().sqrt();

        let y = if a < 1e-4 {
            eval_rational_poly(a_1_4, PQ_INV_EOTF_P_SMALL, PQ_INV_EOTF_Q_SMALL)
        } else {
            eval_rational_poly(a_1_4, PQ_INV_EOTF_P, PQ_INV_EOTF_Q)
        };

        *s = y.copysign(*s);
    }
}

/// Converts linear sample to PQ signal using PQ inverse EOTF (SIMD version).
#[inline(always)]
pub fn linear_to_pq_simd<D: SimdDescriptor>(
    d: D,
    intensity_target: f32,
    xsize: usize,
    samples: &mut [f32],
) {
    let y_mult = D::F32Vec::splat(d, intensity_target * 10000f32.recip());
    let threshold = D::F32Vec::splat(d, 1e-4);

    for vec in samples
        .chunks_exact_mut(D::F32Vec::LEN)
        .take(xsize.div_ceil(D::F32Vec::LEN))
    {
        let s = D::F32Vec::load(d, vec);
        let a = s.abs();
        let a_scaled = a * y_mult;
        let a_1_4 = a_scaled.sqrt().sqrt();

        // Use small polynomial for a < 1e-4, regular polynomial otherwise
        let y_small = eval_rational_poly_simd(d, a_1_4, PQ_INV_EOTF_P_SMALL, PQ_INV_EOTF_Q_SMALL);
        let y_large = eval_rational_poly_simd(d, a_1_4, PQ_INV_EOTF_P, PQ_INV_EOTF_Q);
        let y = threshold.gt(a).if_then_else_f32(y_small, y_large);

        y.copysign(s).store(vec);
    }
}

/// Converts PQ signal to linear sample using PQ EOTF, where linear sample value of 1.0 represents
/// `intensity_target` display nits.
///
/// This version uses approximate curve using rational polynomial.
// Max error: ~3e-6 at intensity_target = 10000
pub fn pq_to_linear(intensity_target: f32, samples: &mut [f32]) {
    let y_mult = 10000.0 / intensity_target;

    for s in samples {
        let a = s.abs();
        // a + a * a
        let x = a.mul_add(a, a);
        let y = eval_rational_poly(x, PQ_EOTF_P, PQ_EOTF_Q);
        *s = (y * y_mult).copysign(*s);
    }
}

/// Converts PQ signal to linear sample using PQ EOTF (SIMD version).
#[inline(always)]
pub fn pq_to_linear_simd<D: SimdDescriptor>(
    d: D,
    intensity_target: f32,
    xsize: usize,
    samples: &mut [f32],
) {
    let y_mult = D::F32Vec::splat(d, 10000.0 / intensity_target);

    for vec in samples
        .chunks_exact_mut(D::F32Vec::LEN)
        .take(xsize.div_ceil(D::F32Vec::LEN))
    {
        let s = D::F32Vec::load(d, vec);
        let a = s.abs();
        // a + a * a
        let x = a.mul_add(a, a);
        let y = eval_rational_poly_simd(d, x, PQ_EOTF_P, PQ_EOTF_Q);
        (y * y_mult).copysign(s).store(vec);
    }
}

const HLG_A: f64 = 0.17883277;
const HLG_B: f64 = 1.0 - 4.0 * HLG_A;
const HLG_C: f64 = 0.5599107295;

fn hlg_ootf_inner_precise(exp: f64, [lr, lg, lb]: [f32; 3], [sr, sg, sb]: [&mut [f32]; 3]) {
    if exp.abs() < 0.1 {
        return;
    }

    let lr = lr as f64;
    let lg = lg as f64;
    let lb = lb as f64;
    for ((r, g), b) in std::iter::zip(sr, sg).zip(sb) {
        let dr = *r as f64;
        let dg = *g as f64;
        let db = *b as f64;
        let mixed = dr.mul_add(lr, dg.mul_add(lg, db * lb));
        let mult = mixed.powf(exp);
        *r = (dr * mult) as f32;
        *g = (dg * mult) as f32;
        *b = (db * mult) as f32;
    }
}

fn hlg_ootf_inner(exp: f32, [lr, lg, lb]: [f32; 3], [sr, sg, sb]: [&mut [f32]; 3]) {
    if exp.abs() < 0.1 {
        return;
    }

    for ((r, g), b) in std::iter::zip(sr, sg).zip(sb) {
        let mixed = r.mul_add(lr, g.mul_add(lg, *b * lb));
        let mult = crate::util::fast_powf(mixed, exp);
        *r *= mult;
        *g *= mult;
        *b *= mult;
    }
}

/// Converts scene-referred linear samples to display-referred linear samples using HLG OOTF.
///
/// This version uses double precision arithmetic internally.
pub fn hlg_scene_to_display_precise(
    intensity_display: f32,
    luminance_rgb: [f32; 3],
    samples_rgb: [&mut [f32]; 3],
) {
    let system_gamma = 1.2f64 * 1.111f64.powf((intensity_display as f64 / 1e3).log2());
    let gamma_sub_one = system_gamma - 1.0;
    hlg_ootf_inner_precise(gamma_sub_one, luminance_rgb, samples_rgb);
}

/// Converts display-referred linear samples to scene-referred linear samples using HLG inverse
/// OOTF.
///
/// This version uses double precision arithmetic internally.
pub fn hlg_display_to_scene_precise(
    intensity_display: f32,
    luminance_rgb: [f32; 3],
    samples_rgb: [&mut [f32]; 3],
) {
    let system_gamma = 1.2f64 * 1.111f64.powf((intensity_display as f64 / 1e3).log2());
    let one_sub_gamma = 1.0 - system_gamma;
    hlg_ootf_inner_precise(one_sub_gamma / system_gamma, luminance_rgb, samples_rgb);
}

/// Converts scene-referred linear samples to display-referred linear samples using HLG OOTF.
///
/// This version uses `fast_powf` to compute power function.
pub fn hlg_scene_to_display(
    intensity_display: f32,
    luminance_rgb: [f32; 3],
    samples_rgb: [&mut [f32]; 3],
) {
    let system_gamma = 1.2f32 * 1.111f32.powf((intensity_display / 1e3).log2());
    let gamma_sub_one = system_gamma - 1.0;
    hlg_ootf_inner(gamma_sub_one, luminance_rgb, samples_rgb);
}

/// Converts display-referred linear samples to scene-referred linear samples using HLG inverse
/// OOTF.
///
/// This version uses `fast_powf` to compute power function.
pub fn hlg_display_to_scene(
    intensity_display: f32,
    luminance_rgb: [f32; 3],
    samples_rgb: [&mut [f32]; 3],
) {
    let system_gamma = 1.2f32 * 1.111f32.powf((intensity_display / 1e3).log2());
    let one_sub_gamma = 1.0 - system_gamma;
    hlg_ootf_inner(one_sub_gamma / system_gamma, luminance_rgb, samples_rgb);
}

/// Converts scene-referred linear sample to HLG signal.
///
/// This version uses double precision arithmetic internally.
pub fn scene_to_hlg_precise(samples: &mut [f32]) {
    for s in samples {
        let a = s.abs() as f64;
        let y = if a <= 1.0 / 12.0 {
            (3.0 * a).sqrt()
        } else {
            // TODO(tirr-c): maybe use mul_add?
            HLG_A * (12.0 * a - HLG_B).ln() + HLG_C
        };
        *s = (y as f32).copysign(*s);
    }
}

/// Converts HLG signal to scene-referred linear sample.
///
/// This version uses double precision arithmetic internally.
pub fn hlg_to_scene_precise(samples: &mut [f32]) {
    for s in samples {
        let a = s.abs() as f64;
        let y = if a <= 0.5 {
            a * a / 3.0
        } else {
            (((a - HLG_C) / HLG_A).exp() + HLG_B) / 12.0
        };
        *s = (y as f32).copysign(*s);
    }
}

/// Converts scene-referred linear sample to HLG signal.
///
/// This version uses `fast_log2f` to apply logarithmic function.
// Max error: ~5e-7
pub fn scene_to_hlg(samples: &mut [f32]) {
    for s in samples {
        let a = s.abs();
        let y = if a <= 1.0 / 12.0 {
            (3.0 * a).sqrt()
        } else {
            // TODO(tirr-c): maybe use mul_add?
            let log = crate::util::fast_log2f(12.0 * a - HLG_B as f32);
            // log2 x = ln x / ln 2, therefore ln x = (ln 2)(log2 x)
            (HLG_A * std::f64::consts::LN_2) as f32 * log + HLG_C as f32
        };
        *s = y.copysign(*s);
    }
}

/// Converts HLG signal to scene-referred linear sample.
///
/// This version uses `fast_pow2f` to apply logarithmic function.
// Max error: ~5e-6
pub fn hlg_to_scene(samples: &mut [f32]) {
    for s in samples {
        let a = s.abs();
        let y = if a <= 0.5 {
            a * a / 3.0
        } else {
            const POW: f32 = (std::f64::consts::LOG2_E / HLG_A) as f32;
            const ADD: f32 = (HLG_B / 12.0as f32;
            // TODO(OneDeuxTriSeiGo): replace raw constant with the below equation
            // when std::f64::exp() can is available as a const fn.
            //
            // Equation: ((-HLG_B / HLG_A).exp() / 12.0)
            // Constant: 0.003_639_807_079_052_639
            const MUL: f32 = 0.003_639_807;

            // TODO(OneDeuxTriSeiGo): maybe use mul_add?
            crate::util::fast_pow2f(a * POW) * MUL + ADD
        };
        *s = y.copysign(*s);
    }
}

#[cfg(test)]
mod test {
    use test_log::test;

    use super::*;
    use crate::util::test::assert_all_almost_abs_eq;

    fn arb_samples(
        u: &mut arbtest::arbitrary::Unstructured,
    ) -> arbtest::arbitrary::Result<Vec<f32>> {
        const DENOM: u32 = 1 << 24;

        let mut samples = Vec::new();

        // uniform distribution in [-1.0, 1.0]
        while !u.is_empty() {
            let a: u32 = u.int_in_range(0..=DENOM)?;
            let signed: bool = u.arbitrary()?;
            let x = a as f32 / DENOM as f32;
            samples.push(if signed { -x } else { x });
        }

        Ok(samples)
    }

    /// Naive linear to sRGB using actual pow for testing.
    fn linear_to_srgb_naive(samples: &mut [f32]) {
        for x in samples {
            let a = x.abs();
            *x = if a <= 0.0031308 {
                a * 12.92
            } else {
                a.powf(1.0 / 2.4).mul_add(1.055, -0.055)
            }
            .copysign(*x);
        }
    }

    /// Naive linear to BT.709 using actual pow for testing.
    fn linear_to_bt709_naive(samples: &mut [f32]) {
        for x in samples {
            let a = x.abs();
            *x = if a <= 0.018 {
                a * 4.5
            } else {
                a.powf(0.45).mul_add(1.099, -0.099)
            }
            .copysign(*x);
        }
    }

    #[test]
    fn srgb_roundtrip_arb() {
        arbtest::arbtest(|u| {
            let samples = arb_samples(u)?;
            let mut output = samples.clone();

            linear_to_srgb_simd(jxl_simd::ScalarDescriptor::new().unwrap(), &mut output);
            srgb_to_linear(&mut output);
            assert_all_almost_abs_eq(&output, &samples, 2e-6);
            Ok(())
        });
    }

    #[test]
    fn bt709_roundtrip_arb() {
        arbtest::arbtest(|u| {
            let samples = arb_samples(u)?;
            let mut output = samples.clone();

            linear_to_bt709_simd(jxl_simd::ScalarDescriptor::new().unwrap(), &mut output);
            bt709_to_linear(&mut output);
            assert_all_almost_abs_eq(&output, &samples, 5e-6);
            Ok(())
        });
    }

    #[test]
    fn linear_to_srgb_simd_arb() {
        arbtest::arbtest(|u| {
            let mut samples = arb_samples(u)?;
            let mut simd = samples.clone();

            linear_to_srgb_naive(&mut samples);
            linear_to_srgb_simd(jxl_simd::ScalarDescriptor::new().unwrap(), &mut simd);
            assert_all_almost_abs_eq(&samples, &simd, 1e-6);
            Ok(())
        });
    }

    #[test]
    fn linear_to_bt709_simd_arb() {
        arbtest::arbtest(|u| {
            let mut samples = arb_samples(u)?;
            let mut simd = samples.clone();

            linear_to_bt709_naive(&mut samples);
            linear_to_bt709_simd(jxl_simd::ScalarDescriptor::new().unwrap(), &mut simd);
            assert_all_almost_abs_eq(&samples, &simd, 1e-6);
            Ok(())
        });
    }

    #[test]
    fn linear_to_pq_arb() {
        arbtest::arbtest(|u| {
            let intensity_target = u.int_in_range(9900..=10100)? as f32;
            let mut samples = arb_samples(u)?;
            let mut precise = samples.clone();

            linear_to_pq(intensity_target, &mut samples);
            linear_to_pq_precise(intensity_target, &mut precise);
            // Error seems to increase at intensity_target < 10000
            assert_all_almost_abs_eq(&samples, &precise, 8e-7);
            Ok(())
        });
    }

    #[test]
    fn pq_to_linear_arb() {
        arbtest::arbtest(|u| {
            let intensity_target = u.int_in_range(9900..=10100)? as f32;
            let mut samples = arb_samples(u)?;
            let mut precise = samples.clone();

            pq_to_linear(intensity_target, &mut samples);
            pq_to_linear_precise(intensity_target, &mut precise);
            assert_all_almost_abs_eq(&samples, &precise, 3e-6);
            Ok(())
        });
    }

    #[test]
    fn bt709_to_linear_simd_arb() {
        arbtest::arbtest(|u| {
            let mut samples = arb_samples(u)?;
            let mut simd = samples.clone();
            let xsize = samples.len();

            bt709_to_linear(&mut samples);
            bt709_to_linear_simd(jxl_simd::ScalarDescriptor::new().unwrap(), xsize, &='color:red'>mut simd);
            assert_all_almost_abs_eq(&samples, &simd, 1e-5);
            Ok(())
        });
    }

    #[test]
    fn pq_to_linear_simd_arb() {
        arbtest::arbtest(|u| {
            let intensity_target = u.int_in_range(9900..=10100)? as f32;
            let mut samples = arb_samples(u)?;
            let mut simd = samples.clone();
            let xsize = samples.len();

            pq_to_linear(intensity_target, &mut samples);
            pq_to_linear_simd(
                jxl_simd::ScalarDescriptor::new().unwrap(),
                intensity_target,
                xsize,
                &mut simd,
            );
            assert_all_almost_abs_eq(&samples, &simd, 2e-5);
            Ok(())
        });
    }

    #[test]
    fn linear_to_pq_simd_arb() {
        arbtest::arbtest(|u| {
            let intensity_target = u.int_in_range(9900..=10100)? as f32;
            let mut samples = arb_samples(u)?;
            let mut simd = samples.clone();
            let xsize = samples.len();

            linear_to_pq(intensity_target, &mut samples);
            linear_to_pq_simd(
                jxl_simd::ScalarDescriptor::new().unwrap(),
                intensity_target,
                xsize,
                &mut simd,
            );
            assert_all_almost_abs_eq(&samples, &simd, 2e-5);
            Ok(())
        });
    }

    #[test]
    fn hlg_ootf_arb() {
        arbtest::arbtest(|u| {
            let intensity_target = u.int_in_range(900..=1100)? as f32;

            let lr = 0.2 + u.int_in_range(0..=255)? as f32 / 255.0;
            let lb = 0.2 + u.int_in_range(0..=255)? as f32 / 255.0;
            let lg = 1.0 - lr - lb;
            let luminance_rgb = [lr, lg, lb];

            let r = u.int_in_range(0u32..=(1 << 24))? as f32 / (1 << 24as f32;
            let g = u.int_in_range(0u32..=(1 << 24))? as f32 / (1 << 24as f32;
            let b = u.int_in_range(0u32..=(1 << 24))? as f32 / (1 << 24as f32;

            let mut fast_r = r;
            let mut fast_g = g;
            let mut fast_b = b;
            let fast = [
                std::slice::from_mut(&mut fast_r),
                std::slice::from_mut(&mut fast_g),
                std::slice::from_mut(&mut fast_b),
            ];
            hlg_display_to_scene(intensity_target, luminance_rgb, fast);

            let mut precise_r = r;
            let mut precise_g = g;
            let mut precise_b = b;
            let precise = [
                std::slice::from_mut(&mut precise_r),
                std::slice::from_mut(&mut precise_g),
                std::slice::from_mut(&mut precise_b),
            ];
            hlg_display_to_scene(intensity_target, luminance_rgb, precise);

            assert_all_almost_abs_eq(
                &[fast_r, fast_g, fast_b],
                &[precise_r, precise_g, precise_b],
                7.2e-7,
            );

            let mut fast_r = r;
            let mut fast_g = g;
            let mut fast_b = b;
            let fast = [
                std::slice::from_mut(&mut fast_r),
                std::slice::from_mut(&mut fast_g),
                std::slice::from_mut(&mut fast_b),
            ];
            hlg_scene_to_display(intensity_target, luminance_rgb, fast);

            let mut precise_r = r;
            let mut precise_g = g;
            let mut precise_b = b;
            let precise = [
                std::slice::from_mut(&mut precise_r),
                std::slice::from_mut(&mut precise_g),
                std::slice::from_mut(&mut precise_b),
            ];
            hlg_scene_to_display(intensity_target, luminance_rgb, precise);

            assert_all_almost_abs_eq(
                &[fast_r, fast_g, fast_b],
                &[precise_r, precise_g, precise_b],
                7.2e-7,
            );

            Ok(())
        });
    }

    #[test]
    fn scene_to_hlg_arb() {
        arbtest::arbtest(|u| {
            let mut samples = arb_samples(u)?;
            let mut precise = samples.clone();

            scene_to_hlg(&mut samples);
            scene_to_hlg_precise(&mut precise);
            assert_all_almost_abs_eq(&samples, &precise, 5e-7);
            Ok(())
        });
    }

    #[test]
    fn hlg_to_scene_arb() {
        arbtest::arbtest(|u| {
            let mut samples = arb_samples(u)?;
            let mut precise = samples.clone();

            hlg_to_scene(&mut samples);
            hlg_to_scene_precise(&mut precise);
            assert_all_almost_abs_eq(&samples, &precise, 5e-6);
            Ok(())
        });
    }
}

Messung V0.5 in Prozent
C=94 H=99 G=96

¤ Dauer der Verarbeitung: 0.10 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=277311
#Domains=752002