Coverage Report

Created: 2025-08-12 07:37

/src/libjxl/lib/jxl/modular/encoding/context_predict.h
Line
Count
Source (jump to first uncovered line)
1
// Copyright (c) the JPEG XL Project Authors. All rights reserved.
2
//
3
// Use of this source code is governed by a BSD-style
4
// license that can be found in the LICENSE file.
5
6
#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
103k
  Header() { Bundle::Init(this); }
37
38
159k
  Status VisitFields(Visitor *JXL_RESTRICT visitor) override {
39
159k
    if (visitor->AllDefault(*this, &all_default)) {
40
      // Overwrite all serialized fields, but not any nonserialized_*.
41
24.8k
      visitor->SetDefault(this);
42
24.8k
      return true;
43
24.8k
    }
44
940k
    auto visit_p = [visitor](pixel_type val, pixel_type *p) -> Status {
45
940k
      uint32_t up = *p;
46
940k
      JXL_QUIET_RETURN_IF_ERROR(visitor->Bits(5, val, &up));
47
940k
      *p = up;
48
940k
      return true;
49
940k
    };
50
134k
    JXL_QUIET_RETURN_IF_ERROR(visit_p(16, &p1C));
51
134k
    JXL_QUIET_RETURN_IF_ERROR(visit_p(10, &p2C));
52
134k
    JXL_QUIET_RETURN_IF_ERROR(visit_p(7, &p3Ca));
53
134k
    JXL_QUIET_RETURN_IF_ERROR(visit_p(7, &p3Cb));
54
134k
    JXL_QUIET_RETURN_IF_ERROR(visit_p(7, &p3Cc));
55
134k
    JXL_QUIET_RETURN_IF_ERROR(visit_p(0, &p3Cd));
56
134k
    JXL_QUIET_RETURN_IF_ERROR(visit_p(0, &p3Ce));
57
134k
    JXL_QUIET_RETURN_IF_ERROR(visitor->Bits(4, 0xd, &w[0]));
58
134k
    JXL_QUIET_RETURN_IF_ERROR(visitor->Bits(4, 0xc, &w[1]));
59
134k
    JXL_QUIET_RETURN_IF_ERROR(visitor->Bits(4, 0xc, &w[2]));
60
134k
    JXL_QUIET_RETURN_IF_ERROR(visitor->Bits(4, 0xc, &w[3]));
61
134k
    return true;
62
134k
  }
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
55.0M
  constexpr static pixel_type_w AddBits(pixel_type_w x) {
90
55.0M
    return static_cast<uint64_t>(x) << kPredExtraBits;
91
55.0M
  }
92
93
4.93k
  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
19.7k
    for (auto &pred_error : pred_errors) {
97
19.7k
      pred_error.resize((xsize + 2) * 2);
98
19.7k
    }
99
4.93k
    error.resize((xsize + 2) * 2);
100
4.93k
  }
101
102
  // Approximates 4+(maxweight<<24)/(x+1), avoiding division
103
30.2M
  JXL_INLINE uint32_t ErrorWeight(uint64_t x, uint32_t maxweight) const {
104
30.2M
    int shift = static_cast<int>(FloorLog2Nonzero(x + 1)) - 5;
105
30.2M
    if (shift < 0) shift = 0;
106
30.2M
    return 4 + ((maxweight * divlookup[x >> shift]) >> shift);
107
30.2M
  }
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
7.56M
                  std::array<uint32_t, kNumPredictors> w) const {
114
7.56M
    uint32_t weight_sum = 0;
115
37.8M
    for (size_t i = 0; i < kNumPredictors; i++) {
116
30.2M
      weight_sum += w[i];
117
30.2M
    }
118
7.56M
    JXL_DASSERT(weight_sum > 15);
119
7.56M
    uint32_t log_weight = FloorLog2Nonzero(weight_sum);  // at least 4.
120
7.56M
    weight_sum = 0;
121
37.8M
    for (size_t i = 0; i < kNumPredictors; i++) {
122
30.2M
      w[i] >>= log_weight - 4;
123
30.2M
      weight_sum += w[i];
124
30.2M
    }
125
    // for rounding.
126
7.56M
    pixel_type_w sum = (weight_sum >> 1) - 1;
127
37.8M
    for (size_t i = 0; i < kNumPredictors; i++) {
128
30.2M
      sum += p[i] * w[i];
129
30.2M
    }
130
7.56M
    return (sum * divlookup[weight_sum - 1]) >> 24;
131
7.56M
  }
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
7.56M
                                  size_t offset) {
139
7.56M
    size_t cur_row = y & 1 ? 0 : (xsize + 2);
140
7.56M
    size_t prev_row = y & 1 ? (xsize + 2) : 0;
141
7.56M
    size_t pos_N = prev_row + x;
142
7.56M
    size_t pos_NE = x < xsize - 1 ? pos_N + 1 : pos_N;
143
7.56M
    size_t pos_NW = x > 0 ? pos_N - 1 : pos_N;
144
7.56M
    std::array<uint32_t, kNumPredictors> weights;
145
37.8M
    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
30.2M
      weights[i] = pred_errors[i][pos_N] + pred_errors[i][pos_NE] +
149
30.2M
                   pred_errors[i][pos_NW];
150
30.2M
      weights[i] = ErrorWeight(weights[i], header.w[i]);
151
30.2M
    }
152
153
7.56M
    N = AddBits(N);
154
7.56M
    W = AddBits(W);
155
7.56M
    NE = AddBits(NE);
156
7.56M
    NW = AddBits(NW);
157
7.56M
    NN = AddBits(NN);
158
159
7.56M
    pixel_type_w teW = x == 0 ? 0 : error[cur_row + x - 1];
160
7.56M
    pixel_type_w teN = error[pos_N];
161
7.56M
    pixel_type_w teNW = error[pos_NW];
162
7.56M
    pixel_type_w sumWN = teN + teW;
163
7.56M
    pixel_type_w teNE = error[pos_NE];
164
165
7.56M
    if (compute_properties) {
166
5.95M
      pixel_type_w p = teW;
167
5.95M
      if (std::abs(teN) > std::abs(p)) p = teN;
168
5.95M
      if (std::abs(teNW) > std::abs(p)) p = teNW;
169
5.95M
      if (std::abs(teNE) > std::abs(p)) p = teNE;
170
5.95M
      (*properties)[offset++] = p;
171
5.95M
    }
172
173
7.56M
    prediction[0] = W + NE - N;
174
7.56M
    prediction[1] = N - (((sumWN + teNE) * header.p1C) >> 5);
175
7.56M
    prediction[2] = W - (((sumWN + teNW) * header.p2C) >> 5);
176
7.56M
    prediction[3] =
177
7.56M
        N - ((teNW * header.p3Ca + teN * header.p3Cb + teNE * header.p3Cc +
178
7.56M
              (NN - N) * header.p3Cd + (NW - W) * header.p3Ce) >>
179
7.56M
             5);
180
181
7.56M
    pred = WeightedAverage(prediction, weights);
182
183
    // If all three have the same sign, skip clamping.
184
7.56M
    if (((teN ^ teW) | (teN ^ teNW)) > 0) {
185
2.21M
      return (pred + kPredictionRound) >> kPredExtraBits;
186
2.21M
    }
187
188
    // Otherwise, clamp to min/max of neighbouring pixels (just W, NE, N).
189
5.34M
    pixel_type_w mx = std::max(W, std::max(NE, N));
190
5.34M
    pixel_type_w mn = std::min(W, std::min(NE, N));
191
5.34M
    pred = std::max(mn, std::min(mx, pred));
192
5.34M
    return (pred + kPredictionRound) >> kPredExtraBits;
193
7.56M
  }
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
1.60M
                                  size_t offset) {
139
1.60M
    size_t cur_row = y & 1 ? 0 : (xsize + 2);
140
1.60M
    size_t prev_row = y & 1 ? (xsize + 2) : 0;
141
1.60M
    size_t pos_N = prev_row + x;
142
1.60M
    size_t pos_NE = x < xsize - 1 ? pos_N + 1 : pos_N;
143
1.60M
    size_t pos_NW = x > 0 ? pos_N - 1 : pos_N;
144
1.60M
    std::array<uint32_t, kNumPredictors> weights;
145
8.04M
    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
6.43M
      weights[i] = pred_errors[i][pos_N] + pred_errors[i][pos_NE] +
149
6.43M
                   pred_errors[i][pos_NW];
150
6.43M
      weights[i] = ErrorWeight(weights[i], header.w[i]);
151
6.43M
    }
152
153
1.60M
    N = AddBits(N);
154
1.60M
    W = AddBits(W);
155
1.60M
    NE = AddBits(NE);
156
1.60M
    NW = AddBits(NW);
157
1.60M
    NN = AddBits(NN);
158
159
1.60M
    pixel_type_w teW = x == 0 ? 0 : error[cur_row + x - 1];
