Coverage Report

Created: 2026-10-28 07:26

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libjxl/lib/jxl/enc_group.cc
Line
Count
Source
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 "lib/jxl/enc_group.h"
7
8
#include <jxl/memory_manager.h>
9
10
#include <algorithm>
11
#include <cmath>
12
#include <cstddef>
13
#include <cstdint>
14
#include <cstdlib>
15
16
#include "lib/jxl/base/common.h"
17
#include "lib/jxl/base/status.h"
18
#include "lib/jxl/chroma_from_luma.h"
19
#include "lib/jxl/coeff_order_fwd.h"
20
#include "lib/jxl/enc_ans.h"
21
#include "lib/jxl/enc_bit_writer.h"
22
#include "lib/jxl/frame_dimensions.h"
23
#include "lib/jxl/memory_manager_internal.h"
24
25
#undef HWY_TARGET_INCLUDE
26
#define HWY_TARGET_INCLUDE "lib/jxl/enc_group.cc"
27
#include <hwy/foreach_target.h>
28
#include <hwy/highway.h>
29
30
#include "lib/jxl/ac_strategy.h"
31
#include "lib/jxl/base/bits.h"
32
#include "lib/jxl/base/compiler_specific.h"
33
#include "lib/jxl/base/rect.h"
34
#include "lib/jxl/common.h"  // kMaxNumPasses
35
#include "lib/jxl/dct_util.h"
36
#include "lib/jxl/dec_transforms-inl.h"
37
#include "lib/jxl/enc_aux_out.h"
38
#include "lib/jxl/enc_cache.h"
39
#include "lib/jxl/enc_params.h"
40
#include "lib/jxl/enc_transforms-inl.h"
41
#include "lib/jxl/image.h"
42
#include "lib/jxl/quantizer-inl.h"
43
#include "lib/jxl/quantizer.h"
44
#include "lib/jxl/simd_util.h"
45
HWY_BEFORE_NAMESPACE();
46
namespace jxl {
47
namespace HWY_NAMESPACE {
48
49
// These templates are not found via ADL.
50
using hwy::HWY_NAMESPACE::Abs;
51
using hwy::HWY_NAMESPACE::Ge;
52
using hwy::HWY_NAMESPACE::IfThenElse;
53
using hwy::HWY_NAMESPACE::IfThenElseZero;
54
using hwy::HWY_NAMESPACE::MaskFromVec;
55
using hwy::HWY_NAMESPACE::Round;
56
57
// NOTE: caller takes care of extracting quant from rect of RawQuantField.
58
void QuantizeBlockAC(const Quantizer& quantizer, const bool error_diffusion,
59
                     size_t c, float qm_multiplier, AcStrategyType quant_kind,
60
                     size_t xsize, size_t ysize, float* thresholds,
61
                     const float* JXL_RESTRICT block_in, const int32_t* quant,
62
11.3M
                     int32_t* JXL_RESTRICT block_out) {
63
11.3M
  const float* JXL_RESTRICT qm = quantizer.InvDequantMatrix(quant_kind, c);
64
11.3M
  float qac = quantizer.Scale() * (*quant);
65
  // Not SIMD-ified for now.
66
11.3M
  if (c != 1 && xsize * ysize >= 4) {
67
2.79M
    for (int i = 0; i < 4; ++i) {
68
2.23M
      thresholds[i] -= 0.00744f * xsize * ysize;
69
2.23M
      if (thresholds[i] < 0.5) {
70
470k
        thresholds[i] = 0.5;
71
470k
      }
72
2.23M
    }
73
559k
  }
74
11.3M
  HWY_CAPPED(float, kBlockDim) df;
75
11.3M
  HWY_CAPPED(int32_t, kBlockDim) di;
76
11.3M
  HWY_CAPPED(uint32_t, kBlockDim) du;
77
11.3M
  const auto quantv = Set(df, qac * qm_multiplier);
78
117M
  for (size_t y = 0; y < ysize * kBlockDim; y++) {
79
106M
    size_t yfix = static_cast<size_t>(y >= ysize * kBlockDim / 2) * 2;
80
106M
    const size_t off = y * kBlockDim * xsize;
81
303M
    for (size_t x = 0; x < xsize * kBlockDim; x += Lanes(df)) {
82
196M
      auto threshold = Zero(df);
83
196M
      if (xsize == 1) {
84
77.4M
        HWY_ALIGN uint32_t kMask[kBlockDim] = {0, 0, 0, 0, ~0u, ~0u, ~0u, ~0u};
85
77.4M
        const auto mask = MaskFromVec(BitCast(df, Load(du, kMask + x)));
86
77.4M
        threshold = IfThenElse(mask, Set(df, thresholds[yfix + 1]),
87
77.4M
                               Set(df, thresholds[yfix]));
88
119M
      } else {
89
        // Same for all lanes in the vector.
90
119M
        threshold = Set(
91
119M
            df,
92
119M
            thresholds[yfix + static_cast<size_t>(x >= xsize * kBlockDim / 2)]);
93
119M
      }
94
196M
      const auto q = Mul(Load(df, qm + off + x), quantv);
95
196M
      const auto in = Load(df, block_in + off + x);
96
196M
      const auto val = Mul(q, in);
97
196M
      const auto nzero_mask = Ge(Abs(val), threshold);
98
196M
      const auto v = ConvertTo(di, IfThenElseZero(nzero_mask, Round(val)));
99
196M
      Store(v, di, block_out + off + x);
100
196M
    }
101
106M
  }
102
11.3M
}
Unexecuted instantiation: jxl::N_SSE4::QuantizeBlockAC(jxl::Quantizer const&, bool, unsigned long, float, jxl::AcStrategyType, unsigned long, unsigned long, float*, float const*, int const*, int*)
jxl::N_AVX2::QuantizeBlockAC(jxl::Quantizer const&, bool, unsigned long, float, jxl::AcStrategyType, unsigned long, unsigned long, float*, float const*, int const*, int*)
Line
Count
Source
62
11.3M
                     int32_t* JXL_RESTRICT block_out) {
63
11.3M
  const float* JXL_RESTRICT qm = quantizer.InvDequantMatrix(quant_kind, c);
64
11.3M
  float qac = quantizer.Scale() * (*quant);
65
  // Not SIMD-ified for now.
66
11.3M
  if (c != 1 && xsize * ysize >= 4) {
67
2.79M
    for (int i = 0; i < 4; ++i) {
68
2.23M
      thresholds[i] -= 0.00744f * xsize * ysize;
69
2.23M
      if (thresholds[i] < 0.5) {
70
470k
        thresholds[i] = 0.5;
71
470k
      }
72
2.23M
    }
73
559k
  }
74
11.3M
  HWY_CAPPED(float, kBlockDim) df;
75
11.3M
  HWY_CAPPED(int32_t, kBlockDim) di;
76
11.3M
  HWY_CAPPED(uint32_t, kBlockDim) du;
77
11.3M
  const auto quantv = Set(df, qac * qm_multiplier);
78
117M
  for (size_t y = 0; y < ysize * kBlockDim; y++) {
79
106M
    size_t yfix = static_cast<size_t>(y >= ysize * kBlockDim / 2) * 2;
80
106M
    const size_t off = y * kBlockDim * xsize;
81
303M
    for (size_t x = 0; x < xsize * kBlockDim; x += Lanes(df)) {
82
196M
      auto threshold = Zero(df);
83
196M
      if (xsize == 1) {
84
77.4M
        HWY_ALIGN uint32_t kMask[kBlockDim] = {0, 0, 0, 0, ~0u, ~0u, ~0u, ~0u};
85
77.4M
        const auto mask = MaskFromVec(BitCast(df, Load(du, kMask + x)));
86
77.4M
        threshold = IfThenElse(mask, Set(df, thresholds[yfix + 1]),
87
77.4M
                               Set(df, thresholds[yfix]));
88
119M
      } else {
89
        // Same for all lanes in the vector.
90
119M
        threshold = Set(
91
119M
            df,
92
119M
            thresholds[yfix + static_cast<size_t>(x >= xsize * kBlockDim / 2)]);
93
119M
      }
94
196M
      const auto q = Mul(Load(df, qm + off + x), quantv);
95
196M
      const auto in = Load(df, block_in + off + x);
96
196M
      const auto val = Mul(q, in);
97
196M
      const auto nzero_mask = Ge(Abs(val), threshold);
98
196M
      const auto v = ConvertTo(di, IfThenElseZero(nzero_mask, Round(val)));
99
196M
      Store(v, di, block_out + off + x);
100
196M
    }
101
106M
  }
102
11.3M
}
Unexecuted instantiation: jxl::N_AVX3::QuantizeBlockAC(jxl::Quantizer const&, bool, unsigned long, float, jxl::AcStrategyType, unsigned long, unsigned long, float*, float const*, int const*, int*)
Unexecuted instantiation: jxl::N_AVX3_ZEN4::QuantizeBlockAC(jxl::Quantizer const&, bool, unsigned long, float, jxl::AcStrategyType, unsigned long, unsigned long, float*, float const*, int const*, int*)
Unexecuted instantiation: jxl::N_AVX3_SPR::QuantizeBlockAC(jxl::Quantizer const&, bool, unsigned long, float, jxl::AcStrategyType, unsigned long, unsigned long, float*, float const*, int const*, int*)
Unexecuted instantiation: jxl::N_SSE2::QuantizeBlockAC(jxl::Quantizer const&, bool, unsigned long, float, jxl::AcStrategyType, unsigned long, unsigned long, float*, float const*, int const*, int*)
103
104
void AdjustQuantBlockAC(const Quantizer& quantizer, size_t c,
105
                        float qm_multiplier, AcStrategyType quant_kind,
106
                        size_t xsize, size_t ysize, float* thresholds,
107
11.3M
                        const float* JXL_RESTRICT block_in, int32_t* quant) {
108
  // No quantization adjusting for these small blocks.
109
  // Quantization adjusting attempts to fix some known issues
110
  // with larger blocks and on the 8x8 dct's emerging 8x8 blockiness
111
  // when there are not many non-zeros.
112
11.3M
  constexpr size_t kPartialBlockKinds =
113
11.3M
      (1 << static_cast<size_t>(AcStrategyType::IDENTITY)) |
114
11.3M
      (1 << static_cast<size_t>(AcStrategyType::DCT2X2)) |
115
11.3M
      (1 << static_cast<size_t>(AcStrategyType::DCT4X4)) |
116
11.3M
      (1 << static_cast<size_t>(AcStrategyType::DCT4X8)) |
117
11.3M
      (1 << static_cast<size_t>(AcStrategyType::DCT8X4)) |
118
11.3M
      (1 << static_cast<size_t>(AcStrategyType::AFV0)) |
119
11.3M
      (1 << static_cast<size_t>(AcStrategyType::AFV1)) |
120
11.3M
      (1 << static_cast<size_t>(AcStrategyType::AFV2)) |
121
11.3M
      (1 << static_cast<size_t>(AcStrategyType::AFV3));
122
11.3M
  if ((1 << static_cast<size_t>(quant_kind)) & kPartialBlockKinds) {
123
5.66M
    return;
124
5.66M
  }
125
126
5.68M
  const float* JXL_RESTRICT qm = quantizer.InvDequantMatrix(quant_kind, c);
127
5.68M
  float qac = quantizer.Scale() * (*quant);
128
5.68M
  if (xsize > 1 || ysize > 1) {
129
8.32M
    for (int i = 0; i < 4; ++i) {
130
6.65M
      thresholds[i] -= Clamp1(0.003f * xsize * ysize, 0.f, 0.08f);
131
6.65M
      if (thresholds[i] < 0.54) {
132
410k
        thresholds[i] = 0.54;
133
410k
      }
134
6.65M
    }
135
1.66M
  }
136
5.68M
  float sum_of_highest_freq_row_and_column = 0;
137
5.68M
  float sum_of_error = 0;
138
5.68M
  float sum_of_vals = 0;
139
5.68M
  float hfNonZeros[4] = {};
140
5.68M
  float hfMaxError[4] = {};
141
142
66.8M
  for (size_t y = 0; y < ysize * kBlockDim; y++) {
143
1.27G
    for (size_t x = 0; x < xsize * kBlockDim; x++) {
144
1.21G
      const size_t pos = y * kBlockDim * xsize + x;
145
1.21G
      if (x < xsize && y < ysize) {
146
18.9M
        continue;
147
18.9M
      }
148
1.19G
      const size_t hfix = (static_cast<size_t>(y >= ysize * kBlockDim / 2) * 2 +
149
1.19G
                           static_cast<size_t>(x >= xsize * kBlockDim / 2));
150
1.19G
      const float val = block_in[pos] * (qm[pos] * qac * qm_multiplier);
151
1.19G
      const float v = (std::abs(val) < thresholds[hfix]) ? 0 : rintf(val);
152
1.19G
      const float error = std::abs(val - v);
153
1.19G
      sum_of_error += error;
154
1.19G
      sum_of_vals += std::abs(v);
155
1.19G
      if (c == 1 && v == 0) {
156
339M
        if (hfMaxError[hfix] < error) {
157
20.0M
          hfMaxError[hfix] = error;
158
20.0M
        }
159
339M
      }
160
1.19G
      if (v != 0.0f) {
161
87.5M
        hfNonZeros[hfix] += std::abs(v);
162
87.5M
        bool in_corner = y >= 7 * ysize && x >= 7 * xsize;
163
87.5M
        bool on_border =
164
87.5M
            y == ysize * kBlockDim - 1 || x == xsize * kBlockDim - 1;
165
87.5M
        bool in_larger_corner = x >= 4 * xsize && y >= 4 * ysize;
166
87.5M
        if (in_corner || (on_border && in_larger_corner)) {
167
2.35M
          sum_of_highest_freq_row_and_column += std::abs(val);
168
2.35M
        }
169
87.5M
      }
170
1.19G
    }
171
61.2M
  }
172
5.68M
  if (c == 1 && sum_of_vals * 8 < xsize * ysize) {
173
416k
    static const double kLimit[4] = {
174
416k
        0.46,
175
416k
        0.46,
176
416k
        0.46,
177
416k
        0.46,
178
416k
    };
179
416k
    static const double kMul[4] = {
180
416k
        0.9999,
181
416k
        0.9999,
182
416k
        0.9999,
183
416k
        0.9999,
184
416k
    };
185
416k
    const int32_t orig_quant = *quant;
186
416k
    int32_t new_quant = *quant;
187
1.65M
    for (int i = 1; i < 4; ++i) {
188
1.24M
      if (hfNonZeros[i] == 0.0 && hfMaxError[i] > kLimit[i]) {
189
4.26k
        new_quant = orig_quant + 1;
190
4.26k
        break;
191
4.26k
      }
192
1.24M
    }
193
416k
    *quant = new_quant;
194
416k
    if (hfNonZeros[3] == 0.0 && hfMaxError[3] > kLimit[3]) {
195
587
      thresholds[3] = kMul[3] * hfMaxError[3] * new_quant / orig_quant;
196
415k
    } else if ((hfNonZeros[1] == 0.0 && hfMaxError[1] > kLimit[1]) ||
197
413k
               (hfNonZeros[2] == 0.0 && hfMaxError[2] > kLimit[2])) {
198
3.67k
      thresholds[1] = kMul[1] * std::max(hfMaxError[1], hfMaxError[2]) *
199
3.67k
                      new_quant / orig_quant;
200
3.67k
      thresholds[2] = thresholds[1];
201
412k
    } else if (hfNonZeros[0] == 0.0 && hfMaxError[0] > kLimit[0]) {
202
15.8k
      thresholds[0] = kMul[0] * hfMaxError[0] * new_quant / orig_quant;
203
15.8k
    }
204
416k
  }
205
  // Heuristic for improving accuracy of high-frequency patterns
206
  // occurring in an environment with no medium-frequency masking
207
  // patterns.
208
5.68M
  {
209
5.68M
    float all =
210
5.68M
        hfNonZeros[0] + hfNonZeros[1] + hfNonZeros[2] + hfNonZeros[3] + 1;
211
5.68M
    float mul[3] = {70, 30, 60};
212
5.68M
    if (mul[c] * sum_of_highest_freq_row_and_column >= all) {
213
555k
      *quant += mul[c] * sum_of_highest_freq_row_and_column / all;
214
555k
      if (*quant >= Quantizer::kQuantMax) {
215
0
        *quant = Quantizer::kQuantMax - 1;
216
0
      }
217
555k
    }
218
5.68M
  }
219
5.68M
  if (quant_kind == AcStrategyType::DCT) {
220
    // If this 8x8 block is too flat, increase the adaptive quantization level
221
    // a bit to reduce visible block boundaries and requantize the block.
222
4.01M
    if (hfNonZeros[0] + hfNonZeros[1] + hfNonZeros[2] + hfNonZeros[3] < 11) {
223
1.75M
      *quant += 1;
224
1.75M
      if (*quant >= Quantizer::kQuantMax) {
225
0
        *quant = Quantizer::kQuantMax - 1;
226
0
      }
227
1.75M
    }
228
4.01M
  }
229
5.68M
  {
230
5.68M
    static const double kMul1[4][3] = {
231
5.68M
        {
232
5.68M
            0.22080615753848404,
233
5.68M
            0.45797479824262011,
234
5.68M
            0.29859235095977965,
235
5.68M
        },
236
5.68M
        {
237
5.68M
            0.70109486510286834,
238
5.68M
            0.16185281305512639,
239
5.68M
            0.14387691730035473,
240
5.68M
        },
241
5.68M
        {
242
5.68M
            0.114985964456218638,
243
5.68M
            0.44656840441027695,
244
5.68M
            0.10587658215149048,
245
5.68M
        },
246
5.68M
        {
247
5.68M
            0.46849665264409396,
248
5.68M
            0.41239077937781954,
249
5.68M
            0.088667407767185444,
250
5.68M
        },
251
5.68M
    };
252
5.68M
    static const double kMul2[4][3] = {
253
5.68M
        {
254
5.68M
            0.27450281941822197,
255
5.68M
            1.1255766549984996,
256
5.68M
            0.98950459134128388,
257
5.68M
        },
258
5.68M
        {
259
5.68M
            0.4652168675598285,
260
5.68M
            0.40945807983455818,
261
5.68M
            0.36581899811751367,
262
5.68M
        },
263
5.68M
        {
264
5.68M
            0.28034972424715715,
265
5.68M
            0.9182653201929738,
266
5.68M
            1.5581531543057416,
267
5.68M
        },
268
5.68M
        {
269
5.68M
            0.26873118114033728,
270
5.68M
            0.68863712390392484,
271
5.68M
            1.2082185408666786,
272
5.68M
        },
273
5.68M
    };
274
5.68M
    static const double kQuantNormalizer = 2.2942708343284721;
275
5.68M
    sum_of_error *= kQuantNormalizer;
276
5.68M
    sum_of_vals *= kQuantNormalizer;
277
5.68M
    if (quant_kind >= AcStrategyType::DCT16X16) {
278
1.66M
      int ix = 3;
279
1.66M
      if (quant_kind == AcStrategyType::DCT32X16 ||
280
1.57M
          quant_kind == AcStrategyType::DCT16X32) {
281
241k
        ix = 1;
282
1.42M
      } else if (quant_kind == AcStrategyType::DCT16X16) {
283
187k
        ix = 0;
284
1.23M
      } else if (quant_kind == AcStrategyType::DCT32X32) {
285
312k
        ix = 2;
286
312k
      }
287
1.66M
      int step =
288
1.66M
          sum_of_error / (kMul1[ix][c] * xsize * ysize * kBlockDim * kBlockDim +
289
1.66M
                          kMul2[ix][c] * sum_of_vals);
290
1.66M
      if (step >= 2) {
291
6.06k
        step = 2;
292
6.06k
      }
293
1.66M
      if (step < 0) {
294
0
        step = 0;
295
0
      }
296
1.66M
      if (sum_of_error > kMul1[ix][c] * xsize * ysize * kBlockDim * kBlockDim +
297
1.66M
                             kMul2[ix][c] * sum_of_vals) {
298
66.7k
        *quant += step;
299
66.7k
        if (*quant >= Quantizer::kQuantMax) {
300
0
          *quant = Quantizer::kQuantMax - 1;
301
0
        }
302
66.7k
      }
303
1.66M
    }
304
5.68M
  }
305
5.68M
  {
306
    // Reduce quant in highly active areas.
307
5.68M
    int32_t div = (xsize * ysize);
308
5.68M
    float min_hf_non_zeros =
309
5.68M
        std::min({hfNonZeros[0], hfNonZeros[1], hfNonZeros[2], hfNonZeros[3]});
310
5.68M
    int32_t activity = 15;
311
5.68M
    if (min_hf_non_zeros < 15.0f * div) {
312
5.53M
      activity = (static_cast<int32_t>(min_hf_non_zeros) + div / 2) / div;
313
5.53M
    }
314
5.68M
    int32_t qp = *quant - activity;
315
5.68M
    if (c == 1) {
316
7.57M
      for (int i = 1; i < 4; ++i) {
317
5.68M
        thresholds[i] += 0.01 * activity;
318
5.68M
      }
319
1.89M
    }
320
5.68M
    int32_t orig_qp_limit = std::max(4, *quant / 2);
321
5.68M
    if (qp < orig_qp_limit) {
322
1.33M
      qp = orig_qp_limit;
323
1.33M
    }
324
5.68M
    *quant = qp;
325
5.68M
  }
326
5.68M
}
Unexecuted instantiation: jxl::N_SSE4::AdjustQuantBlockAC(jxl::Quantizer const&, unsigned long, float, jxl::AcStrategyType, unsigned long, unsigned long, float*, float const*, int*)
jxl::N_AVX2::AdjustQuantBlockAC(jxl::Quantizer const&, unsigned long, float, jxl::AcStrategyType, unsigned long, unsigned long, float*, float const*, int*)
Line
Count
Source
107
11.3M
                        const float* JXL_RESTRICT block_in, int32_t* quant) {
108
  // No quantization adjusting for these small blocks.
109
  // Quantization adjusting attempts to fix some known issues
110
  // with larger blocks and on the 8x8 dct's emerging 8x8 blockiness
111
  // when there are not many non-zeros.
112
11.3M
  constexpr size_t kPartialBlockKinds =
113
11.3M
      (1 << static_cast<size_t>(AcStrategyType::IDENTITY)) |
114
11.3M
      (1 << static_cast<size_t>(AcStrategyType::DCT2X2)) |
115
11.3M
      (1 << static_cast<size_t>(AcStrategyType::DCT4X4)) |
116
11.3M
      (1 << static_cast<size_t>(AcStrategyType::DCT4X8)) |
117
11.3M
      (1 << static_cast<size_t>(AcStrategyType::DCT8X4)) |
118
11.3M
      (1 << static_cast<size_t>(AcStrategyType::AFV0)) |
119
11.3M
      (1 << static_cast<size_t>(AcStrategyType::AFV1)) |
120
11.3M
      (1 << static_cast<size_t>(AcStrategyType::AFV2)) |
121
11.3M
      (1 << static_cast<size_t>(AcStrategyType::AFV3));
122
11.3M
  if ((1 << static_cast<size_t>(quant_kind)) & kPartialBlockKinds) {
123
5.66M
    return;
124
5.66M
  }
125
126
5.68M
  const float* JXL_RESTRICT qm = quantizer.InvDequantMatrix(quant_kind, c);
127
5.68M
  float qac = quantizer.Scale() * (*quant);
128
5.68M
  if (xsize > 1 || ysize > 1) {
129
8.32M
    for (int i = 0; i < 4; ++i) {
130
6.65M
      thresholds[i] -= Clamp1(0.003f * xsize * ysize, 0.f, 0.08f);
131
6.65M
      if (thresholds[i] < 0.54) {
132
410k
        thresholds[i] = 0.54;
133
410k
      }
134
6.65M
    }
135
1.66M
  }
136
5.68M
  float sum_of_highest_freq_row_and_column = 0;
137
5.68M
  float sum_of_error = 0;
138
5.68M
  float sum_of_vals = 0;
139
5.68M
  float hfNonZeros[4] = {};
140
5.68M
  float hfMaxError[4] = {};
141
142
66.8M
  for (size_t y = 0; y < ysize * kBlockDim; y++) {
143
1.27G
    for (size_t x = 0; x < xsize * kBlockDim; x++) {
144
1.21G
      const size_t pos = y * kBlockDim * xsize + x;
145
1.21G
      if (x < xsize && y < ysize) {
146
18.9M
        continue;
147
18.9M
      }
148
1.19G
      const size_t hfix = (static_cast<size_t>(y >= ysize * kBlockDim / 2) * 2 +
149
1.19G
                           static_cast<size_t>(x >= xsize * kBlockDim / 2));
150
1.19G
      const float val = block_in[pos] * (qm[pos] * qac * qm_multiplier);
151
1.19G
      const float v = (std::abs(val) < thresholds[hfix]) ? 0 : rintf(val);
152
1.19G
      const float error = std::abs(val - v);
153
1.19G
      sum_of_error += error;
154
1.19G
      sum_of_vals += std::abs(v);
155
1.19G
      if (c == 1 && v == 0) {
156
339M
        if (hfMaxError[hfix] < error) {
157
20.0M
          hfMaxError[hfix] = error;
158
20.0M
        }
159
339M
      }
160
1.19G
      if (v != 0.0f) {
161
87.5M
        hfNonZeros[hfix] += std::abs(v);
162
87.5M
        bool in_corner = y >= 7 * ysize && x >= 7 * xsize;
163
87.5M
        bool on_border =
164
87.5M
            y == ysize * kBlockDim - 1 || x == xsize * kBlockDim - 1;
165
87.5M
        bool in_larger_corner = x >= 4 * xsize && y >= 4 * ysize;
166
87.5M
        if (in_corner || (on_border && in_larger_corner)) {
167
2.35M
          sum_of_highest_freq_row_and_column += std::abs(val);
168
2.35M
        }
169
87.5M
      }
170
1.19G
    }
171
61.2M
  }
172
5.68M
  if (c == 1 && sum_of_vals * 8 < xsize * ysize) {
173
416k
    static const double kLimit[4] = {
174
416k
        0.46,
175
416k
        0.46,
176
416k
        0.46,
177
416k
        0.46,
178
416k
    };
179
416k
    static const double kMul[4] = {
180
416k
        0.9999,
181
416k
        0.9999,
182
416k
        0.9999,
183
416k
        0.9999,
184
416k
    };
185
416k
    const int32_t orig_quant = *quant;
186
416k
    int32_t new_quant = *quant;
187
1.65M
    for (int i = 1; i < 4; ++i) {
188
1.24M
      if (hfNonZeros[i] == 0.0 && hfMaxError[i] > kLimit[i]) {
189
4.26k
        new_quant = orig_quant + 1;
190
4.26k
        break;
191
4.26k
      }
192
1.24M
    }
193
416k
    *quant = new_quant;
194
416k
    if (hfNonZeros[3] == 0.0 && hfMaxError[3] > kLimit[3]) {
195
587
      thresholds[3] = kMul[3] * hfMaxError[3] * new_quant / orig_quant;
196
415k
    } else if ((hfNonZeros[1] == 0.0 && hfMaxError[1] > kLimit[1]) ||
197
413k
               (hfNonZeros[2] == 0.0 && hfMaxError[2] > kLimit[2])) {
198
3.67k
      thresholds[1] = kMul[1] * std::max(hfMaxError[1], hfMaxError[2]) *
199
3.67k
                      new_quant / orig_quant;
200
3.67k
      thresholds[2] = thresholds[1];
201
412k
    } else if (hfNonZeros[0] == 0.0 && hfMaxError[0] > kLimit[0]) {
202
15.8k
      thresholds[0] = kMul[0] * hfMaxError[0] * new_quant / orig_quant;
203
15.8k
    }
204
416k
  }
205
  // Heuristic for improving accuracy of high-frequency patterns
206
  // occurring in an environment with no medium-frequency masking
207
  // patterns.
208
5.68M
  {
209
5.68M
    float all =
210
5.68M
        hfNonZeros[0] + hfNonZeros[1] + hfNonZeros[2] + hfNonZeros[3] + 1;
211
5.68M
    float mul[3] = {70, 30, 60};
212
5.68M
    if (mul[c] * sum_of_highest_freq_row_and_column >= all) {
213
555k
      *quant += mul[c] * sum_of_highest_freq_row_and_column / all;
214
555k
      if (*quant >= Quantizer::kQuantMax) {
215
0
        *quant = Quantizer::kQuantMax - 1;
216
0
      }
217
555k
    }
218
5.68M
  }
219
5.68M
  if (quant_kind == AcStrategyType::DCT) {
220
    // If this 8x8 block is too flat, increase the adaptive quantization level
221
    // a bit to reduce visible block boundaries and requantize the block.
222
4.01M
    if (hfNonZeros[0] + hfNonZeros[1] + hfNonZeros[2] + hfNonZeros[3] < 11) {
223
1.75M
      *quant += 1;
224
1.75M
      if (*quant >= Quantizer::kQuantMax) {
225
0
        *quant = Quantizer::kQuantMax - 1;
226
0
      }
227
1.75M
    }
228
4.01M
  }
229
5.68M
  {
230
5.68M
    static const double kMul1[4][3] = {
231
5.68M
        {
232
5.68M
            0.22080615753848404,
233
5.68M
            0.45797479824262011,
234
5.68M
            0.29859235095977965,
235
5.68M
        },
236
5.68M
        {
237
5.68M
            0.70109486510286834,
238
5.68M
            0.16185281305512639,
239
5.68M
            0.14387691730035473,
240
5.68M
        },
241
5.68M
        {
242
5.68M
            0.114985964456218638,
243
5.68M
            0.44656840441027695,
244
5.68M
            0.10587658215149048,
245
5.68M
        },
246
5.68M
        {
247
5.68M
            0.46849665264409396,
248
5.68M
            0.41239077937781954,
249
5.68M
            0.088667407767185444,
250
5.68M
        },
251
5.68M
    };
252
5.68M
    static const double kMul2[4][3] = {
253
5.68M
        {
254
5.68M
            0.27450281941822197,
255
5.68M
            1.1255766549984996,
256
5.68M
            0.98950459134128388,
257
5.68M
        },
258
5.68M
        {
259
5.68M
            0.4652168675598285,
260
5.68M
            0.40945807983455818,
261
5.68M
            0.36581899811751367,
262
5.68M
        },
263
5.68M
        {
264
5.68M
            0.28034972424715715,
265
5.68M
            0.9182653201929738,
266
5.68M
            1.5581531543057416,
267
5.68M
        },
268
5.68M
        {
269
5.68M
            0.26873118114033728,
270
5.68M
            0.68863712390392484,
271
5.68M
            1.2082185408666786,
272
5.68M
        },
273
5.68M
    };
274
5.68M
    static const double kQuantNormalizer = 2.2942708343284721;
275
5.68M
    sum_of_error *= kQuantNormalizer;
276
5.68M
    sum_of_vals *= kQuantNormalizer;
277
5.68M
    if (quant_kind >= AcStrategyType::DCT16X16) {
278
1.66M
      int ix = 3;
279
1.66M
      if (quant_kind == AcStrategyType::DCT32X16 ||
280
1.57M
          quant_kind == AcStrategyType::DCT16X32) {
281
241k
        ix = 1;
282
1.42M
      } else if (quant_kind == AcStrategyType::DCT16X16) {
283
187k
        ix = 0;
284
1.23M
      } else if (quant_kind == AcStrategyType::DCT32X32) {
285
312k
        ix = 2;
286
312k
      }
287
1.66M
      int step =
288
1.66M
          sum_of_error / (kMul1[ix][c] * xsize * ysize * kBlockDim * kBlockDim +
289
1.66M
                          kMul2[ix][c] * sum_of_vals);
290
1.66M
      if (step >= 2) {
291
6.06k
        step = 2;
292
6.06k
      }
293
1.66M
      if (step < 0) {
294
0
        step = 0;
295
0
      }
296
1.66M
      if (sum_of_error > kMul1[ix][c] * xsize * ysize * kBlockDim * kBlockDim +
297
1.66M
                             kMul2[ix][c] * sum_of_vals) {
298
66.7k
        *quant += step;
299
66.7k
        if (*quant >= Quantizer::kQuantMax) {
300
0
          *quant = Quantizer::kQuantMax - 1;
301
0
        }
302
66.7k
      }
303
1.66M
    }
304
5.68M
  }
305
5.68M
  {
306
    // Reduce quant in highly active areas.
307
5.68M
    int32_t div = (xsize * ysize);
308
5.68M
    float min_hf_non_zeros =
309
5.68M
        std::min({hfNonZeros[0], hfNonZeros[1], hfNonZeros[2], hfNonZeros[3]});
310
5.68M
    int32_t activity = 15;
311
5.68M
    if (min_hf_non_zeros < 15.0f * div) {
312
5.53M
      activity = (static_cast<int32_t>(min_hf_non_zeros) + div / 2) / div;
313
5.53M
    }
314
5.68M
    int32_t qp = *quant - activity;
315
5.68M
    if (c == 1) {
316
7.57M
      for (int i = 1; i < 4; ++i) {
317
5.68M
        thresholds[i] += 0.01 * activity;
318
5.68M
      }
319
1.89M
    }
320
5.68M
    int32_t orig_qp_limit = std::max(4, *quant / 2);
321
5.68M
    if (qp < orig_qp_limit) {
322
1.33M
      qp = orig_qp_limit;
323
1.33M
    }
324
5.68M
    *quant = qp;
325
5.68M
  }
326
5.68M
}
Unexecuted instantiation: jxl::N_AVX3::AdjustQuantBlockAC(jxl::Quantizer const&, unsigned long, float, jxl::AcStrategyType, unsigned long, unsigned long, float*, float const*, int*)
Unexecuted instantiation: jxl::N_AVX3_ZEN4::AdjustQuantBlockAC(jxl::Quantizer const&, unsigned long, float, jxl::AcStrategyType, unsigned long, unsigned long, float*, float const*, int*)
Unexecuted instantiation: jxl::N_AVX3_SPR::AdjustQuantBlockAC(jxl::Quantizer const&, unsigned long, float, jxl::AcStrategyType, unsigned long, unsigned long, float*, float const*, int*)
Unexecuted instantiation: jxl::N_SSE2::AdjustQuantBlockAC(jxl::Quantizer const&, unsigned long, float, jxl::AcStrategyType, unsigned long, unsigned long, float*, float const*, int*)
327
328
// NOTE: caller takes care of extracting quant from rect of RawQuantField.
329
void QuantizeRoundtripYBlockAC(PassesEncoderState* enc_state, const size_t size,
330
                               const Quantizer& quantizer,
331
                               const bool error_diffusion,
332
                               AcStrategyType quant_kind, size_t xsize,
333
                               size_t ysize, const float* JXL_RESTRICT biases,
334
                               int32_t* quant, float* JXL_RESTRICT inout,
335
3.78M
                               int32_t* JXL_RESTRICT quantized) {
336
3.78M
  float thres_y[4] = {0.58f, 0.64f, 0.64f, 0.64f};
337
3.78M
  if (enc_state->cparams.speed_tier <= SpeedTier::kHare) {
338
3.78M
    int32_t max_quant = 0;
339
3.78M
    int quant_orig = *quant;
340
3.78M
    float val[3] = {enc_state->x_qm_multiplier, 1.0f,
341
3.78M
                    enc_state->b_qm_multiplier};
342
11.3M
    for (int c : {1, 0, 2}) {
343
11.3M
      float thres[4] = {0.58f, 0.64f, 0.64f, 0.64f};
344
11.3M
      *quant = quant_orig;
345
11.3M
      AdjustQuantBlockAC(quantizer, c, val[c], quant_kind, xsize, ysize,
346
11.3M
                         &thres[0], inout + c * size, quant);
347
      // Dead zone adjustment
348
11.3M
      if (c == 1) {
349
18.9M
        for (int k = 0; k < 4; ++k) {
350
15.1M
          thres_y[k] = thres[k];
351
15.1M
        }
352
3.78M
      }
353
11.3M
      max_quant = std::max(*quant, max_quant);
354
11.3M
    }
355
3.78M
    *quant = max_quant;
356
3.78M
  } else {
357
0
    thres_y[0] = 0.56;
358
0
    thres_y[1] = 0.62;
359
0
    thres_y[2] = 0.62;
360
0
    thres_y[3] = 0.62;
361
0
  }
362
363
3.78M
  QuantizeBlockAC(quantizer, error_diffusion, 1, 1.0f, quant_kind, xsize, ysize,
364
3.78M
                  &thres_y[0], inout + size, quant, quantized + size);
365
366
3.78M
  const float* JXL_RESTRICT dequant_matrix =
367
3.78M
      quantizer.DequantMatrix(quant_kind, 1);
368
369
3.78M
  HWY_CAPPED(float, kDCTBlockSize) df;
370
3.78M
  HWY_CAPPED(int32_t, kDCTBlockSize) di;
371
3.78M
  const auto inv_qac = Set(df, quantizer.inv_quant_ac(*quant));
372
69.4M
  for (size_t k = 0; k < kDCTBlockSize * xsize * ysize; k += Lanes(df)) {
373
65.6M
    const auto oquant = Load(di, quantized + size + k);
374
65.6M
    const auto adj_quant = AdjustQuantBias(di, 1, oquant, biases);
375
65.6M
    const auto dequantm = Load(df, dequant_matrix + k);
376
65.6M
    Store(Mul(Mul(adj_quant, dequantm), inv_qac), df, inout + size + k);
377
65.6M
  }
378
3.78M
}
Unexecuted instantiation: jxl::N_SSE4::QuantizeRoundtripYBlockAC(jxl::PassesEncoderState*, unsigned long, jxl::Quantizer const&, bool, jxl::AcStrategyType, unsigned long, unsigned long, float const*, int*, float*, int*)
jxl::N_AVX2::QuantizeRoundtripYBlockAC(jxl::PassesEncoderState*, unsigned long, jxl::Quantizer const&, bool, jxl::AcStrategyType, unsigned long, unsigned long, float const*, int*, float*, int*)
Line
Count
Source
335
3.78M
                               int32_t* JXL_RESTRICT quantized) {
336
3.78M
  float thres_y[4] = {0.58f, 0.64f, 0.64f, 0.64f};
337
3.78M
  if (enc_state->cparams.speed_tier <= SpeedTier::kHare) {
338
3.78M
    int32_t max_quant = 0;
339
3.78M
    int quant_orig = *quant;
340
3.78M
    float val[3] = {enc_state->x_qm_multiplier, 1.0f,
341
3.78M
                    enc_state->b_qm_multiplier};
342
11.3M
    for (int c : {1, 0, 2}) {
343
11.3M
      float thres[4] = {0.58f, 0.64f, 0.64f, 0.64f};
344
11.3M
      *quant = quant_orig;
345
11.3M
      AdjustQuantBlockAC(quantizer, c, val[c], quant_kind, xsize, ysize,
346
11.3M
                         &thres[0], inout + c * size, quant);
347
      // Dead zone adjustment
348
11.3M
      if (c == 1) {
349
18.9M
        for (int k = 0; k < 4; ++k) {
350
15.1M
          thres_y[k] = thres[k];
351
15.1M
        }
352
3.78M
      }
353
11.3M
      max_quant = std::max(*quant, max_quant);
354
11.3M
    }
355
3.78M
    *quant = max_quant;
356
3.78M
  } else {
357
0
    thres_y[0] = 0.56;
358
0
    thres_y[1] = 0.62;
359
0
    thres_y[2] = 0.62;
360
0
    thres_y[3] = 0.62;
361
0
  }
362
363
3.78M
  QuantizeBlockAC(quantizer, error_diffusion, 1, 1.0f, quant_kind, xsize, ysize,
364
3.78M
                  &thres_y[0], inout + size, quant, quantized + size);
365
366
3.78M
  const float* JXL_RESTRICT dequant_matrix =
367
3.78M
      quantizer.DequantMatrix(quant_kind, 1);
368
369
3.78M
  HWY_CAPPED(float, kDCTBlockSize) df;
370
3.78M
  HWY_CAPPED(int32_t, kDCTBlockSize) di;
371
3.78M
  const auto inv_qac = Set(df, quantizer.inv_quant_ac(*quant));
372
69.4M
  for (size_t k = 0; k < kDCTBlockSize * xsize * ysize; k += Lanes(df)) {
373
65.6M
    const auto oquant = Load(di, quantized + size + k);
374
65.6M
    const auto adj_quant = AdjustQuantBias(di, 1, oquant, biases);
375
65.6M
    const auto dequantm = Load(df, dequant_matrix + k);
376
65.6M
    Store(Mul(Mul(adj_quant, dequantm), inv_qac), df, inout + size + k);
377
65.6M
  }
378
3.78M
}
Unexecuted instantiation: jxl::N_AVX3::QuantizeRoundtripYBlockAC(jxl::PassesEncoderState*, unsigned long, jxl::Quantizer const&, bool, jxl::AcStrategyType, unsigned long, unsigned long, float const*, int*, float*, int*)
Unexecuted instantiation: jxl::N_AVX3_ZEN4::QuantizeRoundtripYBlockAC(jxl::PassesEncoderState*, unsigned long, jxl::Quantizer const&, bool, jxl::AcStrategyType, unsigned long, unsigned long, float const*, int*, float*, int*)
Unexecuted instantiation: jxl::N_AVX3_SPR::QuantizeRoundtripYBlockAC(jxl::PassesEncoderState*, unsigned long, jxl::Quantizer const&, bool, jxl::AcStrategyType, unsigned long, unsigned long, float const*, int*, float*, int*)
Unexecuted instantiation: jxl::N_SSE2::QuantizeRoundtripYBlockAC(jxl::PassesEncoderState*, unsigned long, jxl::Quantizer const&, bool, jxl::AcStrategyType, unsigned long, unsigned long, float const*, int*, float*, int*)
379
380
Status ComputeCoefficients(size_t group_idx, PassesEncoderState* enc_state,
381
                           const Image3F& opsin, const Rect& rect,
382
13.0k
                           Image3F* dc) {
383
13.0k
  JxlMemoryManager* memory_manager = opsin.memory_manager();
384
13.0k
  const Rect block_group_rect =
385
13.0k
      enc_state->shared.frame_dim.BlockGroupRect(group_idx);
386
13.0k
  const Rect cmap_rect(
387
13.0k
      block_group_rect.x0() / kColorTileDimInBlocks,
388
13.0k
      block_group_rect.y0() / kColorTileDimInBlocks,
389
13.0k
      DivCeil(block_group_rect.xsize(), kColorTileDimInBlocks),
390
13.0k
      DivCeil(block_group_rect.ysize(), kColorTileDimInBlocks));
391
13.0k
  const Rect group_rect =
392
13.0k
      enc_state->shared.frame_dim.GroupRect(group_idx).Translate(rect.x0(),
393
13.0k
                                                                 rect.y0());
394
395
13.0k
  const size_t xsize_blocks = block_group_rect.xsize();
396
13.0k
  const size_t ysize_blocks = block_group_rect.ysize();
397
398
13.0k
  const size_t dc_stride = static_cast<size_t>(dc->PixelsPerRow());
399
13.0k
  const size_t opsin_stride = static_cast<size_t>(opsin.PixelsPerRow());
400
401
13.0k
  ImageI& full_quant_field = enc_state->shared.raw_quant_field;
402
13.0k
  const CompressParams& cparams = enc_state->cparams;
403
404
13.0k
  const size_t dct_scratch_size =
405
13.0k
      3 * (MaxVectorSize() / sizeof(float)) * AcStrategy::kMaxBlockDim;
406
407
  // TODO(veluca): consider strategies to reduce this memory.
408
13.0k
  size_t mem_bytes = 3 * AcStrategy::kMaxCoeffArea * sizeof(int32_t);
409
13.0k
  JXL_ASSIGN_OR_RETURN(auto mem,
410
13.0k
                       AlignedMemory::Create(memory_manager, mem_bytes));
411
13.0k
  size_t fmem_bytes =
412
13.0k
      (5 * AcStrategy::kMaxCoeffArea + dct_scratch_size) * sizeof(float);
413
13.0k
  JXL_ASSIGN_OR_RETURN(auto fmem,
414
13.0k
                       AlignedMemory::Create(memory_manager, fmem_bytes));
415
13.0k
  float* JXL_RESTRICT scratch_space =
416
13.0k
      fmem.address<float>() + 3 * AcStrategy::kMaxCoeffArea;
417
13.0k
  {
418
    // Only use error diffusion in Squirrel mode or slower.
419
13.0k
    const bool error_diffusion = cparams.speed_tier <= SpeedTier::kSquirrel;
420
13.0k
    constexpr HWY_CAPPED(float, kDCTBlockSize) d;
421
422
13.0k
    int32_t* JXL_RESTRICT coeffs[3][kMaxNumPasses] = {};
423
13.0k
    size_t num_passes = enc_state->progressive_splitter.GetNumPasses();
424
13.0k
    JXL_ENSURE(num_passes > 0);
425
26.1k
    for (size_t i = 0; i < num_passes; i++) {
426
      // TODO(veluca): 16-bit quantized coeffs are not implemented yet.
427
13.0k
      JXL_ENSURE(enc_state->coeffs[i]->Type() == ACType::k32);
428
52.3k
      for (size_t c = 0; c < 3; c++) {
429
39.2k
        coeffs[c][i] = enc_state->coeffs[i]->PlaneRow(c, group_idx, 0).ptr32;
430
39.2k
      }
431
13.0k
    }
432
433
13.0k
    HWY_ALIGN float* coeffs_in = fmem.address<float>();
434
13.0k
    HWY_ALIGN int32_t* quantized = mem.address<int32_t>();
435
436
347k
    for (size_t by = 0; by < ysize_blocks; ++by) {
437
334k
      int32_t* JXL_RESTRICT row_quant_ac =
438
334k
          block_group_rect.Row(&full_quant_field, by);
439
334k
      size_t ty = by / kColorTileDimInBlocks;
440
334k
      const int8_t* JXL_RESTRICT row_cmap[3] = {
441
334k
          cmap_rect.ConstRow(enc_state->shared.cmap.ytox_map, ty),
442
334k
          nullptr,
443
334k
          cmap_rect.ConstRow(enc_state->shared.cmap.ytob_map, ty),
444
334k
      };
445
334k
      const float* JXL_RESTRICT opsin_rows[3] = {
446
334k
          group_rect.ConstPlaneRow(opsin, 0, by * kBlockDim),
447
334k
          group_rect.ConstPlaneRow(opsin, 1, by * kBlockDim),
448
334k
          group_rect.ConstPlaneRow(opsin, 2, by * kBlockDim),
449
334k
      };
450
334k
      float* JXL_RESTRICT dc_rows[3] = {
451
334k
          block_group_rect.PlaneRow(dc, 0, by),
452
334k
          block_group_rect.PlaneRow(dc, 1, by),
453
334k
          block_group_rect.PlaneRow(dc, 2, by),
454
334k
      };
455
334k
      AcStrategyRow ac_strategy_row =
456
334k
          enc_state->shared.ac_strategy.ConstRow(block_group_rect, by);
457
1.44M
      for (size_t tx = 0; tx < DivCeil(xsize_blocks, kColorTileDimInBlocks);
458
1.11M
           tx++) {
459
1.11M
        const auto x_factor =
460
1.11M
            Set(d, enc_state->shared.cmap.base().YtoXRatio(row_cmap[0][tx]));
461
1.11M
        const auto b_factor =
462
1.11M
            Set(d, enc_state->shared.cmap.base().YtoBRatio(row_cmap[2][tx]));
463
1.11M
        for (size_t bx = tx * kColorTileDimInBlocks;
464
9.31M
             bx < xsize_blocks && bx < (tx + 1) * kColorTileDimInBlocks; ++bx) {
465
8.20M
          const AcStrategy acs = ac_strategy_row[bx];
466
8.20M
          if (!acs.IsFirstBlock()) continue;
467
468
3.78M
          size_t xblocks = acs.covered_blocks_x();
469
3.78M
          size_t yblocks = acs.covered_blocks_y();
470
471
3.78M
          CoefficientLayout(&yblocks, &xblocks);
472
473
3.78M
          size_t size = kDCTBlockSize * xblocks * yblocks;
474
475
          // DCT Y channel, roundtrip-quantize it and set DC.
476
3.78M
          int32_t quant_ac = row_quant_ac[bx];
477
11.3M
          for (size_t c : {0, 1, 2}) {
478
11.3M
            TransformFromPixels(acs.Strategy(), opsin_rows[c] + bx * kBlockDim,
479
11.3M
                                opsin_stride, coeffs_in + c * size,
480
11.3M
                                scratch_space);
481
11.3M
          }
482
3.78M
          DCFromLowestFrequencies(acs.Strategy(), coeffs_in + size,
483
3.78M
                                  dc_rows[1] + bx, dc_stride, scratch_space);
484
485
3.78M
          QuantizeRoundtripYBlockAC(
486
3.78M
              enc_state, size, enc_state->shared.quantizer, error_diffusion,
487
3.78M
              acs.Strategy(), xblocks, yblocks, kDefaultQuantBias, &quant_ac,
488
3.78M
              coeffs_in, quantized);
489
490
          // Unapply color correlation
491
69.4M
          for (size_t k = 0; k < size; k += Lanes(d)) {
492
65.6M
            const auto in_x = Load(d, coeffs_in + k);
493
65.6M
            const auto in_y = Load(d, coeffs_in + size + k);
494
65.6M
            const auto in_b = Load(d, coeffs_in + 2 * size + k);
495
65.6M
            const auto out_x = NegMulAdd(x_factor, in_y, in_x);
496
65.6M
            const auto out_b = NegMulAdd(b_factor, in_y, in_b);
497
65.6M
            Store(out_x, d, coeffs_in + k);
498
65.6M
            Store(out_b, d, coeffs_in + 2 * size + k);
499
65.6M
          }
500
501
          // Quantize X and B channels and set DC.
502
7.56M
          for (size_t c : {0, 2}) {
503
7.56M
            float thres[4] = {0.58f, 0.62f, 0.62f, 0.62f};
504
7.56M
            QuantizeBlockAC(enc_state->shared.quantizer, error_diffusion, c,
505
7.56M
                            c == 0 ? enc_state->x_qm_multiplier
506
7.56M
                                   : enc_state->b_qm_multiplier,
507
7.56M
                            acs.Strategy(), xblocks, yblocks, &thres[0],
508
7.56M
                            coeffs_in + c * size, &quant_ac,
509
7.56M
                            quantized + c * size);
510
7.56M
            DCFromLowestFrequencies(acs.Strategy(), coeffs_in + c * size,
511
7.56M
                                    dc_rows[c] + bx, dc_stride, scratch_space);
512
7.56M
          }
513
3.78M
          row_quant_ac[bx] = quant_ac;
514
15.1M
          for (size_t c = 0; c < 3; c++) {
515
11.3M
            enc_state->progressive_splitter.SplitACCoefficients(
516
11.3M
                quantized + c * size, acs, bx, by, coeffs[c]);
517
22.6M
            for (size_t p = 0; p < num_passes; p++) {
518
11.3M
              coeffs[c][p] += size;
519
11.3M
            }
520
11.3M
          }
521
3.78M
        }
522
1.11M
      }
523
334k
    }
524
13.0k
  }
525
0
  return true;
526
13.0k
}
Unexecuted instantiation: jxl::N_SSE4::ComputeCoefficients(unsigned long, jxl::PassesEncoderState*, jxl::Image3<float> const&, jxl::RectT<unsigned long> const&, jxl::Image3<float>*)
jxl::N_AVX2::ComputeCoefficients(unsigned long, jxl::PassesEncoderState*, jxl::Image3<float> const&, jxl::RectT<unsigned long> const&, jxl::Image3<float>*)
Line
Count
Source
382
13.0k
                           Image3F* dc) {
383
13.0k
  JxlMemoryManager* memory_manager = opsin.memory_manager();
384
13.0k
  const Rect block_group_rect =
385
13.0k
      enc_state->shared.frame_dim.BlockGroupRect(group_idx);
386
13.0k
  const Rect cmap_rect(
387
13.0k
      block_group_rect.x0() / kColorTileDimInBlocks,
388
13.0k
      block_group_rect.y0() / kColorTileDimInBlocks,
389
13.0k
      DivCeil(block_group_rect.xsize(), kColorTileDimInBlocks),
390
13.0k
      DivCeil(block_group_rect.ysize(), kColorTileDimInBlocks));
391
13.0k
  const Rect group_rect =
392
13.0k
      enc_state->shared.frame_dim.GroupRect(group_idx).Translate(rect.x0(),
393
13.0k
                                                                 rect.y0());
394
395
13.0k
  const size_t xsize_blocks = block_group_rect.xsize();
396
13.0k
  const size_t ysize_blocks = block_group_rect.ysize();
397
398
13.0k
  const size_t dc_stride = static_cast<size_t>(dc->PixelsPerRow());
399
13.0k
  const size_t opsin_stride = static_cast<size_t>(opsin.PixelsPerRow());
400
401
13.0k
  ImageI& full_quant_field = enc_state->shared.raw_quant_field;
402
13.0k
  const CompressParams& cparams = enc_state->cparams;
403
404
13.0k
  const size_t dct_scratch_size =
405
13.0k
      3 * (MaxVectorSize() / sizeof(float)) * AcStrategy::kMaxBlockDim;
406
407
  // TODO(veluca): consider strategies to reduce this memory.
408
13.0k
  size_t mem_bytes = 3 * AcStrategy::kMaxCoeffArea * sizeof(int32_t);
409
13.0k
  JXL_ASSIGN_OR_RETURN(auto mem,
410
13.0k
                       AlignedMemory::Create(memory_manager, mem_bytes));
411
13.0k
  size_t fmem_bytes =
412
13.0k
      (5 * AcStrategy::kMaxCoeffArea + dct_scratch_size) * sizeof(float);
413
13.0k
  JXL_ASSIGN_OR_RETURN(auto fmem,
414
13.0k
                       AlignedMemory::Create(memory_manager, fmem_bytes));
415
13.0k
  float* JXL_RESTRICT scratch_space =
416
13.0k
      fmem.address<float>() + 3 * AcStrategy::kMaxCoeffArea;
417
13.0k
  {
418
    // Only use error diffusion in Squirrel mode or slower.
419
13.0k
    const bool error_diffusion = cparams.speed_tier <= SpeedTier::kSquirrel;
420
13.0k
    constexpr HWY_CAPPED(float, kDCTBlockSize) d;
421
422
13.0k
    int32_t* JXL_RESTRICT coeffs[3][kMaxNumPasses] = {};
423
13.0k
    size_t num_passes = enc_state->progressive_splitter.GetNumPasses();
424
13.0k
    JXL_ENSURE(num_passes > 0);
425
26.1k
    for (size_t i = 0; i < num_passes; i++) {
426
      // TODO(veluca): 16-bit quantized coeffs are not implemented yet.
427
13.0k
      JXL_ENSURE(enc_state->coeffs[i]->Type() == ACType::k32);
428
52.3k
      for (size_t c = 0; c < 3; c++) {
429
39.2k
        coeffs[c][i] = enc_state->coeffs[i]->PlaneRow(c, group_idx, 0).ptr32;
430
39.2k
      }
431
13.0k
    }
432
433
13.0k
    HWY_ALIGN float* coeffs_in = fmem.address<float>();
434
13.0k
    HWY_ALIGN int32_t* quantized = mem.address<int32_t>();
435
436
347k
    for (size_t by = 0; by < ysize_blocks; ++by) {
437
334k
      int32_t* JXL_RESTRICT row_quant_ac =
438
334k
          block_group_rect.Row(&full_quant_field, by);
439
334k
      size_t ty = by / kColorTileDimInBlocks;
440
334k
      const int8_t* JXL_RESTRICT row_cmap[3] = {
441
334k
          cmap_rect.ConstRow(enc_state->shared.cmap.ytox_map, ty),
442
334k
          nullptr,
443
334k
          cmap_rect.ConstRow(enc_state->shared.cmap.ytob_map, ty),
444
334k
      };
445
334k
      const float* JXL_RESTRICT opsin_rows[3] = {
446
334k
          group_rect.ConstPlaneRow(opsin, 0, by * kBlockDim),
447
334k
          group_rect.ConstPlaneRow(opsin, 1, by * kBlockDim),
448
334k
          group_rect.ConstPlaneRow(opsin, 2, by * kBlockDim),
449
334k
      };
450
334k
      float* JXL_RESTRICT dc_rows[3] = {
451
334k
          block_group_rect.PlaneRow(dc, 0, by),
452
334k
          block_group_rect.PlaneRow(dc, 1, by),
453
334k
          block_group_rect.PlaneRow(dc, 2, by),
454
334k
      };
455
334k
      AcStrategyRow ac_strategy_row =
456
334k
          enc_state->shared.ac_strategy.ConstRow(block_group_rect, by);
457
1.44M
      for (size_t tx = 0; tx < DivCeil(xsize_blocks, kColorTileDimInBlocks);
458
1.11M
           tx++) {
459
1.11M
        const auto x_factor =
460
1.11M
            Set(d, enc_state->shared.cmap.base().YtoXRatio(row_cmap[0][tx]));
461
1.11M
        const auto b_factor =
462
1.11M
            Set(d, enc_state->shared.cmap.base().YtoBRatio(row_cmap[2][tx]));
463
1.11M
        for (size_t bx = tx * kColorTileDimInBlocks;
464
9.31M
             bx < xsize_blocks && bx < (tx + 1) * kColorTileDimInBlocks; ++bx) {
465
8.20M
          const AcStrategy acs = ac_strategy_row[bx];
466
8.20M
          if (!acs.IsFirstBlock()) continue;
467
468
3.78M
          size_t xblocks = acs.covered_blocks_x();
469
3.78M
          size_t yblocks = acs.covered_blocks_y();
470
471
3.78M
          CoefficientLayout(&yblocks, &xblocks);
472
473
3.78M
          size_t size = kDCTBlockSize * xblocks * yblocks;
474
475
          // DCT Y channel, roundtrip-quantize it and set DC.
476
3.78M
          int32_t quant_ac = row_quant_ac[bx];
477
11.3M
          for (size_t c : {0, 1, 2}) {
478
11.3M
            TransformFromPixels(acs.Strategy(), opsin_rows[c] + bx * kBlockDim,
479
11.3M
                                opsin_stride, coeffs_in + c * size,
480
11.3M
                                scratch_space);
481
11.3M
          }
482
3.78M
          DCFromLowestFrequencies(acs.Strategy(), coeffs_in + size,
483
3.78M
                                  dc_rows[1] + bx, dc_stride, scratch_space);
484
485
3.78M
          QuantizeRoundtripYBlockAC(
486
3.78M
              enc_state, size, enc_state->shared.quantizer, error_diffusion,
487
3.78M
              acs.Strategy(), xblocks, yblocks, kDefaultQuantBias, &quant_ac,
488
3.78M
              coeffs_in, quantized);
489
490
          // Unapply color correlation
491
69.4M
          for (size_t k = 0; k < size; k += Lanes(d)) {
492
65.6M
            const auto in_x = Load(d, coeffs_in + k);
493
65.6M
            const auto in_y = Load(d, coeffs_in + size + k);
494
65.6M
            const auto in_b = Load(d, coeffs_in + 2 * size + k);
495
65.6M
            const auto out_x = NegMulAdd(x_factor, in_y, in_x);
496
65.6M
            const auto out_b = NegMulAdd(b_factor, in_y, in_b);
497
65.6M
            Store(out_x, d, coeffs_in + k);
498
65.6M
            Store(out_b, d, coeffs_in + 2 * size + k);
499
65.6M
          }
500
501
          // Quantize X and B channels and set DC.
502
7.56M
          for (size_t c : {0, 2}) {
503
7.56M
            float thres[4] = {0.58f, 0.62f, 0.62f, 0.62f};
504
7.56M
            QuantizeBlockAC(enc_state->shared.quantizer, error_diffusion, c,
505
7.56M
                            c == 0 ? enc_state->x_qm_multiplier
506
7.56M
                                   : enc_state->b_qm_multiplier,
507
7.56M
                            acs.Strategy(), xblocks, yblocks, &thres[0],
508
7.56M
                            coeffs_in + c * size, &quant_ac,
509
7.56M
                            quantized + c * size);
510
7.56M
            DCFromLowestFrequencies(acs.Strategy(), coeffs_in + c * size,
511
7.56M
                                    dc_rows[c] + bx, dc_stride, scratch_space);
512
7.56M
          }
513
3.78M
          row_quant_ac[bx] = quant_ac;
514
15.1M
          for (size_t c = 0; c < 3; c++) {
515
11.3M
            enc_state->progressive_splitter.SplitACCoefficients(
516
11.3M
                quantized + c * size, acs, bx, by, coeffs[c]);
517
22.6M
            for (size_t p = 0; p < num_passes; p++) {
518
11.3M
              coeffs[c][p] += size;
519
11.3M
            }
520
11.3M
          }
521
3.78M
        }
522
1.11M
      }
523
334k
    }
524
13.0k
  }
525
0
  return true;
526
13.0k
}
Unexecuted instantiation: jxl::N_AVX3::ComputeCoefficients(unsigned long, jxl::PassesEncoderState*, jxl::Image3<float> const&, jxl::RectT<unsigned long> const&, jxl::Image3<float>*)
Unexecuted instantiation: jxl::N_AVX3_ZEN4::ComputeCoefficients(unsigned long, jxl::PassesEncoderState*, jxl::Image3<float> const&, jxl::RectT<unsigned long> const&, jxl::Image3<float>*)
Unexecuted instantiation: jxl::N_AVX3_SPR::ComputeCoefficients(unsigned long, jxl::PassesEncoderState*, jxl::Image3<float> const&, jxl::RectT<unsigned long> const&, jxl::Image3<float>*)
Unexecuted instantiation: jxl::N_SSE2::ComputeCoefficients(unsigned long, jxl::PassesEncoderState*, jxl::Image3<float> const&, jxl::RectT<unsigned long> const&, jxl::Image3<float>*)
527
528
// NOLINTNEXTLINE(google-readability-namespace-comments)
529
}  // namespace HWY_NAMESPACE
530
}  // namespace jxl
531
HWY_AFTER_NAMESPACE();
532
533
#if HWY_ONCE
534
namespace jxl {
535
HWY_EXPORT(ComputeCoefficients);
536
Status ComputeCoefficients(size_t group_idx, PassesEncoderState* enc_state,
537
                           const Image3F& opsin, const Rect& rect,
538
13.0k
                           Image3F* dc) {
539
13.0k
  return HWY_DYNAMIC_DISPATCH(ComputeCoefficients)(group_idx, enc_state, opsin,
540
13.0k
                                                   rect, dc);
541
13.0k
}
542
543
Status EncodeGroupTokenizedCoefficients(size_t group_idx, size_t pass_idx,
544
                                        size_t histogram_idx,
545
                                        const PassesEncoderState& enc_state,
546
13.0k
                                        BitWriter* writer, AuxOut* aux_out) {
547
  // Select which histogram to use among those of the current pass.
548
13.0k
  const size_t num_histograms = enc_state.shared.num_histograms;
549
  // num_histograms is 0 only for lossless.
550
13.0k
  JXL_ENSURE(num_histograms == 0 || histogram_idx < num_histograms);
551
13.0k
  size_t histo_selector_bits = CeilLog2Nonzero(num_histograms);
552
553
13.0k
  if (histo_selector_bits != 0) {
554
0
    JXL_RETURN_IF_ERROR(
555
0
        writer->WithMaxBits(histo_selector_bits, LayerType::Ac, aux_out, [&] {
556
0
          writer->Write(histo_selector_bits, histogram_idx);
557
0
          return true;
558
0
        }));
559
0
  }
560
13.0k
  size_t context_offset =
561
13.0k
      histogram_idx * enc_state.shared.block_ctx_map.NumACContexts();
562
13.0k
  JXL_RETURN_IF_ERROR(
563
13.0k
      WriteTokens(enc_state.passes[pass_idx].ac_tokens[group_idx],
564
13.0k
                  enc_state.passes[pass_idx].codes, context_offset, writer,
565
13.0k
                  LayerType::AcTokens, aux_out));
566
567
13.0k
  return true;
568
13.0k
}
569
570
}  // namespace jxl
571
#endif  // HWY_ONCE