/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 | 86.0k | Header() { Bundle::Init(this); } |
37 | | |
38 | 137k | Status VisitFields(Visitor *JXL_RESTRICT visitor) override { |
39 | 137k | if (visitor->AllDefault(*this, &all_default)) { |
40 | | // Overwrite all serialized fields, but not any nonserialized_*. |
41 | 22.6k | visitor->SetDefault(this); |
42 | 22.6k | return true; |
43 | 22.6k | } |
44 | 803k | auto visit_p = [visitor](pixel_type val, pixel_type *p) -> Status { |
45 | 803k | uint32_t up = *p; |
46 | 803k | JXL_QUIET_RETURN_IF_ERROR(visitor->Bits(5, val, &up)); |
47 | 803k | *p = up; |
48 | 803k | return true; |
49 | 803k | }; |
50 | 114k | JXL_QUIET_RETURN_IF_ERROR(visit_p(16, &p1C)); |
51 | 114k | JXL_QUIET_RETURN_IF_ERROR(visit_p(10, &p2C)); |
52 | 114k | JXL_QUIET_RETURN_IF_ERROR(visit_p(7, &p3Ca)); |
53 | 114k | JXL_QUIET_RETURN_IF_ERROR(visit_p(7, &p3Cb)); |
54 | 114k | JXL_QUIET_RETURN_IF_ERROR(visit_p(7, &p3Cc)); |
55 | 114k | JXL_QUIET_RETURN_IF_ERROR(visit_p(0, &p3Cd)); |
56 | 114k | JXL_QUIET_RETURN_IF_ERROR(visit_p(0, &p3Ce)); |
57 | 114k | JXL_QUIET_RETURN_IF_ERROR(visitor->Bits(4, 0xd, &w[0])); |
58 | 114k | JXL_QUIET_RETURN_IF_ERROR(visitor->Bits(4, 0xc, &w[1])); |
59 | 114k | JXL_QUIET_RETURN_IF_ERROR(visitor->Bits(4, 0xc, &w[2])); |
60 | 114k | JXL_QUIET_RETURN_IF_ERROR(visitor->Bits(4, 0xc, &w[3])); |
61 | 114k | return true; |
62 | 114k | } |
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 | 97.1M | constexpr static pixel_type_w AddBits(pixel_type_w x) { |
90 | 97.1M | return static_cast<uint64_t>(x) << kPredExtraBits; |
91 | 97.1M | } |
92 | | |
93 | 8.51k | 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 | 34.0k | for (auto &pred_error : pred_errors) { |
97 | 34.0k | pred_error.resize((xsize + 2) * 2); |
98 | 34.0k | } |
99 | 8.51k | error.resize((xsize + 2) * 2); |
100 | 8.51k | } |
101 | | |
102 | | // Approximates 4+(maxweight<<24)/(x+1), avoiding division |
103 | 64.7M | JXL_INLINE uint32_t ErrorWeight(uint64_t x, uint32_t maxweight) const { |
104 | 64.7M | int shift = static_cast<int>(FloorLog2Nonzero(x + 1)) - 5; |
105 | 64.7M | if (shift < 0) shift = 0; |
106 | 64.7M | return 4 + ((maxweight * divlookup[x >> shift]) >> shift); |
107 | 64.7M | } |
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 | 16.1M | std::array<uint32_t, kNumPredictors> w) const { |
114 | 16.1M | uint32_t weight_sum = 0; |
115 | 80.9M | for (size_t i = 0; i < kNumPredictors; i++) { |
116 | 64.7M | weight_sum += w[i]; |
117 | 64.7M | } |
118 | 16.1M | JXL_DASSERT(weight_sum > 15); |
119 | 16.1M | uint32_t log_weight = FloorLog2Nonzero(weight_sum); // at least 4. |
120 | 16.1M | weight_sum = 0; |
121 | 80.9M | for (size_t i = 0; i < kNumPredictors; i++) { |
122 | 64.7M | w[i] >>= log_weight - 4; |
123 | 64.7M | weight_sum += w[i]; |
124 | 64.7M | } |
125 | | // for rounding. |
126 | 16.1M | pixel_type_w sum = (weight_sum >> 1) - 1; |
127 | 80.9M | for (size_t i = 0; i < kNumPredictors; i++) { |
128 | 64.7M | sum += p[i] * w[i]; |
129 | 64.7M | } |
130 | 16.1M | return (sum * divlookup[weight_sum - 1]) >> 24; |
131 | 16.1M | } |
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 | 16.1M | size_t offset) { |
139 | 16.1M | size_t cur_row = y & 1 ? 0 : (xsize + 2); |
140 | 16.1M | size_t prev_row = y & 1 ? (xsize + 2) : 0; |
141 | 16.1M | size_t pos_N = prev_row + x; |
142 | 16.1M | size_t pos_NE = x < xsize - 1 ? pos_N + 1 : pos_N; |
143 | 16.1M | size_t pos_NW = x > 0 ? pos_N - 1 : pos_N; |
144 | 16.1M | std::array<uint32_t, kNumPredictors> weights; |
145 | 80.9M | 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 | 64.7M | weights[i] = pred_errors[i][pos_N] + pred_errors[i][pos_NE] + |
149 | 64.7M | pred_errors[i][pos_NW]; |
150 | 64.7M | weights[i] = ErrorWeight(weights[i], header.w[i]); |
151 | 64.7M | } |
152 | | |
153 | 16.1M | N = AddBits(N); |
154 | 16.1M | W = AddBits(W); |
155 | 16.1M | NE = AddBits(NE); |
156 | 16.1M | NW = AddBits(NW); |
157 | 16.1M | NN = AddBits(NN); |
158 | | |
159 | 16.1M | pixel_type_w teW = x == 0 ? 0 : error[cur_row + x - 1]; |
160 | 16.1M | pixel_type_w teN = error[pos_N]; |
161 | 16.1M | pixel_type_w teNW = error[pos_NW]; |
162 | 16.1M | pixel_type_w sumWN = teN + teW; |
163 | 16.1M | pixel_type_w teNE = error[pos_NE]; |
164 | | |
165 | 16.1M | if (compute_properties) { |
166 | 14.9M | pixel_type_w p = teW; |
167 | 14.9M | if (std::abs(teN) > std::abs(p)) p = teN; |
168 | 14.9M | if (std::abs(teNW) > std::abs(p)) p = teNW; |
169 | 14.9M | if (std::abs(teNE) > std::abs(p)) p = teNE; |
170 | 14.9M | (*properties)[offset++] = p; |
171 | 14.9M | } |
172 | | |
173 | 16.1M | prediction[0] = W + NE - N; |
174 | 16.1M | prediction[1] = N - (((sumWN + teNE) * header.p1C) >> 5); |
175 | 16.1M | prediction[2] = W - (((sumWN + teNW) * header.p2C) >> 5); |
176 | 16.1M | prediction[3] = |
177 | 16.1M | N - ((teNW * header.p3Ca + teN * header.p3Cb + teNE * header.p3Cc + |
178 | 16.1M | (NN - N) * header.p3Cd + (NW - W) * header.p3Ce) >> |
179 | 16.1M | 5); |
180 | | |
181 | 16.1M | pred = WeightedAverage(prediction, weights); |
182 | | |
183 | | // If all three have the same sign, skip clamping. |
184 | 16.1M | if (((teN ^ teW) | (teN ^ teNW)) > 0) { |
185 | 7.26M | return (pred + kPredictionRound) >> kPredExtraBits; |
186 | 7.26M | } |
187 | | |
188 | | // Otherwise, clamp to min/max of neighbouring pixels (just W, NE, N). |
189 | 8.92M | pixel_type_w mx = std::max(W, std::max(NE, N)); |
190 | 8.92M | pixel_type_w mn = std::min(W, std::min(NE, N)); |
191 | 8.92M | pred = std::max(mn, std::min(mx, pred)); |
192 | 8.92M | return (pred + kPredictionRound) >> kPredExtraBits; |
193 | 16.1M | } 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.28M | size_t offset) { | 139 | 1.28M | size_t cur_row = y & 1 ? 0 : (xsize + 2); | 140 | 1.28M | size_t prev_row = y & 1 ? (xsize + 2) : 0; | 141 | 1.28M | size_t pos_N = prev_row + x; | 142 | 1.28M | size_t pos_NE = x < xsize - 1 ? pos_N + 1 : pos_N; | 143 | 1.28M | size_t pos_NW = x > 0 ? pos_N - 1 : pos_N; | 144 | 1.28M | std::array<uint32_t, kNumPredictors> weights; | 145 | 6.42M | 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 | 5.13M | weights[i] = pred_errors[i][pos_N] + pred_errors[i][pos_NE] + | 149 | 5.13M | pred_errors[i][pos_NW]; | 150 | 5.13M | weights[i] = ErrorWeight(weights[i], header.w[i]); | 151 | 5.13M | } | 152 | | | 153 | 1.28M | N = AddBits(N); | 154 | 1.28M | W = AddBits(W); | 155 | 1.28M | NE = AddBits(NE); | 156 | 1.28M | NW = AddBits(NW); | 157 | 1.28M | NN = AddBits(NN); | 158 | | | 159 | 1.28M | pixel_type_w teW = x == 0 ? 0 : error[cur_row + x - 1]; | 160 | 1.28M | pixel_type_w teN = error[pos_N]; | 161 | 1.28M | pixel_type_w teNW = error[pos_NW]; | 162 | 1.28M | pixel_type_w sumWN = teN + teW; | 163 | 1.28M | pixel_type_w teNE = error[pos_NE]; | 164 | | | 165 | 1.28M | 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.28M | prediction[0] = W + NE - N; | 174 | 1.28M | prediction[1] = N - (((sumWN + teNE) * header.p1C) >> 5); | 175 | 1.28M | prediction[2] = W - (((sumWN + teNW) * header.p2C) >> 5); | 176 | 1.28M | prediction[3] = | 177 | 1.28M | N - ((teNW * header.p3Ca + teN * header.p3Cb + teNE * header.p3Cc + | 178 | 1.28M | (NN - N) * header.p3Cd + (NW - W) * header.p3Ce) >> | 179 | 1.28M | 5); | 180 | | | 181 | 1.28M | pred = WeightedAverage(prediction, weights); | 182 | | | 183 | | // If all three have the same sign, skip clamping. | 184 | 1.28M | if (((teN ^ teW) | (teN ^ teNW)) > 0) { | 185 | 221k | return (pred + kPredictionRound) >> kPredExtraBits; | 186 | 221k | } | 187 | | | 188 | | // Otherwise, clamp to min/max of neighbouring pixels (just W, NE, N). | 189 | 1.06M | pixel_type_w mx = std::max(W, std::max(NE, N)); | 190 | 1.06M | pixel_type_w mn = std::min(W, std::min(NE, N)); | 191 | 1.06M | pred = std::max(mn, std::min(mx, pred)); | 192 | 1.06M | return (pred + kPredictionRound) >> kPredExtraBits; | 193 | 1.28M | } |
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 | 14.9M | size_t offset) { | 139 | 14.9M | size_t cur_row = y & 1 ? 0 : (xsize + 2); | 140 | 14.9M | size_t prev_row = y & 1 ? (xsize + 2) : 0; | 141 | 14.9M | size_t pos_N = prev_row + x; | 142 | 14.9M | size_t pos_NE = x < xsize - 1 ? pos_N + 1 : pos_N; | 143 | 14.9M | size_t pos_NW = x > 0 ? pos_N - 1 : pos_N; | 144 | 14.9M | std::array<uint32_t, kNumPredictors> weights; | 145 | 74.5M | 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 | 59.6M | weights[i] = pred_errors[i][pos_N] + pred_errors[i][pos_NE] + | 149 | 59.6M | pred_errors[i][pos_NW]; | 150 | 59.6M | weights[i] = ErrorWeight(weights[i], header.w[i]); | 151 | 59.6M | } | 152 | | | 153 | 14.9M | N = AddBits(N); | 154 | 14.9M | W = AddBits(W); | 155 | 14.9M | NE = AddBits(NE); | 156 | 14.9M | NW = AddBits(NW); | 157 | 14.9M | NN = AddBits(NN); | 158 | | | 159 | 14.9M | pixel_type_w teW = x == 0 ? 0 : error[cur_row + x - 1]; | 160 | 14.9M | pixel_type_w teN = error[pos_N]; | 161 | 14.9M | pixel_type_w teNW = error[pos_NW]; | 162 | 14.9M | pixel_type_w sumWN = teN + teW; | 163 | 14.9M | pixel_type_w teNE = error[pos_NE]; | 164 | | | 165 | 14.9M | if (compute_properties) { | 166 | 14.9M | pixel_type_w p = teW; | 167 | 14.9M | if (std::abs(teN) > std::abs(p)) p = teN; | 168 | 14.9M | if (std::abs(teNW) > std::abs(p)) p = teNW; | 169 | 14.9M | if (std::abs(teNE) > std::abs(p)) p = teNE; | 170 | 14.9M | (*properties)[offset++] = p; | 171 | 14.9M | } | 172 | | | 173 | 14.9M | prediction[0] = W + NE - N; | 174 | 14.9M | prediction[1] = N - (((sumWN + teNE) * header.p1C) >> 5); | 175 | 14.9M | prediction[2] = W - (((sumWN + teNW) * header.p2C) >> 5); | 176 | 14.9M | prediction[3] = | 177 | 14.9M | N - ((teNW * header.p3Ca + teN * header.p3Cb + teNE * header.p3Cc + | 178 | 14.9M | (NN - N) * header.p3Cd + (NW - W) * header.p3Ce) >> | 179 | 14.9M | 5); | 180 | | | 181 | 14.9M | pred = WeightedAverage(prediction, weights); | 182 | | | 183 | | // If all three have the same sign, skip clamping. | 184 | 14.9M | if (((teN ^ teW) | (teN ^ teNW)) > 0) { | 185 | 7.04M | return (pred + kPredictionRound) >> kPredExtraBits; | 186 | 7.04M | } | 187 | | | 188 | | // Otherwise, clamp to min/max of neighbouring pixels (just W, NE, N). | 189 | 7.86M | pixel_type_w mx = std::max(W, std::max(NE, N)); | 190 | 7.86M | pixel_type_w mn = std::min(W, std::min(NE, N)); | 191 | 7.86M | pred = std::max(mn, std::min(mx, pred)); | 192 | 7.86M | return (pred + kPredictionRound) >> kPredExtraBits; | 193 | 14.9M | } |
|
194 | | |
195 | | JXL_INLINE void UpdateErrors(pixel_type_w val, size_t x, size_t y, |
196 | 16.2M | size_t xsize) { |
197 | 16.2M | size_t cur_row = y & 1 ? 0 : (xsize + 2); |
198 | 16.2M | size_t prev_row = y & 1 ? (xsize + 2) : 0; |
199 | 16.2M | val = AddBits(val); |
200 | 16.2M | error[cur_row + x] = pred - val; |
201 | 81.0M | for (size_t i = 0; i < kNumPredictors; i++) { |
202 | 64.8M | pixel_type_w err = |
203 | 64.8M | (std::abs(prediction[i] - val) + kPredictionRound) >> kPredExtraBits; |
204 | | // For predicting in the next row. |
205 | 64.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 | 64.8M | pred_errors[i][prev_row + x + 1] += err; |
209 | 64.8M | } |
210 | 16.2M | } |
211 | | }; |
212 | | |
213 | | // Encoder helper function to set the parameters to some presets. |
214 | 186 | inline void PredictorMode(int i, Header *header) { |
215 | 186 | switch (i) { |
216 | 186 | case 0: |
217 | | // ~ lossless16 predictor |
218 | 186 | header->w[0] = 0xd; |
219 | 186 | header->w[1] = 0xc; |
220 | 186 | header->w[2] = 0xc; |
221 | 186 | header->w[3] = 0xc; |
222 | 186 | header->p1C = 16; |
223 | 186 | header->p2C = 10; |
224 | 186 | header->p3Ca = 7; |
225 | 186 | header->p3Cb = 7; |
226 | 186 | header->p3Cc = 7; |
227 | 186 | header->p3Cd = 0; |
228 | 186 | header->p3Ce = 0; |
229 | 186 | 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 | 186 | } |
288 | 186 | } |
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 | 17.2k | 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 | 22.0M | JXL_INLINE LookupResult Lookup(const Properties &properties) const { |
323 | 22.0M | uint32_t pos = 0; |
324 | 25.5M | while (true) { |
325 | 25.5M | #define TRAVERSE_THE_TREE \ |
326 | 32.2M | { \ |
327 | 32.2M | const FlatDecisionNode &node = nodes_[pos]; \ |
328 | 32.2M | if (node.property0 < 0) { \ |
329 | 22.0M | return {node.childID, node.predictor, node.predictor_offset, \ |
330 | 22.0M | node.multiplier}; \ |
331 | 22.0M | } \ |
332 | 32.2M | bool p0 = properties[node.property0] <= node.splitval0; \ |
333 | 10.1M | uint32_t off0 = properties[node.properties[0]] <= node.splitvals[0]; \ |
334 | 10.1M | uint32_t off1 = \ |
335 | 10.1M | 2 | int{properties[node.properties[1]] <= node.splitvals[1]}; \ |
336 | 10.1M | pos = node.childID + (p0 ? off1 : off0); \ |
337 | 10.1M | } |
338 | | |
339 | 25.5M | TRAVERSE_THE_TREE; |
340 | 6.71M | TRAVERSE_THE_TREE; |
341 | 3.40M | } |
342 | 22.0M | } |
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 | 5.76M | const int32_t l) { |
358 | 5.76M | const int32_t m = std::min(n, w); |
359 | 5.76M | 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 | 5.76M | const int32_t grad = |
366 | 5.76M | static_cast<int32_t>(static_cast<uint32_t>(n) + static_cast<uint32_t>(w) - |
367 | 5.76M | 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 | 5.76M | const int32_t grad_clamp_M = (l < m) ? M : grad; |
372 | 5.76M | return (l > M) ? m : grad_clamp_M; |
373 | 5.76M | } Unexecuted instantiation: enc_frame.cc:jxl::ClampedGradient(int, int, int) enc_modular.cc:jxl::ClampedGradient(int, int, int) Line | Count | Source | 357 | 42.2k | const int32_t l) { | 358 | 42.2k | const int32_t m = std::min(n, w); | 359 | 42.2k | 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 | 42.2k | const int32_t grad = | 366 | 42.2k | static_cast<int32_t>(static_cast<uint32_t>(n) + static_cast<uint32_t>(w) - | 367 | 42.2k | 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 | 42.2k | const int32_t grad_clamp_M = (l < m) ? M : grad; | 372 | 42.2k | return (l > M) ? m : grad_clamp_M; | 373 | 42.2k | } |
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 | 3.35M | const int32_t l) { | 358 | 3.35M | const int32_t m = std::min(n, w); | 359 | 3.35M | 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.35M | const int32_t grad = | 366 | 3.35M | static_cast<int32_t>(static_cast<uint32_t>(n) + static_cast<uint32_t>(w) - | 367 | 3.35M | 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.35M | const int32_t grad_clamp_M = (l < m) ? M : grad; | 372 | 3.35M | return (l > M) ? m : grad_clamp_M; | 373 | 3.35M | } |
Unexecuted instantiation: enc_ma.cc:jxl::ClampedGradient(int, int, int) Unexecuted instantiation: enc_transform.cc:jxl::ClampedGradient(int, int, int) Unexecuted instantiation: enc_rct.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 | 2.37M | const int32_t l) { | 358 | 2.37M | const int32_t m = std::min(n, w); | 359 | 2.37M | 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.37M | const int32_t grad = | 366 | 2.37M | static_cast<int32_t>(static_cast<uint32_t>(n) + static_cast<uint32_t>(w) - | 367 | 2.37M | 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.37M | const int32_t grad_clamp_M = (l < m) ? M : grad; | 372 | 2.37M | return (l > M) ? m : grad_clamp_M; | 373 | 2.37M | } |
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 | 133k | inline pixel_type_w Select(pixel_type_w a, pixel_type_w b, pixel_type_w c) { |
376 | 133k | pixel_type_w p = a + b - c; |
377 | 133k | pixel_type_w pa = std::abs(p - a); |
378 | 133k | pixel_type_w pb = std::abs(p - b); |
379 | 133k | return pa < pb ? a : b; |
380 | 133k | } |
381 | | |
382 | | inline void PrecomputeReferences(const Channel &ch, size_t y, |
383 | | const Image &image, uint32_t i, |
384 | 355k | Channel *references) { |
385 | 355k | ZeroFillImage(&references->plane); |
386 | 355k | uint32_t offset = 0; |
387 | 355k | size_t num_extra_props = references->w; |
388 | 355k | intptr_t onerow = references->plane.PixelsPerRow(); |
389 | 355k | for (int32_t j = static_cast<int32_t>(i) - 1; |
390 | 459k | j >= 0 && offset < num_extra_props; j--) { |
391 | 103k | if (image.channel[j].w != image.channel[i].w || |
392 | 103k | image.channel[j].h != image.channel[i].h) { |
393 | 94.9k | continue; |
394 | 94.9k | } |
395 | 8.74k | if (image.channel[j].hshift != image.channel[i].hshift) continue; |
396 | 8.35k | if (image.channel[j].vshift != image.channel[i].vshift) continue; |
397 | 8.22k | pixel_type *JXL_RESTRICT rp = references->Row(0) + offset; |
398 | 8.22k | const pixel_type *JXL_RESTRICT rpp = image.channel[j].Row(y); |
399 | 8.22k | const pixel_type *JXL_RESTRICT rpprev = image.channel[j].Row(y ? y - 1 : 0); |
400 | 93.0k | for (size_t x = 0; x < ch.w; x++, rp += onerow) { |
401 | 84.8k | pixel_type_w v = rpp[x]; |
402 | 84.8k | rp[0] = std::abs(v); |
403 | 84.8k | rp[1] = v; |
404 | 84.8k | pixel_type_w vleft = (x ? rpp[x - 1] : 0); |
405 | 84.8k | pixel_type_w vtop = (y ? rpprev[x] : vleft); |
406 | 84.8k | pixel_type_w vtopleft = (x && y ? rpprev[x - 1] : vleft); |
407 | 84.8k | pixel_type_w vpredicted = ClampedGradient(vleft, vtop, vtopleft); |
408 | 84.8k | rp[2] = std::abs(v - vpredicted); |
409 | 84.8k | rp[3] = v - vpredicted; |
410 | 84.8k | } |
411 | | |
412 | 8.22k | offset += kExtraPropsPerChannel; |
413 | 8.22k | } |
414 | 355k | } |
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 | 355k | const int y) { |
427 | 1.06M | for (size_t i = 0; i < kNumStaticProperties; i++) { |
428 | 711k | (*p)[i] = static_props[i]; |
429 | 711k | } |
430 | 355k | (*p)[2] = y; |
431 | 355k | (*p)[9] = 0; // local gradient. |
432 | 355k | } |
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 | 25.8M | pixel_type_w wp_pred) { |
449 | 25.8M | switch (p) { |
450 | 1.62M | case Predictor::Zero: |
451 | 1.62M | return pixel_type_w{0}; |
452 | 4.79M | case Predictor::Left: |
453 | 4.79M | return left; |
454 | 2.52M | case Predictor::Top: |
455 | 2.52M | return top; |
456 | 133k | case Predictor::Select: |
457 | 133k | return Select(left, top, topleft); |
458 | 9.49M | case Predictor::Weighted: |
459 | 9.49M | return wp_pred; |
460 | 4.90M | case Predictor::Gradient: |
461 | 4.90M | return pixel_type_w{ClampedGradient(left, top, topleft)}; |
462 | 1.05M | case Predictor::TopLeft: |
463 | 1.05M | return topleft; |
464 | 102k | case Predictor::TopRight: |
465 | 102k | return topright; |
466 | 57.2k | case Predictor::LeftLeft: |
467 | 57.2k | return leftleft; |
468 | 745k | case Predictor::Average0: |
469 | 745k | return (left + top) / 2; |
470 | 63.9k | case Predictor::Average1: |
471 | 63.9k | return (left + topleft) / 2; |
472 | 271k | case Predictor::Average2: |
473 | 271k | return (topleft + top) / 2; |
474 | 95.9k | case Predictor::Average3: |
475 | 95.9k | return (top + topright) / 2; |
476 | 17.7k | case Predictor::Average4: |
477 | 17.7k | return (6 * top - 2 * toptop + 7 * left + 1 * leftleft + |
478 | 17.7k | 1 * toprightright + 3 * topright + 8) / |
479 | 17.7k | 16; |
480 | 0 | default: |
481 | 0 | return pixel_type_w{0}; |
482 | 25.8M | } |
483 | 25.8M | } |
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 | 25.8M | weighted::State *wp_state, pixel_type_w *predictions) { |
491 | | // We start in position 3 because of 2 static properties + y. |
492 | 25.8M | size_t offset = 3; |
493 | 25.8M | constexpr bool compute_properties = |
494 | 25.8M | mode & kUseTree || mode & kForceComputeProperties; |
495 | 25.8M | constexpr bool nec = mode & kNoEdgeCases; |
496 | 25.8M | pixel_type_w left = (nec || x ? pp[-1] : (y ? pp[-onerow] : 0)); |
497 | 25.8M | pixel_type_w top = (nec || y ? pp[-onerow] : left); |
498 | 25.8M | pixel_type_w topleft = (nec || (x && y) ? pp[-1 - onerow] : left); |
499 | 25.8M | pixel_type_w topright = (nec || (x + 1 < w && y) ? pp[1 - onerow] : top); |
500 | 25.8M | pixel_type_w leftleft = (nec || x > 1 ? pp[-2] : left); |
501 | 25.8M | pixel_type_w toptop = (nec || y > 1 ? pp[-onerow - onerow] : top); |
502 | 25.8M | pixel_type_w toprightright = |
503 | 25.8M | (nec || (x + 2 < w && y) ? pp[2 - onerow] : topright); |
504 | | |
505 | 25.8M | if (compute_properties) { |
506 | | // location |
507 | 23.6M | (*p)[offset++] = x; |
508 | | // neighbors |
509 | 23.6M | (*p)[offset++] = top > 0 ? top : -top; |
510 | 23.6M | (*p)[offset++] = left > 0 ? left : -left; |
511 | 23.6M | (*p)[offset++] = top; |
512 | 23.6M | (*p)[offset++] = left; |
513 | | |
514 | | // local gradient |
515 | 23.6M | (*p)[offset] = left - (*p)[offset + 1]; |
516 | 23.6M | offset++; |
517 | | // local gradient |
518 | 23.6M | (*p)[offset++] = left + top - topleft; |
519 | | |
520 | | // FFV1 context properties |
521 | 23.6M | (*p)[offset++] = left - topleft; |
522 | 23.6M | (*p)[offset++] = topleft - top; |
523 | 23.6M | (*p)[offset++] = top - topright; |
524 | 23.6M | (*p)[offset++] = top - toptop; |
525 | 23.6M | (*p)[offset++] = left - leftleft; |
526 | 23.6M | } |
527 | | |
528 | 25.8M | pixel_type_w wp_pred = 0; |
529 | 25.8M | if (mode & kUseWP) { |
530 | 13.2M | wp_pred = wp_state->Predict<compute_properties>( |
531 | 13.2M | x, y, w, top, left, topright, topleft, toptop, p, offset); |
532 | 13.2M | } |
533 | 25.8M | if (!nec && compute_properties) { |
534 | 5.49M | offset += weighted::kNumProperties; |
535 | | // Extra properties. |
536 | 5.49M | const pixel_type *JXL_RESTRICT rp = references->Row(x); |
537 | 7.57M | for (size_t i = 0; i < references->w; i++) { |
538 | 2.08M | (*p)[offset++] = rp[i]; |
539 | 2.08M | } |
540 | 5.49M | } |
541 | 25.8M | PredictionResult result; |
542 | 25.8M | if (mode & kUseTree) { |
543 | 22.0M | MATreeLookup::LookupResult lr = lookup->Lookup(*p); |
544 | 22.0M | result.context = lr.context; |
545 | 22.0M | result.guess = lr.offset; |
546 | 22.0M | result.multiplier = lr.multiplier; |
547 | 22.0M | predictor = lr.predictor; |
548 | 22.0M | } |
549 | 25.8M | 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 | 25.8M | result.guess += PredictOne(predictor, left, top, toptop, topleft, topright, |
557 | 25.8M | leftleft, toprightright, wp_pred); |
558 | 25.8M | result.predictor = predictor; |
559 | | |
560 | 25.8M | return result; |
561 | 25.8M | } 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 | 973k | weighted::State *wp_state, pixel_type_w *predictions) { | 491 | | // We start in position 3 because of 2 static properties + y. | 492 | 973k | size_t offset = 3; | 493 | 973k | constexpr bool compute_properties = | 494 | 973k | mode & kUseTree || mode & kForceComputeProperties; | 495 | 973k | constexpr bool nec = mode & kNoEdgeCases; | 496 | 973k | pixel_type_w left = (nec || x ? pp[-1] : (y ? pp[-onerow] : 0)); | 497 | 973k | pixel_type_w top = (nec || y ? pp[-onerow] : left); | 498 | 973k | pixel_type_w topleft = (nec || (x && y) ? pp[-1 - onerow] : left); | 499 | 973k | pixel_type_w topright = (nec || (x + 1 < w && y) ? pp[1 - onerow] : top); | 500 | 973k | pixel_type_w leftleft = (nec || x > 1 ? pp[-2] : left); | 501 | 973k | pixel_type_w toptop = (nec || y > 1 ? pp[-onerow - onerow] : top); | 502 | 973k | pixel_type_w toprightright = | 503 | 973k | (nec || (x + 2 < w && y) ? pp[2 - onerow] : topright); | 504 | | | 505 | 973k | 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 | 973k | pixel_type_w wp_pred = 0; | 529 | 973k | 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 | 973k | 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 | 973k | PredictionResult result; | 542 | 973k | 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 | 973k | 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 | 973k | result.guess += PredictOne(predictor, left, top, toptop, topleft, topright, | 557 | 973k | leftleft, toprightright, wp_pred); | 558 | 973k | result.predictor = predictor; | 559 | | | 560 | 973k | return result; | 561 | 973k | } |
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.28M | weighted::State *wp_state, pixel_type_w *predictions) { | 491 | | // We start in position 3 because of 2 static properties + y. | 492 | 1.28M | size_t offset = 3; | 493 | 1.28M | constexpr bool compute_properties = | 494 | 1.28M | mode & kUseTree || mode & kForceComputeProperties; | 495 | 1.28M | constexpr bool nec = mode & kNoEdgeCases; | 496 | 1.28M | pixel_type_w left = (nec || x ? pp[-1] : (y ? pp[-onerow] : 0)); | 497 | 1.28M | pixel_type_w top = (nec || y ? pp[-onerow] : left); | 498 | 1.28M | pixel_type_w topleft = (nec || (x && y) ? pp[-1 - onerow] : left); | 499 | 1.28M | pixel_type_w topright = (nec || (x + 1 < w && y) ? pp[1 - onerow] : top); | 500 | 1.28M | pixel_type_w leftleft = (nec || x > 1 ? pp[-2] : left); | 501 | 1.28M | pixel_type_w toptop = (nec || y > 1 ? pp[-onerow - onerow] : top); | 502 | 1.28M | pixel_type_w toprightright = | 503 | 1.28M | (nec || (x + 2 < w && y) ? pp[2 - onerow] : topright); | 504 | | | 505 | 1.28M | 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.28M | pixel_type_w wp_pred = 0; | 529 | 1.28M | if (mode & kUseWP) { | 530 | 1.28M | wp_pred = wp_state->Predict<compute_properties>( | 531 | 1.28M | x, y, w, top, left, topright, topleft, toptop, p, offset); | 532 | 1.28M | } | 533 | 1.28M | 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.28M | PredictionResult result; | 542 | 1.28M | 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.28M | 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.28M | result.guess += PredictOne(predictor, left, top, toptop, topleft, topright, | 557 | 1.28M | leftleft, toprightright, wp_pred); | 558 | 1.28M | result.predictor = predictor; | 559 | | | 560 | 1.28M | return result; | 561 | 1.28M | } |
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 | 2.81M | weighted::State *wp_state, pixel_type_w *predictions) { | 491 | | // We start in position 3 because of 2 static properties + y. | 492 | 2.81M | size_t offset = 3; | 493 | 2.81M | constexpr bool compute_properties = | 494 | 2.81M | mode & kUseTree || mode & kForceComputeProperties; | 495 | 2.81M | constexpr bool nec = mode & kNoEdgeCases; | 496 | 2.81M | pixel_type_w left = (nec || x ? pp[-1] : (y ? pp[-onerow] : 0)); | 497 | 2.81M | pixel_type_w top = (nec || y ? pp[-onerow] : left); | 498 | 2.81M | pixel_type_w topleft = (nec || (x && y) ? pp[-1 - onerow] : left); | 499 | 2.81M | pixel_type_w topright = (nec || (x + 1 < w && y) ? pp[1 - onerow] : top); | 500 | 2.81M | pixel_type_w leftleft = (nec || x > 1 ? pp[-2] : left); | 501 | 2.81M | pixel_type_w toptop = (nec || y > 1 ? pp[-onerow - onerow] : top); | 502 | 2.81M | pixel_type_w toprightright = | 503 | 2.81M | (nec || (x + 2 < w && y) ? pp[2 - onerow] : topright); | 504 | | | 505 | 2.81M | if (compute_properties) { | 506 | | // location | 507 | 2.81M | (*p)[offset++] = x; | 508 | | // neighbors | 509 | 2.81M | (*p)[offset++] = top > 0 ? top : -top; | 510 | 2.81M | (*p)[offset++] = left > 0 ? left : -left; | 511 | 2.81M | (*p)[offset++] = top; | 512 | 2.81M | (*p)[offset++] = left; | 513 | | | 514 | | // local gradient | 515 | 2.81M | (*p)[offset] = left - (*p)[offset + 1]; | 516 | 2.81M | offset++; | 517 | | // local gradient | 518 | 2.81M | (*p)[offset++] = left + top - topleft; | 519 | | | 520 | | // FFV1 context properties | 521 | 2.81M | (*p)[offset++] = left - topleft; | 522 | 2.81M | (*p)[offset++] = topleft - top; | 523 | 2.81M | (*p)[offset++] = top - topright; | 524 | 2.81M | (*p)[offset++] = top - toptop; | 525 | 2.81M | (*p)[offset++] = left - leftleft; | 526 | 2.81M | } | 527 | | | 528 | 2.81M | pixel_type_w wp_pred = 0; | 529 | 2.81M | 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 | 2.81M | if (!nec && compute_properties) { | 534 | 2.81M | offset += weighted::kNumProperties; | 535 | | // Extra properties. | 536 | 2.81M | const pixel_type *JXL_RESTRICT rp = references->Row(x); | 537 | 4.48M | for (size_t i = 0; i < references->w; i++) { | 538 | 1.66M | (*p)[offset++] = rp[i]; | 539 | 1.66M | } | 540 | 2.81M | } | 541 | 2.81M | PredictionResult result; | 542 | 2.81M | if (mode & kUseTree) { | 543 | 2.81M | MATreeLookup::LookupResult lr = lookup->Lookup(*p); | 544 | 2.81M | result.context = lr.context; | 545 | 2.81M | result.guess = lr.offset; | 546 | 2.81M | result.multiplier = lr.multiplier; | 547 | 2.81M | predictor = lr.predictor; | 548 | 2.81M | } | 549 | 2.81M | 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.81M | result.guess += PredictOne(predictor, left, top, toptop, topleft, topright, | 557 | 2.81M | leftleft, toprightright, wp_pred); | 558 | 2.81M | result.predictor = predictor; | 559 | | | 560 | 2.81M | return result; | 561 | 2.81M | } |
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 | 8.87M | weighted::State *wp_state, pixel_type_w *predictions) { | 491 | | // We start in position 3 because of 2 static properties + y. | 492 | 8.87M | size_t offset = 3; | 493 | 8.87M | constexpr bool compute_properties = | 494 | 8.87M | mode & kUseTree || mode & kForceComputeProperties; | 495 | 8.87M | constexpr bool nec = mode & kNoEdgeCases; | 496 | 8.87M | pixel_type_w left = (nec || x ? pp[-1] : (y ? pp[-onerow] : 0)); | 497 | 8.87M | pixel_type_w top = (nec || y ? pp[-onerow] : left); | 498 | 8.87M | pixel_type_w topleft = (nec || (x && y) ? pp[-1 - onerow] : left); | 499 | 8.87M | pixel_type_w topright = (nec || (x + 1 < w && y) ? pp[1 - onerow] : top); | 500 | 8.87M | pixel_type_w leftleft = (nec || x > 1 ? pp[-2] : left); | 501 | 8.87M | pixel_type_w toptop = (nec || y > 1 ? pp[-onerow - onerow] : top); | 502 | 8.87M | pixel_type_w toprightright = | 503 | 8.87M | (nec || (x + 2 < w && y) ? pp[2 - onerow] : topright); | 504 | | | 505 | 8.87M | if (compute_properties) { | 506 | | // location | 507 | 8.87M | (*p)[offset++] = x; | 508 | | // neighbors | 509 | 8.87M | (*p)[offset++] = top > 0 ? top : -top; | 510 | 8.87M | (*p)[offset++] = left > 0 ? left : -left; | 511 | 8.87M | (*p)[offset++] = top; | 512 | 8.87M | (*p)[offset++] = left; | 513 | | | 514 | | // local gradient | 515 | 8.87M | (*p)[offset] = left - (*p)[offset + 1]; | 516 | 8.87M | offset++; | 517 | | // local gradient | 518 | 8.87M | (*p)[offset++] = left + top - topleft; | 519 | | | 520 | | // FFV1 context properties | 521 | 8.87M | (*p)[offset++] = left - topleft; | 522 | 8.87M | (*p)[offset++] = topleft - top; | 523 | 8.87M | (*p)[offset++] = top - topright; | 524 | 8.87M | (*p)[offset++] = top - toptop; | 525 | 8.87M | (*p)[offset++] = left - leftleft; | 526 | 8.87M | } | 527 | | | 528 | 8.87M | pixel_type_w wp_pred = 0; | 529 | 8.87M | 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 | 8.87M | 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 | 8.87M | PredictionResult result; | 542 | 8.87M | if (mode & kUseTree) { | 543 | 8.87M | MATreeLookup::LookupResult lr = lookup->Lookup(*p); | 544 | 8.87M | result.context = lr.context; | 545 | 8.87M | result.guess = lr.offset; | 546 | 8.87M | result.multiplier = lr.multiplier; | 547 | 8.87M | predictor = lr.predictor; | 548 | 8.87M | } | 549 | 8.87M | 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 | 8.87M | result.guess += PredictOne(predictor, left, top, toptop, topleft, topright, | 557 | 8.87M | leftleft, toprightright, wp_pred); | 558 | 8.87M | result.predictor = predictor; | 559 | | | 560 | 8.87M | return result; | 561 | 8.87M | } |
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 | 2.55M | weighted::State *wp_state, pixel_type_w *predictions) { | 491 | | // We start in position 3 because of 2 static properties + y. | 492 | 2.55M | size_t offset = 3; | 493 | 2.55M | constexpr bool compute_properties = | 494 | 2.55M | mode & kUseTree || mode & kForceComputeProperties; | 495 | 2.55M | constexpr bool nec = mode & kNoEdgeCases; | 496 | 2.55M | pixel_type_w left = (nec || x ? pp[-1] : (y ? pp[-onerow] : 0)); | 497 | 2.55M | pixel_type_w top = (nec || y ? pp[-onerow] : left); | 498 | 2.55M | pixel_type_w topleft = (nec || (x && y) ? pp[-1 - onerow] : left); | 499 | 2.55M | pixel_type_w topright = (nec || (x + 1 < w && y) ? pp[1 - onerow] : top); | 500 | 2.55M | pixel_type_w leftleft = (nec || x > 1 ? pp[-2] : left); | 501 | 2.55M | pixel_type_w toptop = (nec || y > 1 ? pp[-onerow - onerow] : top); | 502 | 2.55M | pixel_type_w toprightright = | 503 | 2.55M | (nec || (x + 2 < w && y) ? pp[2 - onerow] : topright); | 504 | | | 505 | 2.55M | if (compute_properties) { | 506 | | // location | 507 | 2.55M | (*p)[offset++] = x; | 508 | | // neighbors | 509 | 2.55M | (*p)[offset++] = top > 0 ? top : -top; | 510 | 2.55M | (*p)[offset++] = left > 0 ? left : -left; | 511 | 2.55M | (*p)[offset++] = top; | 512 | 2.55M | (*p)[offset++] = left; | 513 | | | 514 | | // local gradient | 515 | 2.55M | (*p)[offset] = left - (*p)[offset + 1]; | 516 | 2.55M | offset++; | 517 | | // local gradient | 518 | 2.55M | (*p)[offset++] = left + top - topleft; | 519 | | | 520 | | // FFV1 context properties | 521 | 2.55M | (*p)[offset++] = left - topleft; | 522 | 2.55M | (*p)[offset++] = topleft - top; | 523 | 2.55M | (*p)[offset++] = top - topright; | 524 | 2.55M | (*p)[offset++] = top - toptop; | 525 | 2.55M | (*p)[offset++] = left - leftleft; | 526 | 2.55M | } | 527 | | | 528 | 2.55M | pixel_type_w wp_pred = 0; | 529 | 2.55M | if (mode & kUseWP) { | 530 | 2.55M | wp_pred = wp_state->Predict<compute_properties>( | 531 | 2.55M | x, y, w, top, left, topright, topleft, toptop, p, offset); | 532 | 2.55M | } | 533 | 2.55M | if (!nec && compute_properties) { | 534 | 2.55M | offset += weighted::kNumProperties; | 535 | | // Extra properties. | 536 | 2.55M | const pixel_type *JXL_RESTRICT rp = references->Row(x); | 537 | 2.97M | for (size_t i = 0; i < references->w; i++) { | 538 | 419k | (*p)[offset++] = rp[i]; | 539 | 419k | } | 540 | 2.55M | } | 541 | 2.55M | PredictionResult result; | 542 | 2.55M | if (mode & kUseTree) { | 543 | 2.55M | MATreeLookup::LookupResult lr = lookup->Lookup(*p); | 544 | 2.55M | result.context = lr.context; | 545 | 2.55M | result.guess = lr.offset; | 546 | 2.55M | result.multiplier = lr.multiplier; | 547 | 2.55M | predictor = lr.predictor; | 548 | 2.55M | } | 549 | 2.55M | 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.55M | result.guess += PredictOne(predictor, left, top, toptop, topleft, topright, | 557 | 2.55M | leftleft, toprightright, wp_pred); | 558 | 2.55M | result.predictor = predictor; | 559 | | | 560 | 2.55M | return result; | 561 | 2.55M | } |
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 | 7.84M | weighted::State *wp_state, pixel_type_w *predictions) { | 491 | | // We start in position 3 because of 2 static properties + y. | 492 | 7.84M | size_t offset = 3; | 493 | 7.84M | constexpr bool compute_properties = | 494 | 7.84M | mode & kUseTree || mode & kForceComputeProperties; | 495 | 7.84M | constexpr bool nec = mode & kNoEdgeCases; | 496 | 7.84M | pixel_type_w left = (nec || x ? pp[-1] : (y ? pp[-onerow] : 0)); | 497 | 7.84M | pixel_type_w top = (nec || y ? pp[-onerow] : left); | 498 | 7.84M | pixel_type_w topleft = (nec || (x && y) ? pp[-1 - onerow] : left); | 499 | 7.84M | pixel_type_w topright = (nec || (x + 1 < w && y) ? pp[1 - onerow] : top); | 500 | 7.84M | pixel_type_w leftleft = (nec || x > 1 ? pp[-2] : left); | 501 | 7.84M | pixel_type_w toptop = (nec || y > 1 ? pp[-onerow - onerow] : top); | 502 | 7.84M | pixel_type_w toprightright = | 503 | 7.84M | (nec || (x + 2 < w && y) ? pp[2 - onerow] : topright); | 504 | | | 505 | 7.84M | if (compute_properties) { | 506 | | // location | 507 | 7.84M | (*p)[offset++] = x; | 508 | | // neighbors | 509 | 7.84M | (*p)[offset++] = top > 0 ? top : -top; | 510 | 7.84M | (*p)[offset++] = left > 0 ? left : -left; | 511 | 7.84M | (*p)[offset++] = top; | 512 | 7.84M | (*p)[offset++] = left; | 513 | | | 514 | | // local gradient | 515 | 7.84M | (*p)[offset] = left - (*p)[offset + 1]; | 516 | 7.84M | offset++; | 517 | | // local gradient | 518 | 7.84M | (*p)[offset++] = left + top - topleft; | 519 | | | 520 | | // FFV1 context properties | 521 | 7.84M | (*p)[offset++] = left - topleft; | 522 | 7.84M | (*p)[offset++] = topleft - top; | 523 | 7.84M | (*p)[offset++] = top - topright; | 524 | 7.84M | (*p)[offset++] = top - toptop; | 525 | 7.84M | (*p)[offset++] = left - leftleft; | 526 | 7.84M | } | 527 | | | 528 | 7.84M | pixel_type_w wp_pred = 0; | 529 | 7.84M | if (mode & kUseWP) { | 530 | 7.84M | wp_pred = wp_state->Predict<compute_properties>( | 531 | 7.84M | x, y, w, top, left, topright, topleft, toptop, p, offset); | 532 | 7.84M | } | 533 | 7.84M | 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 | 7.84M | PredictionResult result; | 542 | 7.84M | if (mode & kUseTree) { | 543 | 7.84M | MATreeLookup::LookupResult lr = lookup->Lookup(*p); | 544 | 7.84M | result.context = lr.context; | 545 | 7.84M | result.guess = lr.offset; | 546 | 7.84M | result.multiplier = lr.multiplier; | 547 | 7.84M | predictor = lr.predictor; | 548 | 7.84M | } | 549 | 7.84M | 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 | 7.84M | result.guess += PredictOne(predictor, left, top, toptop, topleft, topright, | 557 | 7.84M | leftleft, toprightright, wp_pred); | 558 | 7.84M | result.predictor = predictor; | 559 | | | 560 | 7.84M | return result; | 561 | 7.84M | } |
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 | 114k | weighted::State *wp_state, pixel_type_w *predictions) { | 491 | | // We start in position 3 because of 2 static properties + y. | 492 | 114k | size_t offset = 3; | 493 | 114k | constexpr bool compute_properties = | 494 | 114k | mode & kUseTree || mode & kForceComputeProperties; | 495 | 114k | constexpr bool nec = mode & kNoEdgeCases; | 496 | 114k | pixel_type_w left = (nec || x ? pp[-1] : (y ? pp[-onerow] : 0)); | 497 | 114k | pixel_type_w top = (nec || y ? pp[-onerow] : left); | 498 | 114k | pixel_type_w topleft = (nec || (x && y) ? pp[-1 - onerow] : left); | 499 | 114k | pixel_type_w topright = (nec || (x + 1 < w && y) ? pp[1 - onerow] : top); | 500 | 114k | pixel_type_w leftleft = (nec || x > 1 ? pp[-2] : left); | 501 | 114k | pixel_type_w toptop = (nec || y > 1 ? pp[-onerow - onerow] : top); | 502 | 114k | pixel_type_w toprightright = | 503 | 114k | (nec || (x + 2 < w && y) ? pp[2 - onerow] : topright); | 504 | | | 505 | 114k | if (compute_properties) { | 506 | | // location | 507 | 114k | (*p)[offset++] = x; | 508 | | // neighbors | 509 | 114k | (*p)[offset++] = top > 0 ? top : -top; | 510 | 114k | (*p)[offset++] = left > 0 ? left : -left; | 511 | 114k | (*p)[offset++] = top; | 512 | 114k | (*p)[offset++] = left; | 513 | | | 514 | | // local gradient | 515 | 114k | (*p)[offset] = left - (*p)[offset + 1]; | 516 | 114k | offset++; | 517 | | // local gradient | 518 | 114k | (*p)[offset++] = left + top - topleft; | 519 | | | 520 | | // FFV1 context properties | 521 | 114k | (*p)[offset++] = left - topleft; | 522 | 114k | (*p)[offset++] = topleft - top; | 523 | 114k | (*p)[offset++] = top - topright; | 524 | 114k | (*p)[offset++] = top - toptop; | 525 | 114k | (*p)[offset++] = left - leftleft; | 526 | 114k | } | 527 | | | 528 | 114k | pixel_type_w wp_pred = 0; | 529 | 114k | if (mode & kUseWP) { | 530 | 114k | wp_pred = wp_state->Predict<compute_properties>( | 531 | 114k | x, y, w, top, left, topright, topleft, toptop, p, offset); | 532 | 114k | } | 533 | 114k | if (!nec && compute_properties) { | 534 | 114k | offset += weighted::kNumProperties; | 535 | | // Extra properties. | 536 | 114k | const pixel_type *JXL_RESTRICT rp = references->Row(x); | 537 | 114k | for (size_t i = 0; i < references->w; i++) { | 538 | 0 | (*p)[offset++] = rp[i]; | 539 | 0 | } | 540 | 114k | } | 541 | 114k | PredictionResult result; | 542 | 114k | 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 | 114k | 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 | 114k | result.guess += PredictOne(predictor, left, top, toptop, topleft, topright, | 557 | 114k | leftleft, toprightright, wp_pred); | 558 | 114k | result.predictor = predictor; | 559 | | | 560 | 114k | return result; | 561 | 114k | } |
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.42M | weighted::State *wp_state, pixel_type_w *predictions) { | 491 | | // We start in position 3 because of 2 static properties + y. | 492 | 1.42M | size_t offset = 3; | 493 | 1.42M | constexpr bool compute_properties = | 494 | 1.42M | mode & kUseTree || mode & kForceComputeProperties; | 495 | 1.42M | constexpr bool nec = mode & kNoEdgeCases; | 496 | 1.42M | pixel_type_w left = (nec || x ? pp[-1] : (y ? pp[-onerow] : 0)); | 497 | 1.42M | pixel_type_w top = (nec || y ? pp[-onerow] : left); | 498 | 1.42M | pixel_type_w topleft = (nec || (x && y) ? pp[-1 - onerow] : left); | 499 | 1.42M | pixel_type_w topright = (nec || (x + 1 < w && y) ? pp[1 - onerow] : top); | 500 | 1.42M | pixel_type_w leftleft = (nec || x > 1 ? pp[-2] : left); | 501 | 1.42M | pixel_type_w toptop = (nec || y > 1 ? pp[-onerow - onerow] : top); | 502 | 1.42M | pixel_type_w toprightright = | 503 | 1.42M | (nec || (x + 2 < w && y) ? pp[2 - onerow] : topright); | 504 | | | 505 | 1.42M | if (compute_properties) { | 506 | | // location | 507 | 1.42M | (*p)[offset++] = x; | 508 | | // neighbors | 509 | 1.42M | (*p)[offset++] = top > 0 ? top : -top; | 510 | 1.42M | (*p)[offset++] = left > 0 ? left : -left; | 511 | 1.42M | (*p)[offset++] = top; | 512 | 1.42M | (*p)[offset++] = left; | 513 | | | 514 | | // local gradient | 515 | 1.42M | (*p)[offset] = left - (*p)[offset + 1]; | 516 | 1.42M | offset++; | 517 | | // local gradient | 518 | 1.42M | (*p)[offset++] = left + top - topleft; | 519 | | | 520 | | // FFV1 context properties | 521 | 1.42M | (*p)[offset++] = left - topleft; | 522 | 1.42M | (*p)[offset++] = topleft - top; | 523 | 1.42M | (*p)[offset++] = top - topright; | 524 | 1.42M | (*p)[offset++] = top - toptop; | 525 | 1.42M | (*p)[offset++] = left - leftleft; | 526 | 1.42M | } | 527 | | | 528 | 1.42M | pixel_type_w wp_pred = 0; | 529 | 1.42M | if (mode & kUseWP) { | 530 | 1.42M | wp_pred = wp_state->Predict<compute_properties>( | 531 | 1.42M | x, y, w, top, left, topright, topleft, toptop, p, offset); | 532 | 1.42M | } | 533 | 1.42M | 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.42M | PredictionResult result; | 542 | 1.42M | 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.42M | 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.42M | result.guess += PredictOne(predictor, left, top, toptop, topleft, topright, | 557 | 1.42M | leftleft, toprightright, wp_pred); | 558 | 1.42M | result.predictor = predictor; | 559 | | | 560 | 1.42M | return result; | 561 | 1.42M | } |
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 | 973k | const int y, Predictor predictor) { |
568 | 973k | return detail::Predict</*mode=*/0>( |
569 | 973k | /*p=*/nullptr, w, pp, onerow, x, y, predictor, /*lookup=*/nullptr, |
570 | 973k | /*references=*/nullptr, /*wp_state=*/nullptr, /*predictions=*/nullptr); |
571 | 973k | } |
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.28M | weighted::State *wp_state) { |
578 | 1.28M | return detail::Predict<detail::kUseWP>( |
579 | 1.28M | /*p=*/nullptr, w, pp, onerow, x, y, predictor, /*lookup=*/nullptr, |
580 | 1.28M | /*references=*/nullptr, wp_state, /*predictions=*/nullptr); |
581 | 1.28M | } |
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 | 2.81M | const Channel &references) { |
589 | 2.81M | return detail::Predict<detail::kUseTree>( |
590 | 2.81M | p, w, pp, onerow, x, y, Predictor::Zero, &tree_lookup, &references, |
591 | 2.81M | /*wp_state=*/nullptr, /*predictions=*/nullptr); |
592 | 2.81M | } |
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 | 8.87M | const MATreeLookup &tree_lookup, const Channel &references) { |
598 | 8.87M | return detail::Predict<detail::kUseTree | detail::kNoEdgeCases>( |
599 | 8.87M | p, w, pp, onerow, x, y, Predictor::Zero, &tree_lookup, &references, |
600 | 8.87M | /*wp_state=*/nullptr, /*predictions=*/nullptr); |
601 | 8.87M | } |
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 | 2.55M | weighted::State *wp_state) { |
610 | 2.55M | return detail::Predict<detail::kUseTree | detail::kUseWP>( |
611 | 2.55M | p, w, pp, onerow, x, y, Predictor::Zero, &tree_lookup, &references, |
612 | 2.55M | wp_state, /*predictions=*/nullptr); |
613 | 2.55M | } |
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 | 7.84M | weighted::State *wp_state) { |
621 | 7.84M | return detail::Predict<detail::kUseTree | detail::kUseWP | |
622 | 7.84M | detail::kNoEdgeCases>( |
623 | 7.84M | p, w, pp, onerow, x, y, Predictor::Zero, &tree_lookup, &references, |
624 | 7.84M | wp_state, /*predictions=*/nullptr); |
625 | 7.84M | } |
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 | 114k | weighted::State *wp_state) { |
633 | 114k | return detail::Predict<detail::kForceComputeProperties | detail::kUseWP>( |
634 | 114k | p, w, pp, onerow, x, y, predictor, /*lookup=*/nullptr, &references, |
635 | 114k | wp_state, /*predictions=*/nullptr); |
636 | 114k | } |
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.42M | weighted::State *wp_state) { |
655 | 1.42M | return detail::Predict<detail::kForceComputeProperties | detail::kUseWP | |
656 | 1.42M | detail::kNoEdgeCases>( |
657 | 1.42M | p, w, pp, onerow, x, y, predictor, /*lookup=*/nullptr, &references, |
658 | 1.42M | wp_state, /*predictions=*/nullptr); |
659 | 1.42M | } |
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_ |