160
1.60M
    pixel_type_w teN = error[pos_N];
161
1.60M
    pixel_type_w teNW = error[pos_NW];
162
1.60M
    pixel_type_w sumWN = teN + teW;
163
1.60M
    pixel_type_w teNE = error[pos_NE];
164
165
1.60M
    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
1.60M
    prediction[0] = W + NE - N;
174
1.60M
    prediction[1] = N - (((sumWN + teNE) * header.p1C) >> 5);
175
1.60M
    prediction[2] = W - (((sumWN + teNW) * header.p2C) >> 5);
176
1.60M
    prediction[3] =
177
1.60M
        N - ((teNW * header.p3Ca + teN * header.p3Cb + teNE * header.p3Cc +
178
1.60M
              (NN - N) * header.p3Cd + (NW - W) * header.p3Ce) >>
179
1.60M
             5);
180
181
1.60M
    pred = WeightedAverage(prediction, weights);
182
183
    // If all three have the same sign, skip clamping.
184
1.60M
    if (((teN ^ teW) | (teN ^ teNW)) > 0) {
185
190k
      return (pred + kPredictionRound) >> kPredExtraBits;
186
190k
    }
187
188
    // Otherwise, clamp to min/max of neighbouring pixels (just W, NE, N).
189
1.41M
    pixel_type_w mx = std::max(W, std::max(NE, N));
190
1.41M
    pixel_type_w mn = std::min(W, std::min(NE, N));
191
1.41M
    pred = std::max(mn, std::min(mx, pred));
192
1.41M
    return (pred + kPredictionRound) >> kPredExtraBits;
193
1.60M
  }
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
5.95M
                                  size_t offset) {
139
5.95M
    size_t cur_row = y & 1 ? 0 : (xsize + 2);
140
5.95M
    size_t prev_row = y & 1 ? (xsize + 2) : 0;
141
5.95M
    size_t pos_N = prev_row + x;
142
5.95M
    size_t pos_NE = x < xsize - 1 ? pos_N + 1 : pos_N;
143
5.95M
    size_t pos_NW = x > 0 ? pos_N - 1 : pos_N;
144
5.95M
    std::array<uint32_t, kNumPredictors> weights;
145
29.7M
    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
23.8M
      weights[i] = pred_errors[i][pos_N] + pred_errors[i][pos_NE] +
149
23.8M
                   pred_errors[i][pos_NW];
150
23.8M
      weights[i] = ErrorWeight(weights[i], header.w[i]);
151
23.8M
    }
152
153
5.95M
    N = AddBits(N);
154
5.95M
    W = AddBits(W);
155
5.95M
    NE = AddBits(NE);
156
5.95M
    NW = AddBits(NW);
157
5.95M
    NN = AddBits(NN);
158
159
5.95M
    pixel_type_w teW = x == 0 ? 0 : error[cur_row + x - 1];
160
5.95M
    pixel_type_w teN = error[pos_N];
161
5.95M
    pixel_type_w teNW = error[pos_NW];
162
5.95M
    pixel_type_w sumWN = teN + teW;
163
5.95M
    pixel_type_w teNE = error[pos_NE];
164
165
5.95M
    if (compute_properties) {
166
5.95M
      pixel_type_w p = teW;
167
5.95M
      if (std::abs(teN) > std::abs(p)) p = teN;
168
5.95M
      if (std::abs(teNW) > std::abs(p)) p = teNW;
169
5.95M
      if (std::abs(teNE) > std::abs(p)) p = teNE;
170
5.95M
      (*properties)[offset++] = p;
171
5.95M
    }
172
173
5.95M
    prediction[0] = W + NE - N;
174
5.95M
    prediction[1] = N - (((sumWN + teNE) * header.p1C) >> 5);
175
5.95M
    prediction[2] = W - (((sumWN + teNW) * header.p2C) >> 5);
176
5.95M
    prediction[3] =
177
5.95M
        N - ((teNW * header.p3Ca + teN * header.p3Cb + teNE * header.p3Cc +
178
5.95M
              (NN - N) * header.p3Cd + (NW - W) * header.p3Ce) >>
179
5.95M
             5);
180
181
5.95M
    pred = WeightedAverage(prediction, weights);
182
183
    // If all three have the same sign, skip clamping.
184
5.95M
    if (((teN ^ teW) | (teN ^ teNW)) > 0) {
185
2.02M
      return (pred + kPredictionRound) >> kPredExtraBits;
186
2.02M
    }
187
188
    // Otherwise, clamp to min/max of neighbouring pixels (just W, NE, N).
189
3.93M
    pixel_type_w mx = std::max(W, std::max(NE, N));
190
3.93M
    pixel_type_w mn = std::min(W, std::min(NE, N));
191
3.93M
    pred = std::max(mn, std::min(mx, pred));
192
3.93M
    return (pred + kPredictionRound) >> kPredExtraBits;
193
5.95M
  }
194
195
  JXL_INLINE void UpdateErrors(pixel_type_w val, size_t x, size_t y,
196
17.2M
                               size_t xsize) {
197
17.2M
    size_t cur_row = y & 1 ? 0 : (xsize + 2);
198
17.2M
    size_t prev_row = y & 1 ? (xsize + 2) : 0;
199
17.2M
    val = AddBits(val);
200
17.2M
    error[cur_row + x] = pred - val;
201
86.0M
    for (size_t i = 0; i < kNumPredictors; i++) {
202
68.8M
      pixel_type_w err =
203
68.8M
          (std::abs(prediction[i] - val) + kPredictionRound) >> kPredExtraBits;
204
      // For predicting in the next row.
205
68.8M
      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
68.8M
      pred_errors[i][prev_row + x + 1] += err;
209
68.8M
    }
210
17.2M
  }
211
};
212
213
// Encoder helper function to set the parameters to some presets.
214
162
inline void PredictorMode(int i, Header *header) {
215
162
  switch (i) {
216
162
    case 0:
217
      // ~ lossless16 predictor
218
162
      header->w[0] = 0xd;
219
162
      header->w[1] = 0xc;
220
162
      header->w[2] = 0xc;
221
162
      header->w[3] = 0xc;
222
162
      header->p1C = 16;
223
162
      header->p2C = 10;
224
162
      header->p3Ca = 7;
225
162
      header->p3Cb = 7;
226
162
      header->p3Cc = 7;
227
162
      header->p3Cd = 0;
228
162
      header->p3Ce = 0;
229
162
      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
162
  }
288
162
}
289
}  // namespace weighted
290
291
// Stores a node and its two children at the same time. This significantly
292
// reduces the number of branches needed during decoding.
293
struct FlatDecisionNode {
294
  // Property + splitval of the top node.
295
  int32_t property0;  // -1 if leaf.
296
  union {
297
    PropertyVal splitval0;
298
    Predictor predictor;
299
  };
300
  // Property+splitval of the two child nodes.
301
  union {
302
    PropertyVal splitvals[2];
303
    int32_t multiplier;
304
  };
305
  uint32_t childID;  // childID is ctx id if leaf.
306
  union {
307
    int16_t properties[2];
308
    int32_t predictor_offset;
309
  };
310
};
311
using FlatTree = std::vector<FlatDecisionNode>;
312
313
class MATreeLookup {
314
 public:
315
6.84k
  explicit MATreeLookup(const FlatTree &tree) : nodes_(tree) {}
316
  struct LookupResult {
317
    uint32_t context;
318
    Predictor predictor;
319
    int32_t offset;
320
    int32_t multiplier;
321
  };
322
14.3M
  JXL_INLINE LookupResult Lookup(const Properties &properties) const {
323
14.3M
    uint32_t pos = 0;
324
16.7M
    while (true) {
325
16.7M
#define TRAVERSE_THE_TREE                                                \
326
21.0M
  {                                                                      \
327
21.0M
    const FlatDecisionNode &node = nodes_[pos];                          \
328
21.0M
    if (node.property0 < 0) {                                            \
329
14.3M
      return {node.childID, node.predictor, node.predictor_offset,       \
330
14.3M
              node.multiplier};                                          \
331
14.3M
    }                                                                    \
332
21.0M
    bool p0 = properties[node.property0] <= node.splitval0;              \
333
6.65M
    uint32_t off0 = properties[node.properties[0]] <= node.splitvals[0]; \
334
6.65M
    uint32_t off1 =                                                      \
335
6.65M
        2 | int{properties[node.properties[1]] <= node.splitvals[1]};    \
336
6.65M
    pos = node.childID + (p0 ? off1 : off0);                             \
337
6.65M
  }
338
339
16.7M
      TRAVERSE_THE_TREE;
340
4.24M
      TRAVERSE_THE_TREE;
341
2.40M
    }
342
14.3M
  }
343
344
 private:
345
  const FlatTree &nodes_;
346
};
347
348
static constexpr size_t kExtraPropsPerChannel = 4;
349
static constexpr size_t kNumNonrefProperties =
350
    kNumStaticProperties + 13 + weighted::kNumProperties;
