Coverage Report

Created: 2025-11-16 07:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libjxl/lib/jxl/modular/encoding/context_predict.h
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
#ifndef LIB_JXL_MODULAR_ENCODING_CONTEXT_PREDICT_H_
7
#define LIB_JXL_MODULAR_ENCODING_CONTEXT_PREDICT_H_
8
9
#include <algorithm>
10
#include <array>
11
#include <cmath>
12
#include <cstddef>
13
#include <cstdint>
14
#include <vector>
15
16
#include "lib/jxl/base/bits.h"
17
#include "lib/jxl/base/compiler_specific.h"
18
#include "lib/jxl/base/status.h"
19
#include "lib/jxl/field_encodings.h"
20
#include "lib/jxl/fields.h"
21
#include "lib/jxl/image_ops.h"
22
#include "lib/jxl/modular/modular_image.h"
23
#include "lib/jxl/modular/options.h"
24
25
namespace jxl {
26
27
namespace weighted {
28
constexpr static size_t kNumPredictors = 4;
29
constexpr static int64_t kPredExtraBits = 3;
30
constexpr static int64_t kPredictionRound = ((1 << kPredExtraBits) >> 1) - 1;
31
constexpr static size_t kNumProperties = 1;
32
33
struct Header : public Fields {
34
  JXL_FIELDS_NAME(WeightedPredictorHeader)
35
  // TODO(janwas): move to cc file, avoid including fields.h.
36
421k
  Header() { Bundle::Init(this); }
37
38
567k
  Status VisitFields(Visitor *JXL_RESTRICT visitor) override {
39
567k
    if (visitor->AllDefault(*this, &all_default)) {
40
      // Overwrite all serialized fields, but not any nonserialized_*.
41
62.5k
      visitor->SetDefault(this);
42
62.5k
      return true;
43
62.5k
    }
44
3.53M
    auto visit_p = [visitor](pixel_type val, pixel_type *p) -> Status {
45
3.53M
      uint32_t up = *p;
46
3.53M
      JXL_QUIET_RETURN_IF_ERROR(visitor->Bits(5, val, &up));
47
3.53M
      *p = up;
48
3.53M
      return true;
49
3.53M
    };
50
505k
    JXL_QUIET_RETURN_IF_ERROR(visit_p(16, &p1C));
51
505k
    JXL_QUIET_RETURN_IF_ERROR(visit_p(10, &p2C));
52
505k
    JXL_QUIET_RETURN_IF_ERROR(visit_p(7, &p3Ca));
53
505k
    JXL_QUIET_RETURN_IF_ERROR(visit_p(7, &p3Cb));
54
505k
    JXL_QUIET_RETURN_IF_ERROR(visit_p(7, &p3Cc));
55
504k
    JXL_QUIET_RETURN_IF_ERROR(visit_p(0, &p3Cd));
56
504k
    JXL_QUIET_RETURN_IF_ERROR(visit_p(0, &p3Ce));
57
504k
    JXL_QUIET_RETURN_IF_ERROR(visitor->Bits(4, 0xd, &w[0]));
58
504k
    JXL_QUIET_RETURN_IF_ERROR(visitor->Bits(4, 0xc, &w[1]));
59
504k
    JXL_QUIET_RETURN_IF_ERROR(visitor->Bits(4, 0xc, &w[2]));
60
504k
    JXL_QUIET_RETURN_IF_ERROR(visitor->Bits(4, 0xc, &w[3]));
61
504k
    return true;
62
504k
  }
63
64
  bool all_default;
65
  pixel_type p1C = 0, p2C = 0, p3Ca = 0, p3Cb = 0, p3Cc = 0, p3Cd = 0, p3Ce = 0;
66
  uint32_t w[kNumPredictors] = {};
67
};
68
69
struct State {
70
  pixel_type_w prediction[kNumPredictors] = {};
71
  pixel_type_w pred = 0;  // *before* removing the added bits.
72
  std::vector<uint32_t> pred_errors[kNumPredictors];
73
  std::vector<int32_t> error;
74
  const Header &header;
75
76
  // Allows to approximate division by a number from 1 to 64.
77
  //  for (int i = 0; i < 64; i++) divlookup[i] = (1 << 24) / (i + 1);
78
79
  const uint32_t divlookup[64] = {
80
      16777216, 8388608, 5592405, 4194304, 3355443, 2796202, 2396745, 2097152,
81
      1864135,  1677721, 1525201, 1398101, 1290555, 1198372, 1118481, 1048576,
82
      986895,   932067,  883011,  838860,  798915,  762600,  729444,  699050,
83
      671088,   645277,  621378,  599186,  578524,  559240,  541200,  524288,
84
      508400,   493447,  479349,  466033,  453438,  441505,  430185,  419430,
85
      409200,   399457,  390167,  381300,  372827,  364722,  356962,  349525,
86
      342392,   335544,  328965,  322638,  316551,  310689,  305040,  299593,
87
      294337,   289262,  284359,  279620,  275036,  270600,  266305,  262144};
88
89
875M
  constexpr static pixel_type_w AddBits(pixel_type_w x) {
90
875M
    return static_cast<uint64_t>(x) << kPredExtraBits;
91
875M
  }
92
93
56.0k
  State(const Header &header, size_t xsize, size_t ysize) : header(header) {
94
    // Extra margin to avoid out-of-bounds writes.
95
    // All have space for two rows of data.
96
224k
    for (auto &pred_error : pred_errors) {
97
224k
      pred_error.resize((xsize + 2) * 2);
98
224k
    }
99
56.0k
    error.resize((xsize + 2) * 2);
100
56.0k
  }
101
102
  // Approximates 4+(maxweight<<24)/(x+1), avoiding division
103
583M
  JXL_INLINE uint32_t ErrorWeight(uint64_t x, uint32_t maxweight) const {
104
583M
    int shift = static_cast<int>(FloorLog2Nonzero(x + 1)) - 5;
105
583M
    if (shift < 0) shift = 0;
106
583M
    return 4 + ((maxweight * divlookup[x >> shift]) >> shift);
107
583M
  }
108
109
  // Approximates the weighted average of the input values with the given
110
  // weights, avoiding division. Weights must sum to at least 16.
111
  JXL_INLINE pixel_type_w
112
  WeightedAverage(const pixel_type_w *JXL_RESTRICT p,
113
145M
                  std::array<uint32_t, kNumPredictors> w) const {
114
145M
    uint32_t weight_sum = 0;
115
729M
    for (size_t i = 0; i < kNumPredictors; i++) {
116
583M
      weight_sum += w[i];
117
583M
    }
118
145M
    JXL_DASSERT(weight_sum > 15);
119
145M
    uint32_t log_weight = FloorLog2Nonzero(weight_sum);  // at least 4.
120
145M
    weight_sum = 0;
121
729M
    for (size_t i = 0; i < kNumPredictors; i++) {
122
583M
      w[i] >>= log_weight - 4;
123
583M
      weight_sum += w[i];
124
583M
    }
125
    // for rounding.
126
145M
    pixel_type_w sum = (weight_sum >> 1) - 1;
127
729M
    for (size_t i = 0; i < kNumPredictors; i++) {
128
583M
      sum += p[i] * w[i];
129
583M
    }
130
145M
    return (sum * divlookup[weight_sum - 1]) >> 24;
131
145M
  }
132
133
  template <bool compute_properties>
134
  JXL_INLINE pixel_type_w Predict(size_t x, size_t y, size_t xsize,
135
                                  pixel_type_w N, pixel_type_w W,
136
                                  pixel_type_w NE, pixel_type_w NW,
137
                                  pixel_type_w NN, Properties *properties,
138
145M
                                  size_t offset) {
139
145M
    size_t cur_row = y & 1 ? 0 : (xsize + 2);
140
145M
    size_t prev_row = y & 1 ? (xsize + 2) : 0;
141
145M
    size_t pos_N = prev_row + x;
142
145M
    size_t pos_NE = x < xsize - 1 ? pos_N + 1 : pos_N;
143
145M
    size_t pos_NW = x > 0 ? pos_N - 1 : pos_N;
144
145M
    std::array<uint32_t, kNumPredictors> weights;
145
729M
    for (size_t i = 0; i < kNumPredictors; i++) {
146
      // pred_errors[pos_N] also contains the error of pixel W.
147
      // pred_errors[pos_NW] also contains the error of pixel WW.
148
583M
      weights[i] = pred_errors[i][pos_N] + pred_errors[i][pos_NE] +
149
583M
                   pred_errors[i][pos_NW];
150
583M
      weights[i] = ErrorWeight(weights[i], header.w[i]);
151
583M
    }
152
153
145M
    N = AddBits(N);
154
145M
    W = AddBits(W);
155
145M
    NE = AddBits(NE);
156
145M
    NW = AddBits(NW);
157
145M
    NN = AddBits(NN);
158
159
145M
    pixel_type_w teW = x == 0 ? 0 : error[cur_row + x - 1];
160
145M
    pixel_type_w teN = error[pos_N];
161
145M
    pixel_type_w teNW = error[pos_NW];
162
145M
    pixel_type_w sumWN = teN + teW;
163
145M
    pixel_type_w teNE = error[pos_NE];
164
165
145M
    if (compute_properties) {
166
130M
      pixel_type_w p = teW;
167
130M
      if (std::abs(teN) > std::abs(p)) p = teN;
168
130M
      if (std::abs(teNW) > std::abs(p)) p = teNW;
169
130M
      if (std::abs(teNE) > std::abs(p)) p = teNE;
170
130M
      (*properties)[offset++] = p;
171
130M
    }
172
173
145M
    prediction[0] = W + NE - N;
174
145M
    prediction[1] = N - (((sumWN + teNE) * header.p1C) >> 5);
175
145M
    prediction[2] = W - (((sumWN + teNW) * header.p2C) >> 5);
176
145M
    prediction[3] =
177
145M
        N - ((teNW * header.p3Ca + teN * header.p3Cb + teNE * header.p3Cc +
178
145M
              (NN - N) * header.p3Cd + (NW - W) * header.p3Ce) >>
179
145M
             5);
180
181
145M
    pred = WeightedAverage(prediction, weights);
182
183
    // If all three have the same sign, skip clamping.
184
145M
    if (((teN ^ teW) | (teN ^ teNW)) > 0) {
185
31.9M
      return (pred + kPredictionRound) >> kPredExtraBits;
186
31.9M
    }
187
188
    // Otherwise, clamp to min/max of neighbouring pixels (just W, NE, N).
189
113M
    pixel_type_w mx = std::max(W, std::max(NE, N));
190
113M
    pixel_type_w mn = std::min(W, std::min(NE, N));
191
113M
    pred = std::max(mn, std::min(mx, pred));
192
113M
    return (pred + kPredictionRound) >> kPredExtraBits;
193
145M
  }
long jxl::weighted::State::Predict<false>(unsigned long, unsigned long, unsigned long, long, long, long, long, long, std::__1::vector<int, std::__1::allocator<int> >*, unsigned long)
Line
Count
Source
138
15.6M
                                  size_t offset) {
139
15.6M
    size_t cur_row = y & 1 ? 0 : (xsize + 2);
140
15.6M
    size_t prev_row = y & 1 ? (xsize + 2) : 0;
141
15.6M
    size_t pos_N = prev_row + x;
142
15.6M
    size_t pos_NE = x < xsize - 1 ? pos_N + 1 : pos_N;
143
15.6M
    size_t pos_NW = x > 0 ? pos_N - 1 : pos_N;
144
15.6M
    std::array<uint32_t, kNumPredictors> weights;
145
78.1M
    for (size_t i = 0; i < kNumPredictors; i++) {
146
      // pred_errors[pos_N] also contains the error of pixel W.
147
      // pred_errors[pos_NW] also contains the error of pixel WW.
148
62.5M
      weights[i] = pred_errors[i][pos_N] + pred_errors[i][pos_NE] +
149
62.5M
                   pred_errors[i][pos_NW];
150
62.5M
      weights[i] = ErrorWeight(weights[i], header.w[i]);
151
62.5M
    }
152
153
15.6M
    N = AddBits(N);
154
15.6M
    W = AddBits(W);
155
15.6M
    NE = AddBits(NE);
156
15.6M
    NW = AddBits(NW);
157
15.6M
    NN = AddBits(NN);
158
159
15.6M
    pixel_type_w teW = x == 0 ? 0 : error[cur_row + x - 1];
160
15.6M
    pixel_type_w teN = error[pos_N];
161
15.6M
    pixel_type_w teNW = error[pos_NW];
162
15.6M
    pixel_type_w sumWN = teN + teW;
163
15.6M
    pixel_type_w teNE = error[pos_NE];
164
165
15.6M
    if (compute_properties) {
166
0
      pixel_type_w p = teW;
167
0
      if (std::abs(teN) > std::abs(p)) p = teN;
168
0
      if (std::abs(teNW) > std::abs(p)) p = teNW;
169
0
      if (std::abs(teNE) > std::abs(p)) p = teNE;
170
0
      (*properties)[offset++] = p;
171
0
    }
172
173
15.6M
    prediction[0] = W + NE - N;
174
15.6M
    prediction[1] = N - (((sumWN + teNE) * header.p1C) >> 5);
175
15.6M
    prediction[2] = W - (((sumWN + teNW) * header.p2C) >> 5);
176
15.6M
    prediction[3] =
177
15.6M
        N - ((teNW * header.p3Ca + teN * header.p3Cb + teNE * header.p3Cc +
178
15.6M
              (NN - N) * header.p3Cd + (NW - W) * header.p3Ce) >>
179
15.6M
             5);
180
181
15.6M
    pred = WeightedAverage(prediction, weights);
182
183
    // If all three have the same sign, skip clamping.
184
15.6M
    if (((teN ^ teW) | (teN ^ teNW)) > 0) {
185
2.22M
      return (pred + kPredictionRound) >> kPredExtraBits;
186
2.22M
    }
187
188
    // Otherwise, clamp to min/max of neighbouring pixels (just W, NE, N).
189
13.4M
    pixel_type_w mx = std::max(W, std::max(NE, N));
190
13.4M
    pixel_type_w mn = std::min(W, std::min(NE, N));
191
13.4M
    pred = std::max(mn, std::min(mx, pred));
192
13.4M
    return (pred + kPredictionRound) >> kPredExtraBits;
193
15.6M
  }
long jxl::weighted::State::Predict<true>(unsigned long, unsigned long, unsigned long, long, long, long, long, long, std::__1::vector<int, std::__1::allocator<int> >*, unsigned long)
Line
Count
Source
138
130M
                                  size_t offset) {
139
130M
    size_t cur_row = y & 1 ? 0 : (xsize + 2);
140
130M
    size_t prev_row = y & 1 ? (xsize + 2) : 0;
141
130M
    size_t pos_N = prev_row + x;
142
130M
    size_t pos_NE = x < xsize - 1 ? pos_N + 1 : pos_N;
143
130M
    size_t pos_NW = x > 0 ? pos_N - 1 : pos_N;
144
130M
    std::array<uint32_t, kNumPredictors> weights;
145
650M
    for (size_t i = 0; i < kNumPredictors; i++) {
146
      // pred_errors[pos_N] also contains the error of pixel W.
147
      // pred_errors[pos_NW] also contains the error of pixel WW.
148
520M
      weights[i] = pred_errors[i][pos_N] + pred_errors[i][pos_NE] +
149
520M
                   pred_errors[i][pos_NW];
150
520M
      weights[i] = ErrorWeight(weights[i], header.w[i]);
151
520M
    }
152
153
130M
    N = AddBits(N);
154
130M
    W = AddBits(W);
155
130M
    NE = AddBits(NE);
156
130M
    NW = AddBits(NW);
157
130M
    NN = AddBits(NN);
158
159
130M
    pixel_type_w teW = x == 0 ? 0 : error[cur_row + x - 1];
160
130M
    pixel_type_w teN = error[pos_N];
161
130M
    pixel_type_w teNW = error[pos_NW];
162
130M
    pixel_type_w sumWN = teN + teW;
163
130M
    pixel_type_w teNE = error[pos_NE];
164
165
130M
    if (compute_properties) {
166
130M
      pixel_type_w p = teW;
167
130M
      if (std::abs(teN) > std::abs(p)) p = teN;
168
130M
      if (std::abs(teNW) > std::abs(p)) p = teNW;
169
130M
      if (std::abs(teNE) > std::abs(p)) p = teNE;
170
130M
      (*properties)[offset++] = p;
171
130M
    }
172
173
130M
    prediction[0] = W + NE - N;
174
130M
    prediction[1] = N - (((sumWN + teNE) * header.p1C) >> 5);
175
130M
    prediction[2] = W - (((sumWN + teNW) * header.p2C) >> 5);
176
130M
    prediction[3] =
177
130M
        N - ((teNW * header.p3Ca + teN * header.p3Cb + teNE * header.p3Cc +
178
130M
              (NN - N) * header.p3Cd + (NW - W) * header.p3Ce) >>
179
130M
             5);
180
181
130M
    pred = WeightedAverage(prediction, weights);
182
183
    // If all three have the same sign, skip clamping.
184
130M
    if (((teN ^ teW) | (teN ^ teNW)) > 0) {
185
29.7M
      return (pred + kPredictionRound) >> kPredExtraBits;
186
29.7M
    }
187
188
    // Otherwise, clamp to min/max of neighbouring pixels (just W, NE, N).
189
100M
    pixel_type_w mx = std::max(W, std::max(NE, N));
190
100M
    pixel_type_w mn = std::min(W, std::min(NE, N));
191
100M
    pred = std::max(mn, std::min(mx, pred));
192
100M
    return (pred + kPredictionRound) >> kPredExtraBits;
193
130M
  }
194
195
  JXL_INLINE void UpdateErrors(pixel_type_w val, size_t x, size_t y,
196
146M
                               size_t xsize) {
197
146M
    size_t cur_row = y & 1 ? 0 : (xsize + 2);
198
146M
    size_t prev_row = y & 1 ? (xsize + 2) : 0;
199
146M
    val = AddBits(val);
200
146M
    error[cur_row + x] = pred - val;
201
730M
    for (size_t i = 0; i < kNumPredictors; i++) {
202
584M
      pixel_type_w err =
203
584M
          (std::abs(prediction[i] - val) + kPredictionRound) >> kPredExtraBits;
204
      // For predicting in the next row.
205
584M
      pred_errors[i][cur_row + x] = err;
206
      // Add the error on this pixel to the error on the NE pixel. This has the
207
      // effect of adding the error on this pixel to the E and EE pixels.
208
584M
      pred_errors[i][prev_row + x + 1] += err;
209
584M
    }
210
146M
  }
211
};
212
213
// Encoder helper function to set the parameters to some presets.
214
3.48k
inline void PredictorMode(int i, Header *header) {
215
3.48k
  switch (i) {
216
3.48k
    case 0:
217
      // ~ lossless16 predictor
218
3.48k
      header->w[0] = 0xd;
219
3.48k
      header->w[1] = 0xc;
220
3.48k
      header->w[2] = 0xc;
221
3.48k
      header->w[3] = 0xc;
222
3.48k
      header->p1C = 16;
223
3.48k
      header->p2C = 10;
224
3.48k
      header->p3Ca = 7;
225
3.48k
      header->p3Cb = 7;
226
3.48k
      header->p3Cc = 7;
227
3.48k
      header->p3Cd = 0;
228
3.48k
      header->p3Ce = 0;
229
3.48k
      break;
230
0
    case 1:
231
      // ~ default lossless8 predictor
232
0
      header->w[0] = 0xd;
233
0
      header->w[1] = 0xc;
234
0
      header->w[2] = 0xc;
235
0
      header->w[3] = 0xb;
236
0
      header->p1C = 8;
237
0
      header->p2C = 8;
238
0
      header->p3Ca = 4;
239
0
      header->p3Cb = 0;
240
0
      header->p3Cc = 3;
241
0
      header->p3Cd = 23;
242
0
      header->p3Ce = 2;
243
0
      break;
244
0
    case 2:
245
      // ~ west lossless8 predictor
246
0
      header->w[0] = 0xd;
247
0
      header->w[1] = 0xc;
248
0
      header->w[2] = 0xd;
249
0
      header->w[3] = 0xc;
250
0
      header->p1C = 10;
251
0
      header->p2C = 9;
252
0
      header->p3Ca = 7;
253
0
      header->p3Cb = 0;
254
0
      header->p3Cc = 0;
255
0
      header->p3Cd = 16;
256
0
      header->p3Ce = 9;
257
0
      break;
258
0
    case 3:
259
      // ~ north lossless8 predictor
260
0
      header->w[0] = 0xd;
261
0
      header->w[1] = 0xd;
262
0
      header->w[2] = 0xc;
263
0
      header->w[3] = 0xc;
264
0
      header->p1C = 16;
265
0
      header->p2C = 8;
266
0
      header->p3Ca = 0;
267
0
      header->p3Cb = 16;
268
0
      header->p3Cc = 0;
269
0
      header->p3Cd = 23;
270
0
      header->p3Ce = 0;
271
0
      break;
272
0
    case 4:
273
0
    default:
274
      // something else, because why not
275
0
      header->w[0] = 0xd;
276
0
      header->w[1] = 0xc;
277
0
      header->w[2] = 0xc;
278
0
      header->w[3] = 0xc;
279
0
      header->p1C = 10;
280
0
      header->p2C = 10;
281
0
      header->p3Ca = 5;
282
0
      header->p3Cb = 5;
283
0
      header->p3Cc = 5;
284
0
      header->p3Cd = 12;
285
0
      header->p3Ce = 4;
286
0
      break;
287
3.48k
  }
288
3.48k
}
289
}  // namespace weighted
290
291
// Returns true if the (meta)predictor makes use of the weighted predictor.
292
9.86k
inline bool PredictorHasWeighted(Predictor predictor) {
293
  // Use a non-defaulted switch to generate a warning if a case is missing.
294
9.86k
  switch (predictor) {
295
0
    case Predictor::Zero:
296
0
    case Predictor::Left:
297
0
    case Predictor::Top:
298
0
    case Predictor::Average0:
299
0
    case Predictor::Select:
300
6.37k
    case Predictor::Gradient:
301
6.37k
      return false;
302
3.48k
    case Predictor::Weighted:
303
3.48k
      return true;
304
0
    case Predictor::TopRight:
305
0
    case Predictor::TopLeft:
306
0
    case Predictor::LeftLeft:
307
0
    case Predictor::Average1:
308
0
    case Predictor::Average2:
309
0
    case Predictor::Average3:
310
0
    case Predictor::Average4:
311
0
      return false;
312
0
    case Predictor::Best:
313
0
    case Predictor::Variable:
314
0
      return true;
315
9.86k
  }
316
317
0
  return false;
318
9.86k
}
319
320
// Stores a node and its two children at the same time. This significantly
321
// reduces the number of branches needed during decoding.
322
struct FlatDecisionNode {
323
  // Property + splitval of the top node.
324
  int32_t property0;  // -1 if leaf.
325
  union {
326
    PropertyVal splitval0;
327
    Predictor predictor;
328
  };
329
  // Property+splitval of the two child nodes.
330
  union {
331
    PropertyVal splitvals[2];
332
    int32_t multiplier;
333
  };
334
  uint32_t childID;  // childID is ctx id if leaf.
335
  union {
336
    int16_t properties[2];
337
    int32_t predictor_offset;
338
  };
339
};
340
using FlatTree = std::vector<FlatDecisionNode>;
341
342
class MATreeLookup {
343
 public:
344
124k
  explicit MATreeLookup(const FlatTree &tree) : nodes_(tree) {}
345
  struct LookupResult {
346
    uint32_t context;
347
    Predictor predictor;
348
    int32_t offset;
349
    int32_t multiplier;
350
  };
351
212M
  JXL_INLINE LookupResult Lookup(const Properties &properties) const {
352
212M
    uint32_t pos = 0;
353
308M
    while (true) {
354
308M
#define TRAVERSE_THE_TREE                                                \
355
474M
  {                                                                      \
356
474M
    const FlatDecisionNode &node = nodes_[pos];                          \
357
474M
    if (node.property0 < 0) {                                            \
358
212M
      return {node.childID, node.predictor, node.predictor_offset,       \
359
212M
              node.multiplier};                                          \
360
212M
    }                                                                    \
361
474M
    bool p0 = properties[node.property0] <= node.splitval0;              \
362
262M
    uint32_t off0 = properties[node.properties[0]] <= node.splitvals[0]; \
363
262M
    uint32_t off1 =                                                      \
364
262M
        2 | int{properties[node.properties[1]] <= node.splitvals[1]};    \
365
262M
    pos = node.childID + (p0 ? off1 : off0);                             \
366
262M
  }
367
368
308M
      TRAVERSE_THE_TREE;
369
166M
      TRAVERSE_THE_TREE;
370
95.2M
    }
371
212M
  }
372
373
 private:
374
  const FlatTree &nodes_;
375
};
376
377
static constexpr size_t kExtraPropsPerChannel = 4;
378
static constexpr size_t kNumNonrefProperties =
379
    kNumStaticProperties + 13 + weighted::kNumProperties;
