libjxl

FORK: libjxl patches used on blog
git clone https://git.neptards.moe/blog/libjxl.git
Log | Files | Refs | Submodules | README | LICENSE

tone_mapping-inl.h (7008B)


      1 // Copyright (c) the JPEG XL Project Authors. All rights reserved.
      2 //
      3 // Use of this source code is governed by a BSD-style
      4 // license that can be found in the LICENSE file.
      5 
      6 #if defined(LIB_JXL_CMS_TONE_MAPPING_INL_H_) == defined(HWY_TARGET_TOGGLE)
      7 #ifdef LIB_JXL_CMS_TONE_MAPPING_INL_H_
      8 #undef LIB_JXL_CMS_TONE_MAPPING_INL_H_
      9 #else
     10 #define LIB_JXL_CMS_TONE_MAPPING_INL_H_
     11 #endif
     12 
     13 #include <hwy/highway.h>
     14 
     15 #include "lib/jxl/cms/tone_mapping.h"
     16 #include "lib/jxl/cms/transfer_functions-inl.h"
     17 
     18 HWY_BEFORE_NAMESPACE();
     19 namespace jxl {
     20 namespace HWY_NAMESPACE {
     21 namespace {
     22 
     23 // These templates are not found via ADL.
     24 using hwy::HWY_NAMESPACE::Clamp;
     25 using hwy::HWY_NAMESPACE::Max;
     26 using hwy::HWY_NAMESPACE::ZeroIfNegative;
     27 
     28 template <typename D>
     29 class Rec2408ToneMapper : Rec2408ToneMapperBase {
     30  private:
     31   using V = hwy::HWY_NAMESPACE::Vec<D>;
     32 
     33  public:
     34   using Rec2408ToneMapperBase::Rec2408ToneMapperBase;
     35 
     36   void ToneMap(V* red, V* green, V* blue) const {
     37     const V luminance = Mul(Set(df_, source_range_.second),
     38                             (MulAdd(Set(df_, red_Y_), *red,
     39                                     MulAdd(Set(df_, green_Y_), *green,
     40                                            Mul(Set(df_, blue_Y_), *blue)))));
     41     const V pq_mastering_min = Set(df_, pq_mastering_min_);
     42     const V inv_pq_mastering_range = Set(df_, inv_pq_mastering_range_);
     43     const V normalized_pq = Min(
     44         Set(df_, 1.f),
     45         Mul(Sub(InvEOTF(luminance), pq_mastering_min), inv_pq_mastering_range));
     46     const V ks = Set(df_, ks_);
     47     const V e2 =
     48         IfThenElse(Lt(normalized_pq, ks), normalized_pq, P(normalized_pq));
     49     const V one_minus_e2 = Sub(Set(df_, 1), e2);
     50     const V one_minus_e2_2 = Mul(one_minus_e2, one_minus_e2);
     51     const V one_minus_e2_4 = Mul(one_minus_e2_2, one_minus_e2_2);
     52     const V b = Set(df_, min_lum_);
     53     const V e3 = MulAdd(b, one_minus_e2_4, e2);
     54     const V pq_mastering_range = Set(df_, pq_mastering_range_);
     55     const V e4 = MulAdd(e3, pq_mastering_range, pq_mastering_min);
     56     const V new_luminance =
     57         Min(Set(df_, target_range_.second),
     58             ZeroIfNegative(tf_pq_.DisplayFromEncoded(df_, e4)));
     59     const V min_luminance = Set(df_, 1e-6f);
     60     const auto use_cap = Le(luminance, min_luminance);
     61     const V ratio = Div(new_luminance, Max(luminance, min_luminance));
     62     const V cap = Mul(new_luminance, Set(df_, inv_target_peak_));
     63     const V normalizer = Set(df_, normalizer_);
     64     const V multiplier = Mul(ratio, normalizer);
     65     for (V* const val : {red, green, blue}) {
     66       *val = IfThenElse(use_cap, cap, Mul(*val, multiplier));
     67     }
     68   }
     69 
     70  private:
     71   V InvEOTF(const V luminance) const {
     72     return tf_pq_.EncodedFromDisplay(df_, luminance);
     73   }
     74   V T(const V a) const {
     75     const V ks = Set(df_, ks_);
     76     const V inv_one_minus_ks = Set(df_, inv_one_minus_ks_);
     77     return Mul(Sub(a, ks), inv_one_minus_ks);
     78   }
     79   V P(const V b) const {
     80     const V t_b = T(b);
     81     const V t_b_2 = Mul(t_b, t_b);
     82     const V t_b_3 = Mul(t_b_2, t_b);
     83     const V ks = Set(df_, ks_);
     84     const V max_lum = Set(df_, max_lum_);
     85     return MulAdd(
     86         MulAdd(Set(df_, 2), t_b_3, MulAdd(Set(df_, -3), t_b_2, Set(df_, 1))),
     87         ks,
     88         MulAdd(Add(t_b_3, MulAdd(Set(df_, -2), t_b_2, t_b)),
     89                Sub(Set(df_, 1), ks),
     90                Mul(MulAdd(Set(df_, -2), t_b_3, Mul(Set(df_, 3), t_b_2)),
     91                    max_lum)));
     92   }
     93 
     94   D df_;
     95   const TF_PQ tf_pq_ = TF_PQ(/*display_intensity_target=*/1.0);
     96 };
     97 
     98 class HlgOOTF : HlgOOTF_Base {
     99  public:
    100   using HlgOOTF_Base::HlgOOTF_Base;
    101 
    102   static HlgOOTF FromSceneLight(float display_luminance,
    103                                 const float primaries_luminances[3]) {
    104     return HlgOOTF(/*gamma=*/1.2f *
    105                        std::pow(1.111f, std::log2(display_luminance / 1000.f)),
    106                    primaries_luminances);
    107   }
    108 
    109   static HlgOOTF ToSceneLight(float display_luminance,
    110                               const float primaries_luminances[3]) {
    111     return HlgOOTF(
    112         /*gamma=*/(1 / 1.2f) *
    113             std::pow(1.111f, -std::log2(display_luminance / 1000.f)),
    114         primaries_luminances);
    115   }
    116 
    117   template <typename V>
    118   void Apply(V* red, V* green, V* blue) const {
    119     hwy::HWY_NAMESPACE::DFromV<V> df;
    120     if (!apply_ootf_) return;
    121     const V luminance =
    122         MulAdd(Set(df, red_Y_), *red,
    123                MulAdd(Set(df, green_Y_), *green, Mul(Set(df, blue_Y_), *blue)));
    124     const V ratio =
    125         Min(FastPowf(df, luminance, Set(df, exponent_)), Set(df, 1e9));
    126     *red = Mul(*red, ratio);
    127     *green = Mul(*green, ratio);
    128     *blue = Mul(*blue, ratio);
    129   }
    130 
    131   bool WarrantsGamutMapping() const { return apply_ootf_ && exponent_ < 0; }
    132 };
    133 
    134 template <typename V>
    135 void GamutMap(V* red, V* green, V* blue, const float primaries_luminances[3],
    136               float preserve_saturation = 0.1f) {
    137   hwy::HWY_NAMESPACE::DFromV<V> df;
    138   const V luminance =
    139       MulAdd(Set(df, primaries_luminances[0]), *red,
    140              MulAdd(Set(df, primaries_luminances[1]), *green,
    141                     Mul(Set(df, primaries_luminances[2]), *blue)));
    142 
    143   // Desaturate out-of-gamut pixels. This is done by mixing each pixel
    144   // with just enough gray of the target luminance to make all
    145   // components non-negative.
    146   // - For saturation preservation, if a component is still larger than
    147   // 1 then the pixel is normalized to have a maximum component of 1.
    148   // That will reduce its luminance.
    149   // - For luminance preservation, getting all components below 1 is
    150   // done by mixing in yet more gray. That will desaturate it further.
    151   const V zero = Zero(df);
    152   const V one = Set(df, 1);
    153   V gray_mix_saturation = zero;
    154   V gray_mix_luminance = zero;
    155   for (const V* ch : {red, green, blue}) {
    156     const V& val = *ch;
    157     const V val_minus_gray = Sub(val, luminance);
    158     const V inv_val_minus_gray =
    159         Div(one, IfThenElse(Eq(val_minus_gray, zero), one, val_minus_gray));
    160     const V val_over_val_minus_gray = Mul(val, inv_val_minus_gray);
    161     gray_mix_saturation =
    162         IfThenElse(Ge(val_minus_gray, zero), gray_mix_saturation,
    163                    Max(gray_mix_saturation, val_over_val_minus_gray));
    164     gray_mix_luminance =
    165         Max(gray_mix_luminance,
    166             IfThenElse(Le(val_minus_gray, zero), gray_mix_saturation,
    167                        Sub(val_over_val_minus_gray, inv_val_minus_gray)));
    168   }
    169   const V gray_mix = Clamp(
    170       MulAdd(Set(df, preserve_saturation),
    171              Sub(gray_mix_saturation, gray_mix_luminance), gray_mix_luminance),
    172       zero, one);
    173   for (V* const ch : {red, green, blue}) {
    174     V& val = *ch;
    175     val = MulAdd(gray_mix, Sub(luminance, val), val);
    176   }
    177   const V max_clr = Max(Max(one, *red), Max(*green, *blue));
    178   const V normalizer = Div(one, max_clr);
    179   for (V* const ch : {red, green, blue}) {
    180     V& val = *ch;
    181     val = Mul(val, normalizer);
    182   }
    183 }
    184 
    185 }  // namespace
    186 // NOLINTNEXTLINE(google-readability-namespace-comments)
    187 }  // namespace HWY_NAMESPACE
    188 }  // namespace jxl
    189 HWY_AFTER_NAMESPACE();
    190 
    191 #endif  // LIB_JXL_CMS_TONE_MAPPING_INL_H_