351
352
constexpr size_t kWPProp = kNumNonrefProperties - weighted::kNumProperties;
353
constexpr size_t kGradientProp = 9;
354
355
// Clamps gradient to the min/max of n, w (and l, implicitly).
356
static JXL_INLINE int32_t ClampedGradient(const int32_t n, const int32_t w,
357
3.38M
                                          const int32_t l) {
358
3.38M
  const int32_t m = std::min(n, w);
359
3.38M
  const int32_t M = std::max(n, w);
360
  // The end result of this operation doesn't overflow or underflow if the
361
  // result is between m and M, but the intermediate value may overflow, so we
362
  // do the intermediate operations in uint32_t and check later if we had an
363
  // overflow or underflow condition comparing m, M and l directly.
364
  // grad = M + m - l = n + w - l
365
3.38M
  const int32_t grad =
366
3.38M
      static_cast<int32_t>(static_cast<uint32_t>(n) + static_cast<uint32_t>(w) -
367
3.38M
                           static_cast<uint32_t>(l));
368
  // We use two sets of ternary operators to force the evaluation of them in
369
  // any case, allowing the compiler to avoid branches and use cmovl/cmovg in
370
  // x86.
371
3.38M
  const int32_t grad_clamp_M = (l < m) ? M : grad;
372
3.38M
  return (l > M) ? m : grad_clamp_M;
373
3.38M
}
Unexecuted instantiation: enc_frame.cc:jxl::ClampedGradient(int, int, int)
enc_modular.cc:jxl::ClampedGradient(int, int, int)
Line
Count
Source
357
12.7k
                                          const int32_t l) {
358
12.7k
  const int32_t m = std::min(n, w);
359
12.7k
  const int32_t M = std::max(n, w);
360
  // The end result of this operation doesn't overflow or underflow if the
361
  // result is between m and M, but the intermediate value may overflow, so we
362
  // do the intermediate operations in uint32_t and check later if we had an
363
  // overflow or underflow condition comparing m, M and l directly.
364
  // grad = M + m - l = n + w - l
365
12.7k
  const int32_t grad =
366
12.7k
      static_cast<int32_t>(static_cast<uint32_t>(n) + static_cast<uint32_t>(w) -
367
12.7k
                           static_cast<uint32_t>(l));
368
  // We use two sets of ternary operators to force the evaluation of them in
369
  // any case, allowing the compiler to avoid branches and use cmovl/cmovg in
370
  // x86.
371
12.7k
  const int32_t grad_clamp_M = (l < m) ? M : grad;
372
12.7k
  return (l > M) ? m : grad_clamp_M;
373
12.7k
}
Unexecuted instantiation: enc_patch_dictionary.cc:jxl::ClampedGradient(int, int, int)
Unexecuted instantiation: enc_quant_weights.cc:jxl::ClampedGradient(int, int, int)
Unexecuted instantiation: enc_heuristics.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)
enc_encoding.cc:jxl::ClampedGradient(int, int, int)
Line
Count
Source
357
2.36M
                                          const int32_t l) {
358
2.36M
  const int32_t m = std::min(n, w);
359
2.36M
  const int32_t M = std::max(n, w);
360
  // The end result of this operation doesn't overflow or underflow if the
361
  // result is between m and M, but the intermediate value may overflow, so we
362
  // do the intermediate operations in uint32_t and check later if we had an
363
  // overflow or underflow condition comparing m, M and l directly.
364
  // grad = M + m - l = n + w - l
365
2.36M
  const int32_t grad =
366
2.36M
      static_cast<int32_t>(static_cast<uint32_t>(n) + static_cast<uint32_t>(w) -
367
2.36M
                           static_cast<uint32_t>(l));
368
  // We use two sets of ternary operators to force the evaluation of them in
369
  // any case, allowing the compiler to avoid branches and use cmovl/cmovg in
370
  // x86.
371
2.36M
  const int32_t grad_clamp_M = (l < m) ? M : grad;
372
2.36M
  return (l > M) ? m : grad_clamp_M;
373
2.36M
}
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: enc_palette.cc:jxl::ClampedGradient(int, int, int)
Unexecuted instantiation: coeff_order.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: decode.cc:jxl::ClampedGradient(int, int, int)
encoding.cc:jxl::ClampedGradient(int, int, int)
Line
Count
Source
357
999k
                                          const int32_t l) {
358
999k
  const int32_t m = std::min(n, w);
359
999k
  const int32_t M = std::max(n, w);
360
  // The end result of this operation doesn't overflow or underflow if the
361
  // result is between m and M, but the intermediate value may overflow, so we
362
  // do the intermediate operations in uint32_t and check later if we had an
363
  // overflow or underflow condition comparing m, M and l directly.
364
  // grad = M + m - l = n + w - l
365
999k
  const int32_t grad =
366
999k
      static_cast<int32_t>(static_cast<uint32_t>(n) + static_cast<uint32_t>(w) -
367
999k
                           static_cast<uint32_t>(l));
368
  // We use two sets of ternary operators to force the evaluation of them in
369
  // any case, allowing the compiler to avoid branches and use cmovl/cmovg in
370
  // x86.
371
999k
  const int32_t grad_clamp_M = (l < m) ? M : grad;
372
999k
  return (l > M) ? m : grad_clamp_M;
373
999k
}
Unexecuted instantiation: modular_image.cc:jxl::ClampedGradient(int, int, int)
Unexecuted instantiation: transform.cc:jxl::ClampedGradient(int, int, int)
Unexecuted instantiation: rct.cc:jxl::ClampedGradient(int, int, int)
Unexecuted instantiation: palette.cc:jxl::ClampedGradient(int, int, int)
Unexecuted instantiation: quant_weights.cc:jxl::ClampedGradient(int, int, int)
374
375
46.3k
inline pixel_type_w Select(pixel_type_w a, pixel_type_w b, pixel_type_w c) {
376
46.3k
  pixel_type_w p = a + b - c;
377
46.3k
  pixel_type_w pa = std::abs(p - a);
378
46.3k
  pixel_type_w pb = std::abs(p - b);
379
46.3k
  return pa < pb ? a : b;
380
46.3k
}
381
382
inline void PrecomputeReferences(const Channel &ch, size_t y,
383
                                 const Image &image, uint32_t i,
384
186k
                                 Channel *references) {
385
186k
  ZeroFillImage(&references->plane);
386
186k
  uint32_t offset = 0;
387
186k
  size_t num_extra_props = references->w;
388
186k
  intptr_t onerow = references->plane.PixelsPerRow();
389
186k
  for (int32_t j = static_cast<int32_t>(i) - 1;
390
187k
       j >= 0 && offset < num_extra_props; j--) {
391
1.04k
    if (image.channel[j].w != image.channel[i].w ||
392
1.04k
        image.channel[j].h != image.channel[i].h) {
393
666
      continue;
394
666
    }
395
377
    if (image.channel[j].hshift != image.channel[i].hshift) continue;
396
369
    if (image.channel[j].vshift != image.channel[i].vshift) continue;
397
321
    pixel_type *JXL_RESTRICT rp = references->Row(0) + offset;
398
321
    const pixel_type *JXL_RESTRICT rpp = image.channel[j].Row(y);
399
321
    const pixel_type *JXL_RESTRICT rpprev = image.channel[j].Row(y ? y - 1 : 0);
400
6.75k
    for (size_t x = 0; x < ch.w; x++, rp += onerow) {
401
6.43k
      pixel_type_w v = rpp[x];
402
6.43k
      rp[0] = std::abs(v);
403
6.43k
      rp[1] = v;
404
6.43k
      pixel_type_w vleft = (x ? rpp[x - 1] : 0);
405
6.43k
      pixel_type_w vtop = (y ? rpprev[x] : vleft);
406
6.43k
      pixel_type_w vtopleft = (x && y ? rpprev[x - 1] : vleft);
407
6.43k
      pixel_type_w vpredicted = ClampedGradient(vleft, vtop, vtopleft);
408
6.43k
      rp[2] = std::abs(v - vpredicted);
409
6.43k
      rp[3] = v - vpredicted;
410
6.43k
    }
411
412
321
    offset += kExtraPropsPerChannel;
413
321
  }
414
186k
}
415
416
struct PredictionResult {
417
  int context = 0;
418
  pixel_type_w guess = 0;
419
  Predictor predictor;
420
  int32_t multiplier;
421
};
422
423
inline void InitPropsRow(
424
    Properties *p,
425
    const std::array<pixel_type, kNumStaticProperties> &static_props,
426
186k
    const int y) {
427
558k
  for (size_t i = 0; i < kNumStaticProperties; i++) {
428
372k
    (*p)[i] = static_props[i];
429
372k
  }
430
186k
  (*p)[2] = y;
431
186k
  (*p)[9] = 0;  // local gradient.
432
186k
}
433
434
namespace detail {
435
enum PredictorMode {
436
  kUseTree = 1,
437
  kUseWP = 2,
438
  kForceComputeProperties = 4,
439
  kAllPredictions = 8,
440
  kNoEdgeCases = 16
441
};
442
443
JXL_INLINE pixel_type_w PredictOne(Predictor p, pixel_type_w left,
444
                                   pixel_type_w top, pixel_type_w toptop,
445
                                   pixel_type_w topleft, pixel_type_w topright,
446
                                   pixel_type_w leftleft,
447
                                   pixel_type_w toprightright,
448
35.7M
                                   pixel_type_w wp_pred) {
449
35.7M
  switch (p) {
450
18.6M
    case Predictor::Zero:
451
18.6M
      return pixel_type_w{0};
452
7.38M
    case Predictor::Left:
453
7.38M
      return left;
454
1.71M
    case Predictor::Top:
455
1.71M
      return top;
456
46.3k
    case Predictor::Select:
457
46.3k
      return Select(left, top, topleft);
458
3.54M
    case Predictor::Weighted:
459
3.54M
      return wp_pred;
460
3.17M
    case Predictor::Gradient:
461
3.17M
      return pixel_type_w{ClampedGradient(left, top, topleft)};
462
792k
    case Predictor::TopLeft:
463
792k
      return topleft;
464
51.3k
    case Predictor::TopRight:
465
51.3k
      return topright;
466
5.82k
    case Predictor::LeftLeft:
467
5.82k
      return leftleft;
468
310k
    case Predictor::Average0:
469
310k
      return (left + top) / 2;
470
49.2k
    case Predictor::Average1:
471
49.2k
      return (left + topleft) / 2;
472
192
    case Predictor::Average2:
473
192
      return (topleft + top) / 2;
474
3.15k
    case Predictor::Average3:
475
3.15k
      return (top + topright) / 2;
476
71
    case Predictor::Average4:
477
71
      return (6 * top - 2 * toptop + 7 * left + 1 * leftleft +
478
71
              1 * toprightright + 3 * topright + 8) /
479
71
             16;
480
0
    default:
481
0
      return pixel_type_w{0};
482
35.7M
  }
483
35.7M
}
484
485
template <int mode>
486
JXL_INLINE PredictionResult Predict(
487
    Properties *p, size_t w, const pixel_type *JXL_RESTRICT pp,
488
    const intptr_t onerow, const size_t x, const size_t y, Predictor predictor,
489
    const MATreeLookup *lookup, const Channel *references,
490
35.7M
    weighted::State *wp_state, pixel_type_w *predictions) {
491
  // We start in position 3 because of 2 static properties + y.
492
35.7M
  size_t offset = 3;
493
35.7M
  constexpr bool compute_properties =
494
35.7M
      mode & kUseTree || mode & kForceComputeProperties;
495
35.7M
  constexpr bool nec = mode & kNoEdgeCases;
496
35.7M
  pixel_type_w left = (nec || x ? pp[-1] : (y ? pp[-onerow] : 0));
497
35.7M
  pixel_type_w top = (nec || y ? pp[-onerow] : left);
498
35.7M
  pixel_type_w topleft = (nec || (x && y) ? pp[-1 - onerow] : left);
499
35.7M
  pixel_type_w topright = (nec || (x + 1 < w && y) ? pp[1 - onerow] : top);
500
35.7M
  pixel_type_w leftleft = (nec || x > 1 ? pp[-2] : left);
501
35.7M
  pixel_type_w toptop = (nec || y > 1 ? pp[-onerow - onerow] : top);
502
35.7M
  pixel_type_w toprightright =
503
35.7M
      (nec || (x + 2 < w && y) ? pp[2 - onerow] : topright);
504
505
35.7M
  if (compute_properties) {
506
    // location
507
15.5M
    (*p)[offset++] = x;
508
    // neighbors
509
15.5M
    (*p)[offset++] = top > 0 ? top : -top;
510
15.5M
    (*p)[offset++] = left > 0 ? left : -left;
511
15.5M
    (*p)[offset++] = top;
512
15.5M
    (*p)[offset++] = left;
513
514
    // local gradient
515
15.5M
    (*p)[offset] = left - (*p)[offset + 1];
516
15.5M
    offset++;
517
    // local gradient
518
15.5M
    (*p)[offset++] = left + top - topleft;
519
520
    // FFV1 context properties
521
15.5M
    (*p)[offset++] = left - topleft;
522
15.5M
    (*p)[offset++] = topleft - top;
523
15.5M
    (*p)[offset++] = top - topright;
524
15.5M
    (*p)[offset++] = top - toptop;
525
15.5M
    (*p)[offset++] = left - leftleft;
526
15.5M
  }
527
528
35.7M
  pixel_type_w wp_pred = 0;
529
35.7M
  if (mode & kUseWP) {
530
6.43M
    wp_pred = wp_state->Predict<compute_properties>(
531
6.43M
        x, y, w, top, left, topright, topleft, toptop, p, offset);
532
6.43M
  }
533
35.7M
  if (!nec && compute_properties) {
534
2.71M
    offset += weighted::kNumProperties;
535
    // Extra properties.
536
2.71M
    const pixel_type *JXL_RESTRICT rp = references->Row(x);
537
3.19M
    for (size_t i = 0; i < references->w; i++) {
538
476k
      (*p)[offset++] = rp[i];
539
476k
    }
540
2.71M
  }
541
35.7M
  PredictionResult result;
542
35.7M
  if (mode & kUseTree) {
543
14.3M
    MATreeLookup::LookupResult lr = lookup->Lookup(*p);
544
14.3M
    result.context = lr.context;
545
14.3M
    result.guess = lr.offset;
546
14.3M
    result.multiplier = lr.multiplier;
547
14.3M
    predictor = lr.predictor;
548
14.3M
  }
549
35.7M
  if (mode & kAllPredictions) {
550
0
    for (size_t i = 0; i < kNumModularPredictors; i++) {
551
0
      predictions[i] =
552
0
          PredictOne(static_cast<Predictor>(i), left, top, toptop, topleft,
553
0
                     topright, leftleft, toprightright, wp_pred);
554
0
    }
555
0
  }
556
35.7M
  result.guess += PredictOne(predictor, left, top, toptop, topleft, topright,
557
35.7M
                             leftleft, toprightright, wp_pred);
558
35.7M
  result.predictor = predictor;
559
560
35.7M
  return result;
561
35.7M
}
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
490
18.5M
    weighted::State *wp_state, pixel_type_w *predictions) {
491
  // We start in position 3 because of 2 static properties + y.
492
18.5M
  size_t offset = 3;
493
18.5M
  constexpr bool compute_properties =
494
18.5M
      mode & kUseTree || mode & kForceComputeProperties;
495
18.5M
  constexpr bool nec = mode & kNoEdgeCases;
496
18.5M
  pixel_type_w left = (nec || x ? pp[-1] : (y ? pp[-onerow] : 0));
497
18.5M
  pixel_type_w top = (nec || y ? pp[-onerow] : left);
498
18.5M
  pixel_type_w topleft = (nec || (x && y) ? pp[-1 - onerow] : left);
499
18.5M
  pixel_type_w topright = (nec || (x + 1 < w && y) ? pp[1 - onerow] : top);
500
18.5M
  pixel_type_w leftleft = (nec || x > 1 ? pp[-2] : left);
501
18.5M
  pixel_type_w toptop = (nec || y > 1 ? pp[-onerow - onerow] : top);
502
18.5M
  pixel_type_w toprightright =
503
18.5M
      (nec || (x + 2 < w && y) ? pp[2 - onerow] : topright);
504
505
18.5M
  if (compute_properties) {
506
    // location
507
0
    (*p)[offset++] = x;
508
    // neighbors
509
0
    (*p)[offset++] = top > 0 ? top : -top;
510
0
    (*p)[offset++] = left > 0 ? left : -left;
511
0
    (*p)[offset++] = top;
512
0
    (*p)[offset++] = left;
513
514
    // local gradient
515
0
    (*p)[offset] = left - (*p)[offset + 1];
516
0
    offset++;
517
    // local gradient
518
0
    (*p)[offset++] = left + top - topleft;
519
520
    // FFV1 context properties
521
0
    (*p)[offset++] = left - topleft;
522
0
    (*p)[offset++] = topleft - top;
523
0
    (*p)[offset++] = top - topright;
524
0
    (*p)[offset++] = top - toptop;
525
0
    (*p)[offset++] = left - leftleft;
526
0
  }
527
528
18.5M
  pixel_type_w wp_pred = 0;
529
18.5M
  if (mode & kUseWP) {
530
0
    wp_pred = wp_state->Predict<compute_properties>(
531
0
        x, y, w, top, left, topright, topleft, toptop, p, offset);
532
0
  }
533
18.5M
  if (!nec && compute_properties) {
534
0
    offset += weighted::kNumProperties;
535
    // Extra properties.
536
0
    const pixel_type *JXL_RESTRICT rp = references->Row(x);
537
0
    for (size_t i = 0; i < references->w; i++) {
538
0
      (*p)[offset++] = rp[i];
539
0
    }
540
0
  }
541
18.5M
  PredictionResult result;
542
18.5M
  if (mode & kUseTree) {
543
0
    MATreeLookup::LookupResult lr = lookup->Lookup(*p);
544
0
    result.context = lr.context;
545
0
    result.guess = lr.offset;
546
0
    result.multiplier = lr.multiplier;
547
0
    predictor = lr.predictor;
548
0
  }
549
18.5M
  if (mode & kAllPredictions) {
550
0
    for (size_t i = 0; i < kNumModularPredictors; i++) {
551
0
      predictions[i] =
552
0
          PredictOne(static_cast<Predictor>(i), left, top, toptop, topleft,
553
0
                     topright, leftleft, toprightright, wp_pred);
554
0
    }
555
0
  }
556
18.5M
  result.guess += PredictOne(predictor, left, top, toptop, topleft, topright,
557
18.5M
                             leftleft, toprightright, wp_pred);
558
18.5M
  result.predictor = predictor;
559
560
18.5M
  return result;
561
18.5M
}
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
490
1.60M
    weighted::State *wp_state, pixel_type_w *predictions) {
491
  // We start in position 3 because of 2 static properties + y.
492
1.60M
  size_t offset = 3;
493
1.60M
  constexpr bool compute_properties =
494
1.60M
      mode & kUseTree || mode & kForceComputeProperties;
495
1.60M
  constexpr bool nec = mode & kNoEdgeCases;
496
1.60M
  pixel_type_w left = (nec || x ? pp[-1] : (y ? pp[-onerow] : 0));
497
1.60M
  pixel_type_w top = (nec || y ? pp[-onerow] : left);
498
1.60M
  pixel_type_w topleft = (nec || (x && y) ? pp[-1 - onerow] : left);
499
1.60M
  pixel_type_w topright = (nec || (x + 1 < w && y) ? pp[1 - onerow] : top);
500
1.60M
  pixel_type_w leftleft = (nec || x > 1 ? pp[-2] : left);
501
1.60M
  pixel_type_w toptop = (nec || y > 1 ? pp[-onerow - onerow] : top);
502
1.60M
  pixel_type_w toprightright =
503
1.60M
      (nec || (x + 2 < w && y) ? pp[2 - onerow] : topright);
504
505
1.60M
  if (compute_properties) {
506
    // location
507
0
    (*p)[offset++] = x;
508
    // neighbors
509
0
    (*p)[offset++] = top > 0 ? top : -top;
510
0
    (*p)[offset++] = left > 0 ? left : -left;
511
0
    (*p)[offset++] = top;
512
0
    (*p)[offset++] = left;
513
514
    // local gradient
515
0
    (*p)[offset] = left - (*p)[offset + 1];
516
0
    offset++;
517
    // local gradient
518
0
    (*p)[offset++] = left + top - topleft;
519
520
    // FFV1 context properties
521
0
    (*p)[offset++] = left - topleft;
522
0
    (*p)[offset++] = topleft - top;
523
0
    (*p)[offset++] = top - topright;
524
0
    (*p)[offset++] = top - toptop;
525
0
    (*p)[offset++] = left - leftleft;
526
0
  }
527
528
1.60M
  pixel_type_w wp_pred = 0;
529
1.60M
  if (mode & kUseWP) {
530
1.60M
    wp_pred = wp_state->Predict<compute_properties>(
531
1.60M
        x, y, w, top, left, topright, topleft, toptop, p, offset);
532
1.60M
  }
533
1.60M
  if (!nec && compute_properties) {
534
0
    offset += weighted::kNumProperties;
535
    // Extra properties.
536
0
    const pixel_type *JXL_RESTRICT rp = references->Row(x);
537
0
    for (size_t i = 0; i < references->w; i++) {
538
0
      (*p)[offset++] = rp[i];
539
0
    }
540
0
  }
541
1.60M
  PredictionResult result;
542
1.60M
  if (mode & kUseTree) {
543
0
    MATreeLookup::LookupResult lr = lookup->Lookup(*p);
544
0
    result.context = lr.context;
545
0
    result.guess = lr.offset;
546
0
    result.multiplier = lr.multiplier;
547
0
    predictor = lr.predictor;
548
0
  }
549
1.60M
  if (mode & kAllPredictions) {
550
0
    for (size_t i = 0; i < kNumModularPredictors; i++) {
551
0
      predictions[i] =
552
0
          PredictOne(static_cast<Predictor>(i), left, top, toptop, topleft,
553
0
                     topright, leftleft, toprightright, wp_pred);
554
0
    }
555
0
  }
556
1.60M
  result.guess += PredictOne(predictor, left, top, toptop, topleft, topright,
557
1.60M
                             leftleft, toprightright, wp_pred);
558
1.60M
  result.predictor = predictor;
559
560
1.60M
  return result;
561
1.60M
}
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
490
1.54M
    weighted::State *wp_state, pixel_type_w *predictions) {
491
  // We start in position 3 because of 2 static properties + y.
492
1.54M
  size_t offset = 3;
493
1.54M
  constexpr bool compute_properties =
494
1.54M
      mode & kUseTree || mode & kForceComputeProperties;
495
1.54M
  constexpr bool nec = mode & kNoEdgeCases;
496
1.54M
  pixel_type_w left = (nec || x ? pp[-1] : (y ? pp[-onerow] : 0));
497
1.54M
  pixel_type_w top = (nec || y ? pp[-onerow] : left);
498
1.54M
  pixel_type_w topleft = (nec || (x && y) ? pp[-1 - onerow] : left);
499
1.54M
  pixel_type_w topright = (nec || (x + 1 < w && y) ? pp[1 - onerow] : top);
500
1.54M
  pixel_type_w leftleft = (nec || x > 1 ? pp[-2] : left);
501
1.54M
  pixel_type_w toptop = (nec || y > 1 ? pp[-onerow - onerow] : top);
502
1.54M
  pixel_type_w toprightright =
503
1.54M
      (nec || (x + 2 < w && y) ? pp[2 - onerow] : topright);
504
505
1.54M
  if (compute_properties) {
506
    // location
507
1.54M
    (*p)[offset++] = x;
508
    // neighbors
509
1.54M
    (*p)[offset++] = top > 0 ? top : -top;
510
1.54M
    (*p)[offset++] = left > 0 ? left : -left;
511
1.54M
    (*p)[offset++] = top;
512
1.54M
    (*p)[offset++] = left;
513
514
    // local gradient
515
1.54M
    (*p)[offset] = left - (*p)[offset + 1];
516
1.54M
    offset++;
517
    // local gradient
518
1.54M
    (*p)[offset++] = left + top - topleft;
519
520
    // FFV1 context properties
521
1.54M
    (*p)[offset++] = left - topleft;
522
1.54M
    (*p)[offset++] = topleft - top;
523
1.54M
    (*p)[offset++] = top - topright;
524
1.54M
    (*p)[offset++] = top - toptop;
525
1.54M
    (*p)[offset++] = left - leftleft;
526
1.54M
  }
527
528
1.54M
  pixel_type_w wp_pred = 0;
529
1.54M
  if (mode & kUseWP) {
530
0
    wp_pred = wp_state->Predict<compute_properties>(
531
0
        x, y, w, top, left, topright, topleft, toptop, p, offset);
532
0
  }
533
1.54M
  if (!nec && compute_properties) {
534
1.54M
    offset += weighted::kNumProperties;
535
    // Extra properties.
536
1.54M
    const pixel_type *JXL_RESTRICT rp = references->Row(x);
537
2.01M
    for (size_t i = 0; i < references->w; i++) {
538
476k
      (*p)[offset++] = rp[i];
539
476k
    }
540
1.54M
  }
541
1.54M
  PredictionResult result;
542
1.54M
  if (mode & kUseTree) {
543
1.54M
    MATreeLookup::LookupResult lr = lookup->Lookup(*p);
544
1.54M
    result.context = lr.context;
545
1.54M
    result.guess = lr.offset;
546
1.54M
    result.multiplier = lr.multiplier;
547
1.54M
    predictor = lr.predictor;
548
1.54M
  }
549
1.54M
  if (mode & kAllPredictions) {
550
0
    for (size_t i = 0; i < kNumModularPredictors; i++) {
551
0
      predictions[i] =
552
0
          PredictOne(static_cast<Predictor>(i), left, top, toptop, topleft,
553
0
                     topright, leftleft, toprightright, wp_pred);
554
0
    }
555
0
  }
556
1.54M
  result.guess += PredictOne(predictor, left, top, toptop, topleft, topright,
557
1.54M
                             leftleft, toprightright, wp_pred);
558
1.54M
  result.predictor = predictor;
559
560
1.54M
  return result;
561
1.54M
}
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
490
9.15M
    weighted::State *wp_state, pixel_type_w *predictions) {
491
  // We start in position 3 because of 2 static properties + y.
492
9.15M
  size_t offset = 3;
493
9.15M
  constexpr bool compute_properties =
494
9.15M
      mode & kUseTree || mode & kForceComputeProperties;
495
9.15M
  constexpr bool nec = mode & kNoEdgeCases;
496
9.15M
  pixel_type_w left = (nec || x ? pp[-1] : (y ? pp[-onerow] : 0));
497
9.15M
  pixel_type_w top = (nec || y ? pp[-onerow] : left);
498
9.15M
  pixel_type_w topleft = (nec || (x && y) ? pp[-1 - onerow] : left);
499
9.15M
  pixel_type_w topright = (nec || (x + 1 < w && y) ? pp[1 - onerow] : top);
500
9.15M
  pixel_type_w leftleft = (nec || x > 1 ? pp[-2] : left);
501
9.15M
  pixel_type_w toptop = (nec || y > 1 ? pp[-onerow - onerow] : top);
502
9.15M
  pixel_type_w toprightright =
503
9.15M
      (nec || (x + 2 < w && y) ? pp[2 - onerow] : topright);
504
505
9.15M
  if (compute_properties) {
506
    // location
507
9.15M
    (*p)[offset++] = x;
508
    // neighbors
509
9.15M
    (*p)[offset++] = top > 0 ? top : -top;
510
9.15M
    (*p)[offset++] = left > 0 ? left : -left;
511
9.15M
    (*p)[offset++] = top;
512
9.15M
    (*p)[offset++] = left;
513
514
    // local gradient
515
9.15M
    (*p)[offset] = left - (*p)[offset + 1];
516
9.15M
    offset++;
517
    // local gradient
518
9.15M
    (*p)[offset++] = left + top - topleft;
519
520
    // FFV1 context properties
521
9.15M
    (*p)[offset++] = left - topleft;
522
9.15M
    (*p)[offset++] = topleft - top;
523
9.15M
    (*p)[offset++] = top - topright;
524
9.15M
    (*p)[offset++] = top - toptop;
525
9.15M
    (*p)[offset++] = left - leftleft;
526
9.15M
  }
527
528
9.15M
  pixel_type_w wp_pred = 0;
529
9.15M
  if (mode & kUseWP) {
530
0
    wp_pred = wp_state->Predict<compute_properties>(
531
0
        x, y, w, top, left, topright, topleft, toptop, p, offset);
532
0
  }
533
9.15M
  if (!nec && compute_properties) {
534
0
    offset += weighted::kNumProperties;
535
    // Extra properties.
536
0
    const pixel_type *JXL_RESTRICT rp = references->Row(x);
537
0
    for (size_t i = 0; i < references->w; i++) {
538
0
      (*p)[offset++] = rp[i];
539
0
    }
540
0
  }
541
9.15M
  PredictionResult result;
542
9.15M
  if (mode & kUseTree) {
543
9.15M
    MATreeLookup::LookupResult lr = lookup->Lookup(*p);
544
9.15M
    result.context = lr.context;
545
9.15M
    result.guess = lr.offset;
546
9.15M
    result.multiplier = lr.multiplier;
547
9.15M
    predictor = lr.predictor;
548
9.15M
  }
549
9.15M
  if (mode & kAllPredictions) {
550
0
    for (size_t i = 0; i < kNumModularPredictors; i++) {
551
0
      predictions[i] =
552
0
          PredictOne(static_cast<Predictor>(i), left, top, toptop, topleft,
553
0
                     topright, leftleft, toprightright, wp_pred);
554
0
    }
555
0
  }
556
9.15M
  result.guess += PredictOne(predictor, left, top, toptop, topleft, topright,
557
9.15M
                             leftleft, toprightright, wp_pred);
558
9.15M
  result.predictor = predictor;
559
560
9.15M
  return result;
561
9.15M
}
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
490
1.09M
    weighted::State *wp_state, pixel_type_w *predictions) {
491
  // We start in position 3 because of 2 static properties + y.
492
1.09M
  size_t offset = 3;
493
1.09M
  constexpr bool compute_properties =
494
1.09M
      mode & kUseTree || mode & kForceComputeProperties;
495
1.09M
  constexpr bool nec = mode & kNoEdgeCases;
496
1.09M
  pixel_type_w left = (nec || x ? pp[-1] : (y ? pp[-onerow] : 0));
497
1.09M
  pixel_type_w top = (nec || y ? pp[-onerow] : left);
498
1.09M
  pixel_type_w topleft = (nec || (x && y) ? pp[-1 - onerow] : left);
499
1.09M
  pixel_type_w topright = (nec || (x + 1 < w && y) ? pp[1 - onerow] : top);
500
1.09M
  pixel_type_w leftleft = (nec || x > 1 ? pp[-2] : left);
501
1.09M
  pixel_type_w toptop = (nec || y > 1 ? pp[-onerow - onerow] : top);
502
1.09M
  pixel_type_w toprightright =
503
1.09M
      (nec || (x + 2 < w && y) ? pp[2 - onerow] : topright);
504
505
1.09M
  if (compute_properties) {
506
    // location
507
1.09M
    (*p)[offset++] = x;
508
    // neighbors
509
1.09M
    (*p)[offset++] = top > 0 ? top : -top;
510
1.09M
    (*p)[offset++] = left > 0 ? left : -left;
511
1.09M
    (*p)[offset++] = top;
512
1.09M
    (*p)[offset++] = left;
513
514
    // local gradient
515
1.09M
    (*p)[offset] = left - (*p)[offset + 1];
516
1.09M
    offset++;
517
    // local gradient
518
1.09M
    (*p)[offset++] = left + top - topleft;
519
520
    // FFV1 context properties
521
1.09M
    (*p)[offset++] = left - topleft;
522
1.09M
    (*p)[offset++] = topleft - top;
523
1.09M
    (*p)[offset++] = top - topright;
524
1.09M
    (*p)[offset++] = top - toptop;
525
1.09M
    (*p)[offset++] = left - leftleft;
526
1.09M
  }
527
528
1.09M
  pixel_type_w wp_pred = 0;
529
1.09M
  if (mode & kUseWP) {
530
1.09M
    wp_pred = wp_state->Predict<compute_properties>(
531
1.09M
        x, y, w, top, left, topright, topleft, toptop, p, offset);
532
1.09M
  }
533
1.09M
  if (!nec && compute_properties) {
534
1.09M
    offset += weighted::kNumProperties;
535
    // Extra properties.
536
1.09M
    const pixel_type *JXL_RESTRICT rp = references->Row(x);
537
1.09M
    for (size_t i = 0; i < references->w; i++) {
538
0
      (*p)[offset++] = rp[i];
539
0
    }
540
1.09M
  }
541
1.09M
  PredictionResult result;
542
1.09M
  if (mode & kUseTree) {
543
1.09M
    MATreeLookup::LookupResult lr = lookup->Lookup(*p);
544
1.09M
    result.context = lr.context;
545
1.09M
    result.guess = lr.offset;
546
1.09M
    result.multiplier = lr.multiplier;
547
1.09M
    predictor = lr.predictor;
548
1.09M
  }
549
1.09M
  if (mode & kAllPredictions) {
550
0
    for (size_t i = 0; i < kNumModularPredictors; i++) {
551
0
      predictions[i] =
552
0
          PredictOne(static_cast<Predictor>(i), left, top, toptop, topleft,
553
0
                     topright, leftleft, toprightright, wp_pred);
554
0
    }
555
0
  }
556
1.09M
  result.guess += PredictOne(predictor, left, top, toptop, topleft, topright,
557
1.09M
                             leftleft, toprightright, wp_pred);
558
1.09M
  result.predictor = predictor;
559
560
1.09M
  return result;
561
1.09M
}
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
490
2.58M
    weighted::State *wp_state, pixel_type_w *predictions) {
491
  // We start in position 3 because of 2 static properties + y.
492
2.58M
  size_t offset = 3;
493
2.58M
  constexpr bool compute_properties =
494
2.58M
      mode & kUseTree || mode & kForceComputeProperties;
495
2.58M
  constexpr bool nec = mode & kNoEdgeCases;
496
2.58M
  pixel_type_w left = (nec || x ? pp[-1] : (y ? pp[-onerow] : 0));
497
2.58M
  pixel_type_w top = (nec || y ? pp[-onerow] : left);
498
2.58M
  pixel_type_w topleft = (nec || (x && y) ? pp[-1 - onerow] : left);
499
2.58M
  pixel_type_w topright = (nec || (x + 1 < w && y) ? pp[1 - onerow] : top);
500
2.58M
  pixel_type_w leftleft = (nec || x > 1 ? pp[-2] : left);
501
2.58M
  pixel_type_w toptop = (nec || y > 1 ? pp[-onerow - onerow] : top);
502
2.58M
  pixel_type_w toprightright =
503
2.58M
      (nec || (x + 2 < w && y) ? pp[2 - onerow] : topright);
504
505
2.58M
  if (compute_properties) {
506
    // location
507
2.58M
    (*p)[offset++] = x;
508
    // neighbors
509
2.58M
    (*p)[offset++] = top > 0 ? top : -top;
510
2.58M
    (*p)[offset++] = left > 0 ? left : -left;
511
2.58M
    (*p)[offset++] = top;
512
2.58M
    (*p)[offset++] = left;
513
514
    // local gradient
515
2.58M
    (*p)[offset] = left - (*p)[offset + 1];
516
2.58M
    offset++;
517
    // local gradient
518
2.58M
    (*p)[offset++] = left + top - topleft;
519
520
    // FFV1 context properties
521
2.58M
    (*p)[offset++] = left - topleft;
522
2.58M
    (*p)[offset++] = topleft - top;
523
2.58M
    (*p)[offset++] = top - topright;
524
2.58M
    (*p)[offset++] = top - toptop;
525
2.58M
    (*p)[offset++] = left - leftleft;
526
2.58M
  }
527
528
2.58M
  pixel_type_w wp_pred = 0;
529
2.58M
  if (mode & kUseWP) {
530
2.58M
    wp_pred = wp_state->Predict<compute_properties>(
531
2.58M
        x, y, w, top, left, topright, topleft, toptop, p, offset);
532
2.58M
  }
533
2.58M
  if (!nec && compute_properties) {
534
0
    offset += weighted::kNumProperties;
535
    // Extra properties.
536
0
    const pixel_type *JXL_RESTRICT rp = references->Row(x);
537
0
    for (size_t i = 0; i < references->w; i++) {
538
0
      (*p)[offset++] = rp[i];
539
0
    }
540
0
  }
541
2.58M
  PredictionResult result;
542
2.58M
  if (mode & kUseTree) {
543
2.58M
    MATreeLookup::LookupResult lr = lookup->Lookup(*p);
544
2.58M
    result.context = lr.context;
545
2.58M
    result.guess = lr.offset;
546
2.58M
    result.multiplier = lr.multiplier;
547
2.58M
    predictor = lr.predictor;
548
2.58M
  }
549
2.58M
  if (mode & kAllPredictions) {
550
0
    for (size_t i = 0; i < kNumModularPredictors; i++) {
551
0
      predictions[i] =
552
0
          PredictOne(static_cast<Predictor>(i), left, top, toptop, topleft,
553
0
                     topright, leftleft, toprightright, wp_pred);
554
0
    }
555
0
  }
556
2.58M
  result.guess += PredictOne(predictor, left, top, toptop, topleft, topright,
557
2.58M
                             leftleft, toprightright, wp_pred);
558
2.58M
  result.predictor = predictor;
559
560
2.58M
  return result;
561
2.58M
}
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
490
79.0k
    weighted::State *wp_state, pixel_type_w *predictions) {
491
  // We start in position 3 because of 2 static properties + y.
492
79.0k
  size_t offset = 3;
493
79.0k
  constexpr bool compute_properties =
494
79.0k
      mode & kUseTree || mode & kForceComputeProperties;
495
79.0k
  constexpr bool nec = mode & kNoEdgeCases;
496
79.0k
  pixel_type_w left = (nec || x ? pp[-1] : (y ? pp[-onerow] : 0));
497
79.0k
  pixel_type_w top = (nec || y ? pp[-onerow] : left);
498
79.0k
  pixel_type_w topleft = (nec || (x && y) ? pp[-1 - onerow] : left);
499
79.0k
  pixel_type_w topright = (nec || (x + 1 < w && y) ? pp[1 - onerow] : top);
500
79.0k
  pixel_type_w leftleft = (nec || x > 1 ? pp[-2] : left);
501
79.0k
  pixel_type_w toptop = (nec || y > 1 ? pp[-onerow - onerow] : top);
502
79.0k
  pixel_type_w toprightright =
503
79.0k
      (nec || (x + 2 < w && y) ? pp[2 - onerow] : topright);
504
505
79.0k
  if (compute_properties) {
506
    // location
507
79.0k
    (*p)[offset++] = x;
508
    // neighbors
509
79.0k
    (*p)[offset++] = top > 0 ? top : -top;
510
79.0k
    (*p)[offset++] = left > 0 ? left : -left;
511
79.0k
    (*p)[offset++] = top;
512
79.0k
    (*p)[offset++] = left;
513
514
    // local gradient
515
79.0k
    (*p)[offset] = left - (*p)[offset + 1];
516
79.0k
    offset++;
517
    // local gradient
518
79.0k
    (*p)[offset++] = left + top - topleft;
519
520
    // FFV1 context properties
521
79.0k
    (*p)[offset++] = left - topleft;
522
79.0k
    (*p)[offset++] = topleft - top;
523
79.0k
    (*p)[offset++] = top - topright;
524
79.0k
    (*p)[offset++] = top - toptop;
525
79.0k
    (*p)[offset++] = left - leftleft;
526
79.0k
  }
527
528
79.0k
  pixel_type_w wp_pred = 0;
529
79.0k
  if (mode & kUseWP) {
530
79.0k
    wp_pred = wp_state->Predict<compute_properties>(
531
79.0k
        x, y, w, top, left, topright, topleft, toptop, p, offset);
532
79.0k
  }
533
79.0k
  if (!nec && compute_properties) {
534
79.0k
    offset += weighted::kNumProperties;
535
    // Extra properties.
536
79.0k
    const pixel_type *JXL_RESTRICT rp = references->Row(x);
537
79.0k
    for (size_t i = 0; i < references->w; i++) {
538
0
      (*p)[offset++] = rp[i];
539
0
    }
540
79.0k
  }
541
79.0k
  PredictionResult result;
542
79.0k
  if (mode & kUseTree) {
543
0
    MATreeLookup::LookupResult lr = lookup->Lookup(*p);
544
0
    result.context = lr.context;
545
0
    result.guess = lr.offset;
546
0
    result.multiplier = lr.multiplier;
547
0
    predictor = lr.predictor;
548
0
  }
549
79.0k
  if (mode & kAllPredictions) {
550
0
    for (size_t i = 0; i < kNumModularPredictors; i++) {
551
0
      predictions[i] =
552
0
          PredictOne(static_cast<Predictor>(i), left, top, toptop, topleft,
553
0
                     topright, leftleft, toprightright, wp_pred);
554
0
    }
555
0
  }
556
79.0k
  result.guess += PredictOne(predictor, left, top, toptop, topleft, topright,
557
79.0k
                             leftleft, toprightright, wp_pred);
558
79.0k
  result.predictor = predictor;
559
560
79.0k
  return result;
561
79.0k
}
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
490
1.06M
    weighted::State *wp_state, pixel_type_w *predictions) {
491
  // We start in position 3 because of 2 static properties + y.
492
1.06M
  size_t offset = 3;
493
1.06M
  constexpr bool compute_properties =
494
1.06M
      mode & kUseTree || mode & kForceComputeProperties;
495
1.06M
  constexpr bool nec = mode & kNoEdgeCases;
496
1.06M
  pixel_type_w left = (nec || x ? pp[-1] : (y ? pp[-onerow] : 0));
497
1.06M
  pixel_type_w top = (nec || y ? pp[-onerow] : left);
498
1.06M
  pixel_type_w topleft = (nec || (x && y) ? pp[-1 - onerow] : left);
499
1.06M
  pixel_type_w topright = (nec || (x + 1 < w && y) ? pp[1 - onerow] : top);
500
1.06M
  pixel_type_w leftleft = (nec || x > 1 ? pp[-2] : left);
501
1.06M
  pixel_type_w toptop = (nec || y > 1 ? pp[-onerow - onerow] : top);
502
1.06M
  pixel_type_w toprightright =
503
1.06M
      (nec || (x + 2 < w && y) ? pp[2 - onerow] : topright);
504
505
1.06M
  if (compute_properties) {
506
    // location
507
1.06M
    (*p)[offset++] = x;
508
    // neighbors
509
1.06M
    (*p)[offset++] = top > 0 ? top : -top;
510
1.06M
    (*p)[offset++] = left > 0 ? left : -left;
511
1.06M
    (*p)[offset++] = top;
512
1.06M
    (*p)[offset++] = left;
513
514
    // local gradient
515
1.06M
    (*p)[offset] = left - (*p)[offset + 1];
516
1.06M
    offset++;
517
    // local gradient
518
1.06M
    (*p)[offset++] = left + top - topleft;
519
520
    // FFV1 context properties
521
1.06M
    (*p)[offset++] = left - topleft;
522
1.06M
    (*p)[offset++] = topleft - top;
523
1.06M
    (*p)[offset++] = top - topright;
524
1.06M
    (*p)[offset++] = top - toptop;
525
1.06M
    (*p)[offset++] = left - leftleft;
526
1.06M
  }
527
528
1.06M
  pixel_type_w wp_pred = 0;
529
1.06M
  if (mode & kUseWP) {
530
1.06M
    wp_pred = wp_state->Predict<compute_properties>(
531
1.06M
        x, y, w, top, left, topright, topleft, toptop, p, offset);
532
1.06M
  }
533
1.06M
  if (!nec && compute_properties) {
534
0
    offset += weighted::kNumProperties;
535
    // Extra properties.
536
0
    const pixel_type *JXL_RESTRICT rp = references->Row(x);
537
0
    for (size_t i = 0; i < references->w; i++) {
538
0
      (*p)[offset++] = rp[i];
539
0
    }
540
0
  }
541
1.06M
  PredictionResult result;
542
1.06M
  if (mode & kUseTree) {
543
0
    MATreeLookup::LookupResult lr = lookup->Lookup(*p);
544
0
    result.context = lr.context;
545
0
    result.guess = lr.offset;
546
0
    result.multiplier = lr.multiplier;
547
0
    predictor = lr.predictor;
548
0
  }
549
1.06M
  if (mode & kAllPredictions) {
550
0
    for (size_t i = 0; i < kNumModularPredictors; i++) {
551
0
      predictions[i] =
552
0
          PredictOne(static_cast<Predictor>(i), left, top, toptop, topleft,
553
0
                     topright, leftleft, toprightright, wp_pred);
554
0
    }
555
0
  }
556
1.06M
  result.guess += PredictOne(predictor, left, top, toptop, topleft, topright,
557
1.06M
                             leftleft, toprightright, wp_pred);
558
1.06M
  result.predictor = predictor;
559
560
1.06M
  return result;
561
1.06M
}
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*)
562
}  // namespace detail
563
564
inline PredictionResult PredictNoTreeNoWP(size_t w,
565
                                          const pixel_type *JXL_RESTRICT pp,
566
                                          const intptr_t onerow, const int x,
567
18.5M
                                          const int y, Predictor predictor) {
568
18.5M
  return detail::Predict</*mode=*/0>(
569
18.5M
      /*p=*/nullptr, w, pp, onerow, x, y, predictor, /*lookup=*/nullptr,
570
18.5M
      /*references=*/nullptr, /*wp_state=*/nullptr, /*predictions=*/nullptr);
571
18.5M
}
572
573
inline PredictionResult PredictNoTreeWP(size_t w,
574
                                        const pixel_type *JXL_RESTRICT pp,
575
                                        const intptr_t onerow, const int x,
576
                                        const int y, Predictor predictor,
577
1.60M
                                        weighted::State *wp_state) {
578
1.60M
  return detail::Predict<detail::kUseWP>(
579
1.60M
      /*p=*/nullptr, w, pp, onerow, x, y, predictor, /*lookup=*/nullptr,
580
1.60M
      /*references=*/nullptr, wp_state, /*predictions=*/nullptr);
581
1.60M
}
582
583
inline PredictionResult PredictTreeNoWP(Properties *p, size_t w,
584
                                        const pixel_type *JXL_RESTRICT pp,
585
                                        const intptr_t onerow, const int x,
586
                                        const int y,
587
                                        const MATreeLookup &tree_lookup,
588
1.54M
                                        const Channel &references) {
589
1.54M
  return detail::Predict<detail::kUseTree>(
590
1.54M
      p, w, pp, onerow, x, y, Predictor::Zero, &tree_lookup, &references,
591
1.54M
      /*wp_state=*/nullptr, /*predictions=*/nullptr);
592
1.54M
}
593
// Only use for y > 1, x > 1, x < w-2, and empty references
594
JXL_INLINE PredictionResult
595
PredictTreeNoWPNEC(Properties *p, size_t w, const pixel_type *JXL_RESTRICT pp,
596
                   const intptr_t onerow, const int x, const int y,
597
9.15M
                   const MATreeLookup &tree_lookup, const Channel &references) {
598
9.15M
  return detail::Predict<detail::kUseTree | detail::kNoEdgeCases>(
599
9.15M
      p, w, pp, onerow, x, y, Predictor::Zero, &tree_lookup, &references,
600
9.15M
      /*wp_state=*/nullptr, /*predictions=*/nullptr);
601
9.15M
}
602
603
inline PredictionResult PredictTreeWP(Properties *p, size_t w,
604
                                      const pixel_type *JXL_RESTRICT pp,
605
                                      const intptr_t onerow, const int x,
606
                                      const int y,
607
                                      const MATreeLookup &tree_lookup,
608
                                      const Channel &references,
609
1.09M
                                      weighted::State *wp_state) {
610
1.09M
  return detail::Predict<detail::kUseTree | detail::kUseWP>(
611
1.09M
      p, w, pp, onerow, x, y, Predictor::Zero, &tree_lookup, &references,
612
1.09M
      wp_state, /*predictions=*/nullptr);
613
1.09M
}
614
JXL_INLINE PredictionResult PredictTreeWPNEC(Properties *p, size_t w,
615
                                             const pixel_type *JXL_RESTRICT pp,
616
                                             const intptr_t onerow, const int x,
617
                                             const int y,
618
                                             const MATreeLookup &tree_lookup,
619
                                             const Channel &references,
620
2.58M
                                             weighted::State *wp_state) {
621
2.58M
  return detail::Predict<detail::kUseTree | detail::kUseWP |
622
2.58M
                         detail::kNoEdgeCases>(
623
2.58M
      p, w, pp, onerow, x, y, Predictor::Zero, &tree_lookup, &references,
624
2.58M
      wp_state, /*predictions=*/nullptr);
625
2.58M
}
626
627
inline PredictionResult PredictLearn(Properties *p, size_t w,
628
                                     const pixel_type *JXL_RESTRICT pp,
629
                                     const intptr_t onerow, const int x,
630
                                     const int y, Predictor predictor,
631
                                     const Channel &references,
632
79.0k
                                     weighted::State *wp_state) {
633
79.0k
  return detail::Predict<detail::kForceComputeProperties | detail::kUseWP>(
634
79.0k
      p, w, pp, onerow, x, y, predictor, /*lookup=*/nullptr, &references,
635
79.0k
      wp_state, /*predictions=*/nullptr);
636
79.0k
}
637
638
inline void PredictLearnAll(Properties *p, size_t w,
639
                            const pixel_type *JXL_RESTRICT pp,
640
                            const intptr_t onerow, const int x, const int y,
641
                            const Channel &references,
642
                            weighted::State *wp_state,
643
0
                            pixel_type_w *predictions) {
644
0
  detail::Predict<detail::kForceComputeProperties | detail::kUseWP |
645
0
                  detail::kAllPredictions>(
646
0
      p, w, pp, onerow, x, y, Predictor::Zero,
647
0
      /*lookup=*/nullptr, &references, wp_state, predictions);
648
0
}
649
inline PredictionResult PredictLearnNEC(Properties *p, size_t w,
650
                                        const pixel_type *JXL_RESTRICT pp,
651
                                        const intptr_t onerow, const int x,
652
                                        const int y, Predictor predictor,
653
                                        const Channel &references,
654
1.06M
                                        weighted::State *wp_state) {
655
1.06M
  return detail::Predict<detail::kForceComputeProperties | detail::kUseWP |
656
1.06M
                         detail::kNoEdgeCases>(
657
1.06M
      p, w, pp, onerow, x, y, predictor, /*lookup=*/nullptr, &references,
658
1.06M
      wp_state, /*predictions=*/nullptr);
659
1.06M
}
660
661
inline void PredictLearnAllNEC(Properties *p, size_t w,
662
                               const pixel_type *JXL_RESTRICT pp,
663
                               const intptr_t onerow, const int x, const int y,
664
                               const Channel &references,
665
                               weighted::State *wp_state,
666
0
                               pixel_type_w *predictions) {
667
0
  detail::Predict<detail::kForceComputeProperties | detail::kUseWP |
668
0
                  detail::kAllPredictions | detail::kNoEdgeCases>(
669
0
      p, w, pp, onerow, x, y, Predictor::Zero,
670
0
      /*lookup=*/nullptr, &references, wp_state, predictions);
671
0
}
672
673
inline void PredictAllNoWP(size_t w, const pixel_type *JXL_RESTRICT pp,
674
                           const intptr_t onerow, const int x, const int y,
675
0
                           pixel_type_w *predictions) {
676
0
  detail::Predict<detail::kAllPredictions>(
677
0
      /*p=*/nullptr, w, pp, onerow, x, y, Predictor::Zero,
678
0
      /*lookup=*/nullptr,
679
0
      /*references=*/nullptr, /*wp_state=*/nullptr, predictions);
680
0
}
681
}  // namespace jxl
682
683
#endif  // LIB_JXL_MODULAR_ENCODING_CONTEXT_PREDICT_H_