Coverage Report

Created: 2025-06-16 07:00

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