380
381
constexpr size_t kWPProp = kNumNonrefProperties - weighted::kNumProperties;
382
constexpr size_t kGradientProp = 9;
383
384
// Clamps gradient to the min/max of n, w (and l, implicitly).
385
static JXL_INLINE int32_t ClampedGradient(const int32_t n, const int32_t w,
386
97.2M
                                          const int32_t l) {
387
97.2M
  const int32_t m = std::min(n, w);
388
97.2M
  const int32_t M = std::max(n, w);
389
  // The end result of this operation doesn't overflow or underflow if the
390
  // result is between m and M, but the intermediate value may overflow, so we
391
  // do the intermediate operations in uint32_t and check later if we had an
392
  // overflow or underflow condition comparing m, M and l directly.
393
  // grad = M + m - l = n + w - l
394
97.2M
  const int32_t grad =
395
97.2M
      static_cast<int32_t>(static_cast<uint32_t>(n) + static_cast<uint32_t>(w) -
396
97.2M
                           static_cast<uint32_t>(l));
397
  // We use two sets of ternary operators to force the evaluation of them in
398
  // any case, allowing the compiler to avoid branches and use cmovl/cmovg in
399
  // x86.
400
97.2M
  const int32_t grad_clamp_M = (l < m) ? M : grad;
401
97.2M
  return (l > M) ? m : grad_clamp_M;
402
97.2M
}
Unexecuted instantiation: decode.cc:jxl::ClampedGradient(int, int, int)
encoding.cc:jxl::ClampedGradient(int, int, int)
Line
Count
Source
386
68.4M
                                          const int32_t l) {
387
68.4M
  const int32_t m = std::min(n, w);
388
68.4M
  const int32_t M = std::max(n, w);
389
  // The end result of this operation doesn't overflow or underflow if the
390
  // result is between m and M, but the intermediate value may overflow, so we
391
  // do the intermediate operations in uint32_t and check later if we had an
392
  // overflow or underflow condition comparing m, M and l directly.
393
  // grad = M + m - l = n + w - l
394
68.4M
  const int32_t grad =
395
68.4M
      static_cast<int32_t>(static_cast<uint32_t>(n) + static_cast<uint32_t>(w) -
396
68.4M
                           static_cast<uint32_t>(l));
397
  // We use two sets of ternary operators to force the evaluation of them in
398
  // any case, allowing the compiler to avoid branches and use cmovl/cmovg in
399
  // x86.
400
68.4M
  const int32_t grad_clamp_M = (l < m) ? M : grad;
401
68.4M
  return (l > M) ? m : grad_clamp_M;
402
68.4M
}
Unexecuted instantiation: modular_image.cc:jxl::ClampedGradient(int, int, int)
Unexecuted instantiation: transform.cc:jxl::ClampedGradient(int, int, int)
Unexecuted instantiation: quant_weights.cc:jxl::ClampedGradient(int, int, int)
Unexecuted instantiation: enc_frame.cc:jxl::ClampedGradient(int, int, int)
Unexecuted instantiation: enc_heuristics.cc:jxl::ClampedGradient(int, int, int)
enc_modular.cc:jxl::ClampedGradient(int, int, int)
Line
Count
Source
386
72.6k
                                          const int32_t l) {
387
72.6k
  const int32_t m = std::min(n, w);
388
72.6k
  const int32_t M = std::max(n, w);
389
  // The end result of this operation doesn't overflow or underflow if the
390
  // result is between m and M, but the intermediate value may overflow, so we
391
  // do the intermediate operations in uint32_t and check later if we had an
392
  // overflow or underflow condition comparing m, M and l directly.
393
  // grad = M + m - l = n + w - l
394
72.6k
  const int32_t grad =
395
72.6k
      static_cast<int32_t>(static_cast<uint32_t>(n) + static_cast<uint32_t>(w) -
396
72.6k
                           static_cast<uint32_t>(l));
397
  // We use two sets of ternary operators to force the evaluation of them in
398
  // any case, allowing the compiler to avoid branches and use cmovl/cmovg in
399
  // x86.
400
72.6k
  const int32_t grad_clamp_M = (l < m) ? M : grad;
401
72.6k
  return (l > M) ? m : grad_clamp_M;
402
72.6k
}
Unexecuted instantiation: enc_patch_dictionary.cc:jxl::ClampedGradient(int, int, int)
Unexecuted instantiation: enc_quant_weights.cc:jxl::ClampedGradient(int, int, int)
enc_encoding.cc:jxl::ClampedGradient(int, int, int)
Line
Count
Source
386
28.7M
                                          const int32_t l) {
387
28.7M
  const int32_t m = std::min(n, w);
388
28.7M
  const int32_t M = std::max(n, w);
389
  // The end result of this operation doesn't overflow or underflow if the
390
  // result is between m and M, but the intermediate value may overflow, so we
391
  // do the intermediate operations in uint32_t and check later if we had an
392
  // overflow or underflow condition comparing m, M and l directly.
393
  // grad = M + m - l = n + w - l
394
28.7M
  const int32_t grad =
395
28.7M
      static_cast<int32_t>(static_cast<uint32_t>(n) + static_cast<uint32_t>(w) -
396
28.7M
                           static_cast<uint32_t>(l));
397
  // We use two sets of ternary operators to force the evaluation of them in
398
  // any case, allowing the compiler to avoid branches and use cmovl/cmovg in
399
  // x86.
400
28.7M
  const int32_t grad_clamp_M = (l < m) ? M : grad;
401
28.7M
  return (l > M) ? m : grad_clamp_M;
402
28.7M
}
Unexecuted instantiation: enc_ma.cc:jxl::ClampedGradient(int, int, int)
Unexecuted instantiation: enc_rct.cc:jxl::ClampedGradient(int, int, int)
Unexecuted instantiation: enc_transform.cc:jxl::ClampedGradient(int, int, int)
Unexecuted instantiation: dec_frame.cc:jxl::ClampedGradient(int, int, int)
Unexecuted instantiation: dec_modular.cc:jxl::ClampedGradient(int, int, int)
Unexecuted instantiation: palette.cc:jxl::ClampedGradient(int, int, int)
Unexecuted instantiation: rct.cc:jxl::ClampedGradient(int, int, int)
Unexecuted instantiation: enc_adaptive_quantization.cc:jxl::ClampedGradient(int, int, int)
Unexecuted instantiation: enc_cache.cc:jxl::ClampedGradient(int, int, int)
Unexecuted instantiation: enc_palette.cc:jxl::ClampedGradient(int, int, int)
Unexecuted instantiation: coeff_order.cc:jxl::ClampedGradient(int, int, int)
403
404
1.80M
inline pixel_type_w Select(pixel_type_w a, pixel_type_w b, pixel_type_w c) {
405
1.80M
  pixel_type_w p = a + b - c;
406
1.80M
  pixel_type_w pa = std::abs(p - a);
407
1.80M
  pixel_type_w pb = std::abs(p - b);
408
1.80M
  return pa < pb ? a : b;
409
1.80M
}
410
411
inline void PrecomputeReferences(const Channel &ch, size_t y,
412
                                 const Image &image, uint32_t i,
413
3.66M
                                 Channel *references) {
414
3.66M
  ZeroFillImage(&references->plane);
415
3.66M
  uint32_t offset = 0;
416
3.66M
  size_t num_extra_props = references->w;
417
3.66M
  ptrdiff_t onerow = references->plane.PixelsPerRow();
418
3.66M
  for (int32_t j = static_cast<int32_t>(i) - 1;
419
4.78M
       j >= 0 && offset < num_extra_props; j--) {
420
1.11M
    if (image.channel[j].w != image.channel[i].w ||
421
1.04M
        image.channel[j].h != image.channel[i].h) {
422
1.04M
      continue;
423
1.04M
    }
424
77.4k
    if (image.channel[j].hshift != image.channel[i].hshift) continue;
425
61.2k
    if (image.channel[j].vshift != image.channel[i].vshift) continue;
426
60.9k
    pixel_type *JXL_RESTRICT rp = references->Row(0) + offset;
427
60.9k
    const pixel_type *JXL_RESTRICT rpp = image.channel[j].Row(y);
428
60.9k
    const pixel_type *JXL_RESTRICT rpprev = image.channel[j].Row(y ? y - 1 : 0);
429
2.33M
    for (size_t x = 0; x < ch.w; x++, rp += onerow) {
430
2.27M
      pixel_type_w v = rpp[x];
431
2.27M
      rp[0] = std::abs(v);
432
2.27M
      rp[1] = v;
433
2.27M
      pixel_type_w vleft = (x ? rpp[x - 1] : 0);
434
2.27M
      pixel_type_w vtop = (y ? rpprev[x] : vleft);
435
2.27M
      pixel_type_w vtopleft = (x && y ? rpprev[x - 1] : vleft);
436
2.27M
      pixel_type_w vpredicted = ClampedGradient(vleft, vtop, vtopleft);
437
2.27M
      rp[2] = std::abs(v - vpredicted);
438
2.27M
      rp[3] = v - vpredicted;
439
2.27M
    }
440
441
60.9k
    offset += kExtraPropsPerChannel;
442
60.9k
  }
443
3.66M
}
444
445
struct PredictionResult {
446
  int context = 0;
447
  pixel_type_w guess = 0;
448
  Predictor predictor;
449
  int32_t multiplier;
450
};
451
452
inline void InitPropsRow(
453
    Properties *p,
454
    const std::array<pixel_type, kNumStaticProperties> &static_props,
455
3.66M
    const int y) {
456
11.0M
  for (size_t i = 0; i < kNumStaticProperties; i++) {
457
7.33M
    (*p)[i] = static_props[i];
458
7.33M
  }
459
3.66M
  (*p)[2] = y;
460
3.66M
  (*p)[9] = 0;  // local gradient.
461
3.66M
}
462
463
namespace detail {
464
enum PredictorMode {
465
  kUseTree = 1,
466
  kUseWP = 2,
467
  kForceComputeProperties = 4,
468
  kAllPredictions = 8,
469
  kNoEdgeCases = 16
470
};
471
472
JXL_INLINE pixel_type_w PredictOne(Predictor p, pixel_type_w left,
473
                                   pixel_type_w top, pixel_type_w toptop,
474
                                   pixel_type_w topleft, pixel_type_w topright,
475
                                   pixel_type_w leftleft,
476
                                   pixel_type_w toprightright,
477
257M
                                   pixel_type_w wp_pred) {
478
257M
  switch (p) {
479
22.5M
    case Predictor::Zero:
480
22.5M
      return pixel_type_w{0};
481
15.9M
    case Predictor::Left:
482
15.9M
      return left;
483
23.9M
    case Predictor::Top:
484
23.9M
      return top;
485
1.80M
    case Predictor::Select:
486
1.80M
      return Select(left, top, topleft);
487
37.5M
    case Predictor::Weighted:
488
37.5M
      return wp_pred;
489
88.6M
    case Predictor::Gradient:
490
88.6M
      return pixel_type_w{ClampedGradient(left, top, topleft)};
491
767k
    case Predictor::TopLeft:
492
767k
      return topleft;
493
2.38M
    case Predictor::TopRight:
494
2.38M
      return topright;
495
413k
    case Predictor::LeftLeft:
496
413k
      return leftleft;
497
58.7M
    case Predictor::Average0:
498
58.7M
      return (left + top) / 2;
499
1.23M
    case Predictor::Average1:
500
1.23M
      return (left + topleft) / 2;
501
994k
    case Predictor::Average2:
502
994k
      return (topleft + top) / 2;
503
778k
    case Predictor::Average3:
504
778k
      return (top + topright) / 2;
505
1.77M
    case Predictor::Average4:
506
1.77M
      return (6 * top - 2 * toptop + 7 * left + 1 * leftleft +
507
1.77M
              1 * toprightright + 3 * topright + 8) /
508
1.77M
             16;
509
0
    default:
510
0
      return pixel_type_w{0};
511
257M
  }
512
257M
}
513
514
template <int mode>
515
JXL_INLINE PredictionResult Predict(
516
    Properties *p, size_t w, const pixel_type *JXL_RESTRICT pp,
517
    const ptrdiff_t onerow, const size_t x, const size_t y, Predictor predictor,
518
    const MATreeLookup *lookup, const Channel *references,
519
257M
    weighted::State *wp_state, pixel_type_w *predictions) {
520
  // We start in position 3 because of 2 static properties + y.
521
257M
  size_t offset = 3;
522
257M
  constexpr bool compute_properties =
523
257M
      !!(mode & kUseTree) || !!(mode & kForceComputeProperties);
524
257M
  constexpr bool nec = !!(mode & kNoEdgeCases);
525
257M
  pixel_type_w left = (nec || x ? pp[-1] : (y ? pp[-onerow] : 0));
526
257M
  pixel_type_w top = (nec || y ? pp[-onerow] : left);
527
257M
  pixel_type_w topleft = (nec || (x && y) ? pp[-1 - onerow] : left);
528
257M
  pixel_type_w topright = (nec || (x + 1 < w && y) ? pp[1 - onerow] : top);
529
257M
  pixel_type_w leftleft = (nec || x > 1 ? pp[-2] : left);
530
257M
  pixel_type_w toptop = (nec || y > 1 ? pp[-onerow - onerow] : top);
531
257M
  pixel_type_w toprightright =
532
257M
      (nec || (x + 2 < w && y) ? pp[2 - onerow] : topright);
533
534
257M
  if (compute_properties) {
535
    // location
536
240M
    (*p)[offset++] = x;
537
    // neighbors
538
240M
    (*p)[offset++] = top > 0 ? top : -top;
539
240M
    (*p)[offset++] = left > 0 ? left : -left;
540
240M
    (*p)[offset++] = top;
541
240M
    (*p)[offset++] = left;
542
543
    // local gradient
544
240M
    (*p)[offset] = left - (*p)[offset + 1];
545
240M
    offset++;
546
    // local gradient
547
240M
    (*p)[offset++] = left + top - topleft;
548
549
    // FFV1 context properties
550
240M
    (*p)[offset++] = left - topleft;
551
240M
    (*p)[offset++] = topleft - top;
552
240M
    (*p)[offset++] = top - topright;
553
240M
    (*p)[offset++] = top - toptop;
554
240M
    (*p)[offset++] = left - leftleft;
555
240M
  }
556
557
257M
  pixel_type_w wp_pred = 0;
558
257M
  if (mode & kUseWP) {
559
122M
    wp_pred = wp_state->Predict<compute_properties>(
560
122M
        x, y, w, top, left, topright, topleft, toptop, p, offset);
561
122M
  }
562
257M
  if (!nec && compute_properties) {
563
67.1M
    offset += weighted::kNumProperties;
564
    // Extra properties.
565
67.1M
    const pixel_type *JXL_RESTRICT rp = references->Row(x);
566
161M
    for (size_t i = 0; i < references->w; i++) {
567
94.6M
      (*p)[offset++] = rp[i];
568
94.6M
    }
569
67.1M
  }
570
257M
  PredictionResult result;
571
257M
  if (mode & kUseTree) {
572
212M
    MATreeLookup::LookupResult lr = lookup->Lookup(*p);
573
212M
    result.context = lr.context;
574
212M
    result.guess = lr.offset;
575
212M
    result.multiplier = lr.multiplier;
576
212M
    predictor = lr.predictor;
577
212M
  }
578
257M
  if (mode & kAllPredictions) {
579
0
    for (size_t i = 0; i < kNumModularPredictors; i++) {
580
0
      predictions[i] =
581
0
          PredictOne(static_cast<Predictor>(i), left, top, toptop, topleft,
582
0
                     topright, leftleft, toprightright, wp_pred);
583
0
    }
584
0
  }
585
257M
  result.guess += PredictOne(predictor, left, top, toptop, topleft, topright,
586
257M
                             leftleft, toprightright, wp_pred);
587
257M
  result.predictor = predictor;
588
589
257M
  return result;
590
257M
}
jxl::PredictionResult jxl::detail::Predict<0>(std::__1::vector<int, std::__1::allocator<int> >*, unsigned long, int const*, long, unsigned long, unsigned long, jxl::Predictor, jxl::MATreeLookup const*, jxl::Channel const*, jxl::weighted::State*, long*)
Line
Count
Source
519
1.07M
    weighted::State *wp_state, pixel_type_w *predictions) {
520
  // We start in position 3 because of 2 static properties + y.
521
1.07M
  size_t offset = 3;
522
1.07M
  constexpr bool compute_properties =
523
1.07M
      !!(mode & kUseTree) || !!(mode & kForceComputeProperties);
524
1.07M
  constexpr bool nec = !!(mode & kNoEdgeCases);
525
1.07M
  pixel_type_w left = (nec || x ? pp[-1] : (y ? pp[-onerow] : 0));
526
1.07M
  pixel_type_w top = (nec || y ? pp[-onerow] : left);
527
1.07M
  pixel_type_w topleft = (nec || (x && y) ? pp[-1 - onerow] : left);
528
1.07M
  pixel_type_w topright = (nec || (x + 1 < w && y) ? pp[1 - onerow] : top);
529
1.07M
  pixel_type_w leftleft = (nec || x > 1 ? pp[-2] : left);
530
1.07M
  pixel_type_w toptop = (nec || y > 1 ? pp[-onerow - onerow] : top);
531
1.07M
  pixel_type_w toprightright =
532
1.07M
      (nec || (x + 2 < w && y) ? pp[2 - onerow] : topright);
533
534
1.07M
  if (compute_properties) {
535
    // location
536
0
    (*p)[offset++] = x;
537
    // neighbors
538
0
    (*p)[offset++] = top > 0 ? top : -top;
539
0
    (*p)[offset++] = left > 0 ? left : -left;
540
0
    (*p)[offset++] = top;
541
0
    (*p)[offset++] = left;
542
543
    // local gradient
544
0
    (*p)[offset] = left - (*p)[offset + 1];
545
0
    offset++;
546
    // local gradient
547
0
    (*p)[offset++] = left + top - topleft;
548
549
    // FFV1 context properties
550
0
    (*p)[offset++] = left - topleft;
551
0
    (*p)[offset++] = topleft - top;
552
0
    (*p)[offset++] = top - topright;
553
0
    (*p)[offset++] = top - toptop;
554
0
    (*p)[offset++] = left - leftleft;
555
0
  }
556
557
1.07M
  pixel_type_w wp_pred = 0;
558
1.07M
  if (mode & kUseWP) {
559
0
    wp_pred = wp_state->Predict<compute_properties>(
560
0
        x, y, w, top, left, topright, topleft, toptop, p, offset);
561
0
  }
562
1.07M
  if (!nec && compute_properties) {
563
0
    offset += weighted::kNumProperties;
564
    // Extra properties.
565
0
    const pixel_type *JXL_RESTRICT rp = references->Row(x);
566
0
    for (size_t i = 0; i < references->w; i++) {
567
0
      (*p)[offset++] = rp[i];
568
0
    }
569
0
  }
570
1.07M
  PredictionResult result;
571
1.07M
  if (mode & kUseTree) {
572
0
    MATreeLookup::LookupResult lr = lookup->Lookup(*p);
573
0
    result.context = lr.context;
574
0
    result.guess = lr.offset;
575
0
    result.multiplier = lr.multiplier;
576
0
    predictor = lr.predictor;
577
0
  }
578
1.07M
  if (mode & kAllPredictions) {
579
0
    for (size_t i = 0; i < kNumModularPredictors; i++) {
580
0
      predictions[i] =
581
0
          PredictOne(static_cast<Predictor>(i), left, top, toptop, topleft,
582
0
                     topright, leftleft, toprightright, wp_pred);
583
0
    }
584
0
  }
585
1.07M
  result.guess += PredictOne(predictor, left, top, toptop, topleft, topright,
586
1.07M
                             leftleft, toprightright, wp_pred);
587
1.07M
  result.predictor = predictor;
588
589
1.07M
  return result;
590
1.07M
}
jxl::PredictionResult jxl::detail::Predict<2>(std::__1::vector<int, std::__1::allocator<int> >*, unsigned long, int const*, long, unsigned long, unsigned long, jxl::Predictor, jxl::MATreeLookup const*, jxl::Channel const*, jxl::weighted::State*, long*)
Line
Count
Source
519
15.6M
    weighted::State *wp_state, pixel_type_w *predictions) {
520
  // We start in position 3 because of 2 static properties + y.
521
15.6M
  size_t offset = 3;
522
15.6M
  constexpr bool compute_properties =
523
15.6M
      !!(mode & kUseTree) || !!(mode & kForceComputeProperties);
524
15.6M
  constexpr bool nec = !!(mode & kNoEdgeCases);
525
15.6M
  pixel_type_w left = (nec || x ? pp[-1] : (y ? pp[-onerow] : 0));
526
15.6M
  pixel_type_w top = (nec || y ? pp[-onerow] : left);
527
15.6M
  pixel_type_w topleft = (nec || (x && y) ? pp[-1 - onerow] : left);
528
15.6M
  pixel_type_w topright = (nec || (x + 1 < w && y) ? pp[1 - onerow] : top);
529
15.6M
  pixel_type_w leftleft = (nec || x > 1 ? pp[-2] : left);
530
15.6M
  pixel_type_w toptop = (nec || y > 1 ? pp[-onerow - onerow] : top);
531
15.6M
  pixel_type_w toprightright =
532
15.6M
      (nec || (x + 2 < w && y) ? pp[2 - onerow] : topright);
533
534
15.6M
  if (compute_properties) {
535
    // location
536
0
    (*p)[offset++] = x;
537
    // neighbors
538
0
    (*p)[offset++] = top > 0 ? top : -top;
539
0
    (*p)[offset++] = left > 0 ? left : -left;
540
0
    (*p)[offset++] = top;
541
0
    (*p)[offset++] = left;
542
543
    // local gradient
544
0
    (*p)[offset] = left - (*p)[offset + 1];
545
0
    offset++;
546
    // local gradient
547
0
    (*p)[offset++] = left + top - topleft;
548
549
    // FFV1 context properties
550
0
    (*p)[offset++] = left - topleft;
551
0
    (*p)[offset++] = topleft - top;
552
0
    (*p)[offset++] = top - topright;
553
0
    (*p)[offset++] = top - toptop;
554
0
    (*p)[offset++] = left - leftleft;
555
0
  }
556
557
15.6M
  pixel_type_w wp_pred = 0;
558
15.6M
  if (mode & kUseWP) {
559
15.6M
    wp_pred = wp_state->Predict<compute_properties>(
560
15.6M
        x, y, w, top, left, topright, topleft, toptop, p, offset);
561
15.6M
  }
562
15.6M
  if (!nec && compute_properties) {
563
0
    offset += weighted::kNumProperties;
564
    // Extra properties.
565
0
    const pixel_type *JXL_RESTRICT rp = references->Row(x);
566
0
    for (size_t i = 0; i < references->w; i++) {
567
0
      (*p)[offset++] = rp[i];
568
0
    }
569
0
  }
570
15.6M
  PredictionResult result;
571
15.6M
  if (mode & kUseTree) {
572
0
    MATreeLookup::LookupResult lr = lookup->Lookup(*p);
573
0
    result.context = lr.context;
574
0
    result.guess = lr.offset;
575
0
    result.multiplier = lr.multiplier;
576
0
    predictor = lr.predictor;
577
0
  }
578
15.6M
  if (mode & kAllPredictions) {
579
0
    for (size_t i = 0; i < kNumModularPredictors; i++) {
580
0
      predictions[i] =
581
0
          PredictOne(static_cast<Predictor>(i), left, top, toptop, topleft,
582
0
                     topright, leftleft, toprightright, wp_pred);
583
0
    }
584
0
  }
585
15.6M
  result.guess += PredictOne(predictor, left, top, toptop, topleft, topright,
586
15.6M
                             leftleft, toprightright, wp_pred);
587
15.6M
  result.predictor = predictor;
588
589
15.6M
  return result;
590
15.6M
}
jxl::PredictionResult jxl::detail::Predict<1>(std::__1::vector<int, std::__1::allocator<int> >*, unsigned long, int const*, long, unsigned long, unsigned long, jxl::Predictor, jxl::MATreeLookup const*, jxl::Channel const*, jxl::weighted::State*, long*)
Line
Count
Source
519
31.9M
    weighted::State *wp_state, pixel_type_w *predictions) {
520
  // We start in position 3 because of 2 static properties + y.
521
31.9M
  size_t offset = 3;
522
31.9M
  constexpr bool compute_properties =
523
31.9M
      !!(mode & kUseTree) || !!(mode & kForceComputeProperties);
524
31.9M
  constexpr bool nec = !!(mode & kNoEdgeCases);
525
31.9M
  pixel_type_w left = (nec || x ? pp[-1] : (y ? pp[-onerow] : 0));
526
31.9M
  pixel_type_w top = (nec || y ? pp[-onerow] : left);
527
31.9M
  pixel_type_w topleft = (nec || (x && y) ? pp[-1 - onerow] : left);
528
31.9M
  pixel_type_w topright = (nec || (x + 1 < w && y) ? pp[1 - onerow] : top);
529
31.9M
  pixel_type_w leftleft = (nec || x > 1 ? pp[-2] : left);
530
31.9M
  pixel_type_w toptop = (nec || y > 1 ? pp[-onerow - onerow] : top);
531
31.9M
  pixel_type_w toprightright =
532
31.9M
      (nec || (x + 2 < w && y) ? pp[2 - onerow] : topright);
533
534
31.9M
  if (compute_properties) {
535
    // location
536
31.9M
    (*p)[offset++] = x;
537
    // neighbors
538
31.9M
    (*p)[offset++] = top > 0 ? top : -top;
539
31.9M
    (*p)[offset++] = left > 0 ? left : -left;
540
31.9M
    (*p)[offset++] = top;
541
31.9M
    (*p)[offset++] = left;
542
543
    // local gradient
544
31.9M
    (*p)[offset] = left - (*p)[offset + 1];
545
31.9M
    offset++;
546
    // local gradient
547
31.9M
    (*p)[offset++] = left + top - topleft;
548
549
    // FFV1 context properties
550
31.9M
    (*p)[offset++] = left - topleft;
551
31.9M
    (*p)[offset++] = topleft - top;
552
31.9M
    (*p)[offset++] = top - topright;
553
31.9M
    (*p)[offset++] = top - toptop;
554
31.9M
    (*p)[offset++] = left - leftleft;
555
31.9M
  }
556
557
31.9M
  pixel_type_w wp_pred = 0;
558
31.9M
  if (mode & kUseWP) {
559
0
    wp_pred = wp_state->Predict<compute_properties>(
560
0
        x, y, w, top, left, topright, topleft, toptop, p, offset);
561
0
  }
562
31.9M
  if (!nec && compute_properties) {
563
31.9M
    offset += weighted::kNumProperties;
564
    // Extra properties.
565
31.9M
    const pixel_type *JXL_RESTRICT rp = references->Row(x);
566
114M
    for (size_t i = 0; i < references->w; i++) {
567
82.0M
      (*p)[offset++] = rp[i];
568
82.0M
    }
569
31.9M
  }
570
31.9M
  PredictionResult result;
571
31.9M
  if (mode & kUseTree) {
572
31.9M
    MATreeLookup::LookupResult lr = lookup->Lookup(*p);
573
31.9M
    result.context = lr.context;
574
31.9M
    result.guess = lr.offset;
575
31.9M
    result.multiplier = lr.multiplier;
576
31.9M
    predictor = lr.predictor;
577
31.9M
  }
578
31.9M
  if (mode & kAllPredictions) {
579
0
    for (size_t i = 0; i < kNumModularPredictors; i++) {
580
0
      predictions[i] =
581
0
          PredictOne(static_cast<Predictor>(i), left, top, toptop, topleft,
582
0
                     topright, leftleft, toprightright, wp_pred);
583
0
    }
584
0
  }
585
31.9M
  result.guess += PredictOne(predictor, left, top, toptop, topleft, topright,
586
31.9M
                             leftleft, toprightright, wp_pred);
587
31.9M
  result.predictor = predictor;
588
589
31.9M
  return result;
590
31.9M
}
jxl::PredictionResult jxl::detail::Predict<17>(std::__1::vector<int, std::__1::allocator<int> >*, unsigned long, int const*, long, unsigned long, unsigned long, jxl::Predictor, jxl::MATreeLookup const*, jxl::Channel const*, jxl::weighted::State*, long*)
Line
Count
Source
519
101M
    weighted::State *wp_state, pixel_type_w *predictions) {
520
  // We start in position 3 because of 2 static properties + y.
521
101M
  size_t offset = 3;
522
101M
  constexpr bool compute_properties =
523
101M
      !!(mode & kUseTree) || !!(mode & kForceComputeProperties);
524
101M
  constexpr bool nec = !!(mode & kNoEdgeCases);
525
101M
  pixel_type_w left = (nec || x ? pp[-1] : (y ? pp[-onerow] : 0));
526
101M
  pixel_type_w top = (nec || y ? pp[-onerow] : left);
527
101M
  pixel_type_w topleft = (nec || (x && y) ? pp[-1 - onerow] : left);
528
101M
  pixel_type_w topright = (nec || (x + 1 < w && y) ? pp[1 - onerow] : top);
529
101M
  pixel_type_w leftleft = (nec || x > 1 ? pp[-2] : left);
530
101M
  pixel_type_w toptop = (nec || y > 1 ? pp[-onerow - onerow] : top);
531
101M
  pixel_type_w toprightright =
532
101M
      (nec || (x + 2 < w && y) ? pp[2 - onerow] : topright);
533
534
101M
  if (compute_properties) {
535
    // location
536
101M
    (*p)[offset++] = x;
537
    // neighbors
538
101M
    (*p)[offset++] = top > 0 ? top : -top;
539
101M
    (*p)[offset++] = left > 0 ? left : -left;
540
101M
    (*p)[offset++] = top;
541
101M
    (*p)[offset++] = left;
542
543
    // local gradient
544
101M
    (*p)[offset] = left - (*p)[offset + 1];
545
101M
    offset++;
546
    // local gradient
547
101M
    (*p)[offset++] = left + top - topleft;
548
549
    // FFV1 context properties
550
101M
    (*p)[offset++] = left - topleft;
551
101M
    (*p)[offset++] = topleft - top;
552
101M
    (*p)[offset++] = top - topright;
553
101M
    (*p)[offset++] = top - toptop;
554
101M
    (*p)[offset++] = left - leftleft;
555
101M
  }
556
557
101M
  pixel_type_w wp_pred = 0;
558
101M
  if (mode & kUseWP) {
559
0
    wp_pred = wp_state->Predict<compute_properties>(
560
0
        x, y, w, top, left, topright, topleft, toptop, p, offset);
561
0
  }
562
101M
  if (!nec && compute_properties) {
563
0
    offset += weighted::kNumProperties;
564
    // Extra properties.
565
0
    const pixel_type *JXL_RESTRICT rp = references->Row(x);
566
0
    for (size_t i = 0; i < references->w; i++) {
567
0
      (*p)[offset++] = rp[i];
568
0
    }
569
0
  }
570
101M
  PredictionResult result;
571
101M
  if (mode & kUseTree) {
572
101M
    MATreeLookup::LookupResult lr = lookup->Lookup(*p);
573
101M
    result.context = lr.context;
574
101M
    result.guess = lr.offset;
575
101M
    result.multiplier = lr.multiplier;
576
101M
    predictor = lr.predictor;
577
101M
  }
578
101M
  if (mode & kAllPredictions) {
579
0
    for (size_t i = 0; i < kNumModularPredictors; i++) {
580
0
      predictions[i] =
581
0
          PredictOne(static_cast<Predictor>(i), left, top, toptop, topleft,
582
0
                     topright, leftleft, toprightright, wp_pred);
583
0
    }
584
0
  }
585
101M
  result.guess += PredictOne(predictor, left, top, toptop, topleft, topright,
586
101M
                             leftleft, toprightright, wp_pred);
587
101M
  result.predictor = predictor;
588
589
101M
  return result;
590
101M
}
jxl::PredictionResult jxl::detail::Predict<3>(std::__1::vector<int, std::__1::allocator<int> >*, unsigned long, int const*, long, unsigned long, unsigned long, jxl::Predictor, jxl::MATreeLookup const*, jxl::Channel const*, jxl::weighted::State*, long*)
Line
Count
Source
519
33.6M
    weighted::State *wp_state, pixel_type_w *predictions) {
520
  // We start in position 3 because of 2 static properties + y.
521
33.6M
  size_t offset = 3;
522
33.6M
  constexpr bool compute_properties =
523
33.6M
      !!(mode & kUseTree) || !!(mode & kForceComputeProperties);
524
33.6M
  constexpr bool nec = !!(mode & kNoEdgeCases);
525
33.6M
  pixel_type_w left = (nec || x ? pp[-1] : (y ? pp[-onerow] : 0));
526
33.6M
  pixel_type_w top = (nec || y ? pp[-onerow] : left);
527
33.6M
  pixel_type_w topleft = (nec || (x && y) ? pp[-1 - onerow] : left);
528
33.6M
  pixel_type_w topright = (nec || (x + 1 < w && y) ? pp[1 - onerow] : top);
529
33.6M
  pixel_type_w leftleft = (nec || x > 1 ? pp[-2] : left);
530
33.6M
  pixel_type_w toptop = (nec || y > 1 ? pp[-onerow - onerow] : top);
531
33.6M
  pixel_type_w toprightright =
532
33.6M
      (nec || (x + 2 < w && y) ? pp[2 - onerow] : topright);
533
534
33.6M
  if (compute_properties) {
535
    // location
536
33.6M
    (*p)[offset++] = x;
537
    // neighbors
538
33.6M
    (*p)[offset++] = top > 0 ? top : -top;
539
33.6M
    (*p)[offset++] = left > 0 ? left : -left;
540
33.6M
    (*p)[offset++] = top;
541
33.6M
    (*p)[offset++] = left;
542
543
    // local gradient
544
33.6M
    (*p)[offset] = left - (*p)[offset + 1];
545
33.6M
    offset++;
546
    // local gradient
547
33.6M
    (*p)[offset++] = left + top - topleft;
548
549
    // FFV1 context properties
550
33.6M
    (*p)[offset++] = left - topleft;
551
33.6M
    (*p)[offset++] = topleft - top;
552
33.6M
    (*p)[offset++] = top - topright;
553
33.6M
    (*p)[offset++] = top - toptop;
554
33.6M
    (*p)[offset++] = left - leftleft;
555
33.6M
  }
556
557
33.6M
  pixel_type_w wp_pred = 0;
558
33.6M
  if (mode & kUseWP) {
559
33.6M
    wp_pred = wp_state->Predict<compute_properties>(
560
33.6M
        x, y, w, top, left, topright, topleft, toptop, p, offset);
561
33.6M
  }
562
33.6M
  if (!nec && compute_properties) {
563
33.6M
    offset += weighted::kNumProperties;
564
    // Extra properties.
565
33.6M
    const pixel_type *JXL_RESTRICT rp = references->Row(x);
566
46.2M
    for (size_t i = 0; i < references->w; i++) {
567
12.5M
      (*p)[offset++] = rp[i];
568
12.5M
    }
569
33.6M
  }
570
33.6M
  PredictionResult result;
571
33.6M
  if (mode & kUseTree) {
572
33.6M
    MATreeLookup::LookupResult lr = lookup->Lookup(*p);
573
33.6M
    result.context = lr.context;
574
33.6M
    result.guess = lr.offset;
575
33.6M
    result.multiplier = lr.multiplier;
576
33.6M
    predictor = lr.predictor;
577
33.6M
  }
578
33.6M
  if (mode & kAllPredictions) {
579
0
    for (size_t i = 0; i < kNumModularPredictors; i++) {
580
0
      predictions[i] =
581
0
          PredictOne(static_cast<Predictor>(i), left, top, toptop, topleft,
582
0
                     topright, leftleft, toprightright, wp_pred);
583
0
    }
584
0
  }
585
33.6M
  result.guess += PredictOne(predictor, left, top, toptop, topleft, topright,
586
33.6M
                             leftleft, toprightright, wp_pred);
587
33.6M
  result.predictor = predictor;
588
589
33.6M
  return result;
590
33.6M
}
jxl::PredictionResult jxl::detail::Predict<19>(std::__1::vector<int, std::__1::allocator<int> >*, unsigned long, int const*, long, unsigned long, unsigned long, jxl::Predictor, jxl::MATreeLookup const*, jxl::Channel const*, jxl::weighted::State*, long*)
Line
Count
Source
519
45.5M
    weighted::State *wp_state, pixel_type_w *predictions) {
520
  // We start in position 3 because of 2 static properties + y.
521
45.5M
  size_t offset = 3;
522
45.5M
  constexpr bool compute_properties =
523
45.5M
      !!(mode & kUseTree) || !!(mode & kForceComputeProperties);
524
45.5M
  constexpr bool nec = !!(mode & kNoEdgeCases);
525
45.5M
  pixel_type_w left = (nec || x ? pp[-1] : (y ? pp[-onerow] : 0));
526
45.5M
  pixel_type_w top = (nec || y ? pp[-onerow] : left);
527
45.5M
  pixel_type_w topleft = (nec || (x && y) ? pp[-1 - onerow] : left);
528
45.5M
  pixel_type_w topright = (nec || (x + 1 < w && y) ? pp[1 - onerow] : top);
529
45.5M
  pixel_type_w leftleft = (nec || x > 1 ? pp[-2] : left);
530
45.5M
  pixel_type_w toptop = (nec || y > 1 ? pp[-onerow - onerow] : top);
531
45.5M
  pixel_type_w toprightright =
532
45.5M
      (nec || (x + 2 < w && y) ? pp[2 - onerow] : topright);
533
534
45.5M
  if (compute_properties) {
535
    // location
536
45.5M
    (*p)[offset++] = x;
537
    // neighbors
538
45.5M
    (*p)[offset++] = top > 0 ? top : -top;
539
45.5M
    (*p)[offset++] = left > 0 ? left : -left;
540
45.5M
    (*p)[offset++] = top;
541
45.5M
    (*p)[offset++] = left;
542
543
    // local gradient
544
45.5M
    (*p)[offset] = left - (*p)[offset + 1];
545
45.5M
    offset++;
546
    // local gradient
547
45.5M
    (*p)[offset++] = left + top - topleft;
548
549
    // FFV1 context properties
550
45.5M
    (*p)[offset++] = left - topleft;
551
45.5M
    (*p)[offset++] = topleft - top;
552
45.5M
    (*p)[offset++] = top - topright;
553
45.5M
    (*p)[offset++] = top - toptop;
554
45.5M
    (*p)[offset++] = left - leftleft;
555
45.5M
  }
556
557
45.5M
  pixel_type_w wp_pred = 0;
558
45.5M
  if (mode & kUseWP) {
559
45.5M
    wp_pred = wp_state->Predict<compute_properties>(
560
45.5M
        x, y, w, top, left, topright, topleft, toptop, p, offset);
561
45.5M
  }
562
45.5M
  if (!nec && compute_properties) {
563
0
    offset += weighted::kNumProperties;
564
    // Extra properties.
565
0
    const pixel_type *JXL_RESTRICT rp = references->Row(x);
566
0
    for (size_t i = 0; i < references->w; i++) {
567
0
      (*p)[offset++] = rp[i];
568
0
    }
569
0
  }
570
45.5M
  PredictionResult result;
571
45.5M
  if (mode & kUseTree) {
572
45.5M
    MATreeLookup::LookupResult lr = lookup->Lookup(*p);
573
45.5M
    result.context = lr.context;
574
45.5M
    result.guess = lr.offset;
575
45.5M
    result.multiplier = lr.multiplier;
576
45.5M
    predictor = lr.predictor;
577
45.5M
  }
578
45.5M
  if (mode & kAllPredictions) {
579
0
    for (size_t i = 0; i < kNumModularPredictors; i++) {
580
0
      predictions[i] =
581
0
          PredictOne(static_cast<Predictor>(i), left, top, toptop, topleft,
582
0
                     topright, leftleft, toprightright, wp_pred);
583
0
    }
584
0
  }
585
45.5M
  result.guess += PredictOne(predictor, left, top, toptop, topleft, topright,
586
45.5M
                             leftleft, toprightright, wp_pred);
587
45.5M
  result.predictor = predictor;
588
589
45.5M
  return result;
590
45.5M
}
jxl::PredictionResult jxl::detail::Predict<6>(std::__1::vector<int, std::__1::allocator<int> >*, unsigned long, int const*, long, unsigned long, unsigned long, jxl::Predictor, jxl::MATreeLookup const*, jxl::Channel const*, jxl::weighted::State*, long*)
Line
Count
Source
519
1.48M
    weighted::State *wp_state, pixel_type_w *predictions) {
520
  // We start in position 3 because of 2 static properties + y.
521
1.48M
  size_t offset = 3;
522
1.48M
  constexpr bool compute_properties =
523
1.48M
      !!(mode & kUseTree) || !!(mode & kForceComputeProperties);
524
1.48M
  constexpr bool nec = !!(mode & kNoEdgeCases);
525
1.48M
  pixel_type_w left = (nec || x ? pp[-1] : (y ? pp[-onerow] : 0));
526
1.48M
  pixel_type_w top = (nec || y ? pp[-onerow] : left);
527
1.48M
  pixel_type_w topleft = (nec || (x && y) ? pp[-1 - onerow] : left);
528
1.48M
  pixel_type_w topright = (nec || (x + 1 < w && y) ? pp[1 - onerow] : top);
529
1.48M
  pixel_type_w leftleft = (nec || x > 1 ? pp[-2] : left);
530
1.48M
  pixel_type_w toptop = (nec || y > 1 ? pp[-onerow - onerow] : top);
531
1.48M
  pixel_type_w toprightright =
532
1.48M
      (nec || (x + 2 < w && y) ? pp[2 - onerow] : topright);
533
534
1.48M
  if (compute_properties) {
535
    // location
536
1.48M
    (*p)[offset++] = x;
537
    // neighbors
538
1.48M
    (*p)[offset++] = top > 0 ? top : -top;
539
1.48M
    (*p)[offset++] = left > 0 ? left : -left;
540
1.48M
    (*p)[offset++] = top;
541
1.48M
    (*p)[offset++] = left;
542
543
    // local gradient
544
1.48M
    (*p)[offset] = left - (*p)[offset + 1];
545
1.48M
    offset++;
546
    // local gradient
547
1.48M
    (*p)[offset++] = left + top - topleft;
548
549
    // FFV1 context properties
550
1.48M
    (*p)[offset++] = left - topleft;
551
1.48M
    (*p)[offset++] = topleft - top;
552
1.48M
    (*p)[offset++] = top - topright;
553
1.48M
    (*p)[offset++] = top - toptop;
554
1.48M
    (*p)[offset++] = left - leftleft;
555
1.48M
  }
556
557
1.48M
  pixel_type_w wp_pred = 0;
558
1.48M
  if (mode & kUseWP) {
559
1.48M
    wp_pred = wp_state->Predict<compute_properties>(
560
1.48M
        x, y, w, top, left, topright, topleft, toptop, p, offset);
561
1.48M
  }
562
1.48M
  if (!nec && compute_properties) {
563
1.48M
    offset += weighted::kNumProperties;
564
    // Extra properties.
565
1.48M
    const pixel_type *JXL_RESTRICT rp = references->Row(x);
566
1.48M
    for (size_t i = 0; i < references->w; i++) {
567
0
      (*p)[offset++] = rp[i];
568
0
    }
569
1.48M
  }
570
1.48M
  PredictionResult result;
571
1.48M
  if (mode & kUseTree) {
572
0
    MATreeLookup::LookupResult lr = lookup->Lookup(*p);
573
0
    result.context = lr.context;
574
0
    result.guess = lr.offset;
575
0
    result.multiplier = lr.multiplier;
576
0
    predictor = lr.predictor;
577
0
  }
578
1.48M
  if (mode & kAllPredictions) {
579
0
    for (size_t i = 0; i < kNumModularPredictors; i++) {
580
0
      predictions[i] =
581
0
          PredictOne(static_cast<Predictor>(i), left, top, toptop, topleft,
582
0
                     topright, leftleft, toprightright, wp_pred);
583
0
    }
584
0
  }
585
1.48M
  result.guess += PredictOne(predictor, left, top, toptop, topleft, topright,
586
1.48M
                             leftleft, toprightright, wp_pred);
587
1.48M
  result.predictor = predictor;
588
589
1.48M
  return result;
590
1.48M
}
Unexecuted instantiation: jxl::PredictionResult jxl::detail::Predict<14>(std::__1::vector<int, std::__1::allocator<int> >*, unsigned long, int const*, long, unsigned long, unsigned long, jxl::Predictor, jxl::MATreeLookup const*, jxl::Channel const*, jxl::weighted::State*, long*)
jxl::PredictionResult jxl::detail::Predict<22>(std::__1::vector<int, std::__1::allocator<int> >*, unsigned long, int const*, long, unsigned long, unsigned long, jxl::Predictor, jxl::MATreeLookup const*, jxl::Channel const*, jxl::weighted::State*, long*)
Line
Count
Source
519
26.2M
    weighted::State *wp_state, pixel_type_w *predictions) {
520
  // We start in position 3 because of 2 static properties + y.
521
26.2M
  size_t offset = 3;
522
26.2M
  constexpr bool compute_properties =
523
26.2M
      !!(mode & kUseTree) || !!(mode & kForceComputeProperties);
524
26.2M
  constexpr bool nec = !!(mode & kNoEdgeCases);
525
26.2M
  pixel_type_w left = (nec || x ? pp[-1] : (y ? pp[-onerow] : 0));
526
26.2M
  pixel_type_w top = (nec || y ? pp[-onerow] : left);
527
26.2M
  pixel_type_w topleft = (nec || (x && y) ? pp[-1 - onerow] : left);
528
26.2M
  pixel_type_w topright = (nec || (x + 1 < w && y) ? pp[1 - onerow] : top);
529
26.2M
  pixel_type_w leftleft = (nec || x > 1 ? pp[-2] : left);
530
26.2M
  pixel_type_w toptop = (nec || y > 1 ? pp[-onerow - onerow] : top);
531
26.2M
  pixel_type_w toprightright =
532
26.2M
      (nec || (x + 2 < w && y) ? pp[2 - onerow] : topright);
533
534
26.2M
  if (compute_properties) {
535
    // location
536
26.2M
    (*p)[offset++] = x;
537
    // neighbors
538
26.2M
    (*p)[offset++] = top > 0 ? top : -top;
539
26.2M
    (*p)[offset++] = left > 0 ? left : -left;
540
26.2M
    (*p)[offset++] = top;
541
26.2M
    (*p)[offset++] = left;
542
543
    // local gradient
544
26.2M
    (*p)[offset] = left - (*p)[offset + 1];
545
26.2M
    offset++;
546
    // local gradient
547
26.2M
    (*p)[offset++] = left + top - topleft;
548
549
    // FFV1 context properties
550
26.2M
    (*p)[offset++] = left - topleft;
551
26.2M
    (*p)[offset++] = topleft - top;
552
26.2M
    (*p)[offset++] = top - topright;
553
26.2M
    (*p)[offset++] = top - toptop;
554
26.2M
    (*p)[offset++] = left - leftleft;
555
26.2M
  }
556
557
26.2M
  pixel_type_w wp_pred = 0;
558
26.2M
  if (mode & kUseWP) {
559
26.2M
    wp_pred = wp_state->Predict<compute_properties>(
560
26.2M
        x, y, w, top, left, topright, topleft, toptop, p, offset);
561
26.2M
  }
562
26.2M
  if (!nec && compute_properties) {
563
0
    offset += weighted::kNumProperties;
564
    // Extra properties.
565
0
    const pixel_type *JXL_RESTRICT rp = references->Row(x);
566
0
    for (size_t i = 0; i < references->w; i++) {
567
0
      (*p)[offset++] = rp[i];
568
0
    }
569
0
  }
570
26.2M
  PredictionResult result;
571
26.2M
  if (mode & kUseTree) {
572
0
    MATreeLookup::LookupResult lr = lookup->Lookup(*p);
573
0
    result.context = lr.context;
574
0
    result.guess = lr.offset;
575
0
    result.multiplier = lr.multiplier;
576
0
    predictor = lr.predictor;
577
0
  }
578
26.2M
  if (mode & kAllPredictions) {
579
0
    for (size_t i = 0; i < kNumModularPredictors; i++) {
580
0
      predictions[i] =
581
0
          PredictOne(static_cast<Predictor>(i), left, top, toptop, topleft,
582
0
                     topright, leftleft, toprightright, wp_pred);
583
0
    }
584
0
  }
585
26.2M
  result.guess += PredictOne(predictor, left, top, toptop, topleft, topright,
586
26.2M
                             leftleft, toprightright, wp_pred);
587
26.2M
  result.predictor = predictor;
588
589
26.2M
  return result;
590
26.2M
}
Unexecuted instantiation: jxl::PredictionResult jxl::detail::Predict<30>(std::__1::vector<int, std::__1::allocator<int> >*, unsigned long, int const*, long, unsigned long, unsigned long, jxl::Predictor, jxl::MATreeLookup const*, jxl::Channel const*, jxl::weighted::State*, long*)
Unexecuted instantiation: jxl::PredictionResult jxl::detail::Predict<8>(std::__1::vector<int, std::__1::allocator<int> >*, unsigned long, int const*, long, unsigned long, unsigned long, jxl::Predictor, jxl::MATreeLookup const*, jxl::Channel const*, jxl::weighted::State*, long*)
591
}  // namespace detail
592
593
inline PredictionResult PredictNoTreeNoWP(size_t w,
594
                                          const pixel_type *JXL_RESTRICT pp,
595
                                          const ptrdiff_t onerow, const int x,
596
1.07M
                                          const int y, Predictor predictor) {
597
1.07M
  return detail::Predict</*mode=*/0>(
598
1.07M
      /*p=*/nullptr, w, pp, onerow, x, y, predictor, /*lookup=*/nullptr,
599
1.07M
      /*references=*/nullptr, /*wp_state=*/nullptr, /*predictions=*/nullptr);
600
1.07M
}
601
602
inline PredictionResult PredictNoTreeWP(size_t w,
603
                                        const pixel_type *JXL_RESTRICT pp,
604
                                        const ptrdiff_t onerow, const int x,
605
                                        const int y, Predictor predictor,
606
15.6M
                                        weighted::State *wp_state) {
607
15.6M
  return detail::Predict<detail::kUseWP>(
608
15.6M
      /*p=*/nullptr, w, pp, onerow, x, y, predictor, /*lookup=*/nullptr,
609
15.6M
      /*references=*/nullptr, wp_state, /*predictions=*/nullptr);
610
15.6M
}
611
612
inline PredictionResult PredictTreeNoWP(Properties *p, size_t w,
613
                                        const pixel_type *JXL_RESTRICT pp,
614
                                        const ptrdiff_t onerow, const int x,
615
                                        const int y,
616
                                        const MATreeLookup &tree_lookup,
617
31.9M
                                        const Channel &references) {
618
31.9M
  return detail::Predict<detail::kUseTree>(
619
31.9M
      p, w, pp, onerow, x, y, Predictor::Zero, &tree_lookup, &references,
620
31.9M
      /*wp_state=*/nullptr, /*predictions=*/nullptr);
621
31.9M
}
622
// Only use for y > 1, x > 1, x < w-2, and empty references
623
JXL_INLINE PredictionResult
624
PredictTreeNoWPNEC(Properties *p, size_t w, const pixel_type *JXL_RESTRICT pp,
625
                   const ptrdiff_t onerow, const int x, const int y,
626
101M
                   const MATreeLookup &tree_lookup, const Channel &references) {
627
101M
  return detail::Predict<detail::kUseTree | detail::kNoEdgeCases>(
628
101M
      p, w, pp, onerow, x, y, Predictor::Zero, &tree_lookup, &references,
629
101M
      /*wp_state=*/nullptr, /*predictions=*/nullptr);
630
101M
}
631
632
inline PredictionResult PredictTreeWP(Properties *p, size_t w,
633
                                      const pixel_type *JXL_RESTRICT pp,
634
                                      const ptrdiff_t onerow, const int x,
635
                                      const int y,
636
                                      const MATreeLookup &tree_lookup,
637
                                      const Channel &references,
638
33.6M
                                      weighted::State *wp_state) {
639
33.6M
  return detail::Predict<detail::kUseTree | detail::kUseWP>(
640
33.6M
      p, w, pp, onerow, x, y, Predictor::Zero, &tree_lookup, &references,
641
33.6M
      wp_state, /*predictions=*/nullptr);
642
33.6M
}
643
JXL_INLINE PredictionResult PredictTreeWPNEC(Properties *p, size_t w,
644
                                             const pixel_type *JXL_RESTRICT pp,
645
                                             const ptrdiff_t onerow, const int x,
646
                                             const int y,
647
                                             const MATreeLookup &tree_lookup,
648
                                             const Channel &references,
649
45.5M
                                             weighted::State *wp_state) {
650
45.5M
  return detail::Predict<detail::kUseTree | detail::kUseWP |
651
45.5M
                         detail::kNoEdgeCases>(
652
45.5M
      p, w, pp, onerow, x, y, Predictor::Zero, &tree_lookup, &references,
653
45.5M
      wp_state, /*predictions=*/nullptr);
654
45.5M
}
655
656
inline PredictionResult PredictLearn(Properties *p, size_t w,
657
                                     const pixel_type *JXL_RESTRICT pp,
658
                                     const ptrdiff_t onerow, const int x,
659
                                     const int y, Predictor predictor,
660
                                     const Channel &references,
661
1.48M
                                     weighted::State *wp_state) {
662
1.48M
  return detail::Predict<detail::kForceComputeProperties | detail::kUseWP>(
663
1.48M
      p, w, pp, onerow, x, y, predictor, /*lookup=*/nullptr, &references,
664
1.48M
      wp_state, /*predictions=*/nullptr);
665
1.48M
}
666
667
inline void PredictLearnAll(Properties *p, size_t w,
668
                            const pixel_type *JXL_RESTRICT pp,
669
                            const ptrdiff_t onerow, const int x, const int y,
670
                            const Channel &references,
671
                            weighted::State *wp_state,
672
0
                            pixel_type_w *predictions) {
673
0
  detail::Predict<detail::kForceComputeProperties | detail::kUseWP |
674
0
                  detail::kAllPredictions>(
675
0
      p, w, pp, onerow, x, y, Predictor::Zero,
676
0
      /*lookup=*/nullptr, &references, wp_state, predictions);
677
0
}
678
inline PredictionResult PredictLearnNEC(Properties *p, size_t w,
679
                                        const pixel_type *JXL_RESTRICT pp,
680
                                        const ptrdiff_t onerow, const int x,
681
                                        const int y, Predictor predictor,
682
                                        const Channel &references,
683
26.2M
                                        weighted::State *wp_state) {
684
26.2M
  return detail::Predict<detail::kForceComputeProperties | detail::kUseWP |
685
26.2M
                         detail::kNoEdgeCases>(
686
26.2M
      p, w, pp, onerow, x, y, predictor, /*lookup=*/nullptr, &references,
687
26.2M
      wp_state, /*predictions=*/nullptr);
688
26.2M
}
689
690
inline void PredictLearnAllNEC(Properties *p, size_t w,
691
                               const pixel_type *JXL_RESTRICT pp,
692
                               const ptrdiff_t onerow, const int x, const int y,
693
                               const Channel &references,
694
                               weighted::State *wp_state,
695
0
                               pixel_type_w *predictions) {
696
0
  detail::Predict<detail::kForceComputeProperties | detail::kUseWP |
697
0
                  detail::kAllPredictions | detail::kNoEdgeCases>(
698
0
      p, w, pp, onerow, x, y, Predictor::Zero,
699
0
      /*lookup=*/nullptr, &references, wp_state, predictions);
700
0
}
701
702
inline void PredictAllNoWP(size_t w, const pixel_type *JXL_RESTRICT pp,
703
                           const ptrdiff_t onerow, const int x, const int y,
704
0
                           pixel_type_w *predictions) {
705
0
  detail::Predict<detail::kAllPredictions>(
706
0
      /*p=*/nullptr, w, pp, onerow, x, y, Predictor::Zero,
707
0
      /*lookup=*/nullptr,
708
0
      /*references=*/nullptr, /*wp_state=*/nullptr, predictions);
709
0
}
710
}  // namespace jxl
711
712
#endif  // LIB_JXL_MODULAR_ENCODING_CONTEXT_PREDICT_H_