FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libswscale/ops_optimizer.c
Date: 2026-10-19 08:11:58
Exec Total Coverage
Lines: 640 698 91.7%
Functions: 20 20 100.0%
Branches: 460 527 87.3%

Line Branch Exec Source
1 /**
2 * Copyright (C) 2025 Niklas Haas
3 *
4 * This file is part of FFmpeg.
5 *
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #include "libavutil/attributes.h"
22 #include "libavutil/avassert.h"
23 #include "libavutil/bswap.h"
24 #include "libavutil/rational.h"
25
26 #include "ops.h"
27 #include "ops_internal.h"
28
29 #define RET(x) \
30 do { \
31 if ((ret = (x)) < 0) \
32 return ret; \
33 } while (0)
34
35 /**
36 * Try to commute a clear op with the next operation. Makes any adjustments
37 * to the operations as needed, but does not perform the actual commutation.
38 *
39 * Returns whether successful.
40 */
41 1375911 static bool op_commute_clear(SwsOp *op, SwsOp *next)
42 {
43 av_assert1(op->op == SWS_OP_CLEAR);
44
5/8
✓ Branch 0 taken 168301 times.
✓ Branch 1 taken 263320 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 191718 times.
✓ Branch 4 taken 68166 times.
✓ Branch 5 taken 684406 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
1375911 switch (next->op) {
45 168301 case SWS_OP_CONVERT:
46 168301 op->type = next->convert.to;
47 av_fallthrough;
48 431621 case SWS_OP_LSHIFT:
49 case SWS_OP_RSHIFT:
50 case SWS_OP_DITHER:
51 case SWS_OP_MIN:
52 case SWS_OP_MAX:
53 case SWS_OP_SCALE:
54 case SWS_OP_READ:
55 431621 ff_sws_apply_op_q(next, op->clear.value);
56 431621 return true;
57 ✗ case SWS_OP_FILTER_H:
58 case SWS_OP_FILTER_V:
59 ✗ op->type = next->filter.type;
60 ✗ return true;
61 191718 case SWS_OP_SWIZZLE:
62 191718 ff_sws_comp_mask_swizzle(&op->clear.mask, &next->swizzle);
63 191718 ff_sws_apply_op_q(next, op->clear.value);
64 191718 return true;
65 68166 case SWS_OP_SWAP_BYTES:
66
2/2
✓ Branch 0 taken 50074 times.
✓ Branch 1 taken 18092 times.
68166 switch (next->type) {
67 50074 case SWS_PIXEL_U16:
68 case SWS_PIXEL_U32:
69 50074 ff_sws_apply_op_q(next, op->clear.value); /* always representable */
70 50074 return true;
71 18092 default:
72 18092 return false;
73 }
74 684406 case SWS_OP_INVALID:
75 case SWS_OP_WRITE:
76 case SWS_OP_LINEAR:
77 case SWS_OP_PACK:
78 case SWS_OP_UNPACK:
79 case SWS_OP_CLEAR:
80 case SWS_OP_LUT_3D:
81 684406 return false;
82 ✗ case SWS_OP_TYPE_NB:
83 ✗ break;
84 }
85
86 ✗ av_unreachable("Invalid operation type!");
87 return false;
88 }
89
90 /**
91 * Try to commute a swizzle op with the next operation. Makes any adjustments
92 * to the operations as needed, but does not perform the actual commutation.
93 *
94 * Returns whether successful.
95 */
96 1621740 static bool op_commute_swizzle(SwsOp *op, SwsOp *next)
97 {
98 1621740 bool seen[4] = {0};
99
100 av_assert1(op->op == SWS_OP_SWIZZLE);
101
5/8
✓ Branch 0 taken 253970 times.
✓ Branch 1 taken 296049 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 113509 times.
✓ Branch 4 taken 78585 times.
✓ Branch 5 taken 879627 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
1621740 switch (next->op) {
102 253970 case SWS_OP_CONVERT:
103 253970 op->type = next->convert.to;
104 av_fallthrough;
105 550019 case SWS_OP_SWAP_BYTES:
106 case SWS_OP_LSHIFT:
107 case SWS_OP_RSHIFT:
108 case SWS_OP_SCALE:
109 550019 return true;
110 ✗ case SWS_OP_FILTER_H:
111 case SWS_OP_FILTER_V:
112 ✗ op->type = next->filter.type;
113 ✗ return true;
114
115 /**
116 * We can commute per-channel ops only if the per-channel constants are the
117 * same for all duplicated channels; e.g.:
118 * SWIZZLE {0, 0, 0, 3}
119 * NEXT {x, x, x, w}
120 * ->
121 * NEXT {x, _, _, w}
122 * SWIZZLE {0, 0, 0, 3}
123 */
124 113509 case SWS_OP_MIN:
125 case SWS_OP_MAX: {
126 113509 const SwsClampOp c = next->clamp;
127
2/2
✓ Branch 0 taken 454036 times.
✓ Branch 1 taken 113509 times.
567545 for (int i = 0; i < 4; i++) {
128
2/2
✓ Branch 0 taken 105076 times.
✓ Branch 1 taken 348960 times.
454036 if (!SWS_OP_NEEDED(op, i))
129 105076 continue;
130 348960 const int j = op->swizzle.in[i];
131
3/4
✓ Branch 0 taken 71922 times.
✓ Branch 1 taken 277038 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 71922 times.
348960 if (seen[j] && ff_cmp_q64(next->clamp.limit[j], c.limit[i]))
132 ✗ return false;
133 348960 next->clamp.limit[j] = c.limit[i];
134 348960 seen[j] = true;
135 }
136 113509 return true;
137 }
138
139 78585 case SWS_OP_DITHER: {
140 78585 const SwsDitherOp d = next->dither;
141
2/2
✓ Branch 0 taken 294736 times.
✓ Branch 1 taken 68783 times.
363519 for (int i = 0; i < 4; i++) {
142
2/2
✓ Branch 0 taken 64252 times.
✓ Branch 1 taken 230484 times.
294736 if (!SWS_OP_NEEDED(op, i))
143 64252 continue;
144 230484 const int j = op->swizzle.in[i];
145
4/4
✓ Branch 0 taken 42296 times.
✓ Branch 1 taken 188188 times.
✓ Branch 2 taken 9802 times.
✓ Branch 3 taken 32494 times.
230484 if (seen[j] && next->dither.y_offset[j] != d.y_offset[i])
146 9802 return false;
147 220682 next->dither.y_offset[j] = d.y_offset[i];
148 220682 seen[j] = true;
149 }
150 68783 return true;
151 }
152
153 879627 case SWS_OP_INVALID:
154 case SWS_OP_READ:
155 case SWS_OP_WRITE:
156 case SWS_OP_SWIZZLE:
157 case SWS_OP_CLEAR:
158 case SWS_OP_LINEAR:
159 case SWS_OP_PACK:
160 case SWS_OP_UNPACK:
161 case SWS_OP_LUT_3D:
162 879627 return false;
163 ✗ case SWS_OP_TYPE_NB:
164 ✗ break;
165 }
166
167 ✗ av_unreachable("Invalid operation type!");
168 return false;
169 }
170
171 /**
172 * Try to commute a filter op with the previous operation. Makes any
173 * adjustments to the operations as needed, but does not perform the actual
174 * commutation.
175 *
176 * Returns whether successful.
177 */
178 10782018 static bool op_commute_filter(SwsOp *op, SwsOp *prev)
179 {
180
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10782018 times.
10782018 av_assert0(!ff_sws_pixel_type_is_int(op->filter.type));
181
182
2/4
✓ Branch 0 taken 1304927 times.
✓ Branch 1 taken 9477091 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
10782018 switch (prev->op) {
183 1304927 case SWS_OP_SWIZZLE:
184 case SWS_OP_SCALE:
185 case SWS_OP_LINEAR:
186 case SWS_OP_DITHER:
187 1304927 prev->type = op->filter.type;
188 1304927 return true;
189 9477091 case SWS_OP_CONVERT:
190 case SWS_OP_INVALID:
191 case SWS_OP_READ:
192 case SWS_OP_WRITE:
193 case SWS_OP_SWAP_BYTES:
194 case SWS_OP_UNPACK:
195 case SWS_OP_PACK:
196 case SWS_OP_LSHIFT:
197 case SWS_OP_RSHIFT:
198 case SWS_OP_CLEAR:
199 case SWS_OP_MIN:
200 case SWS_OP_MAX:
201 case SWS_OP_FILTER_H:
202 case SWS_OP_FILTER_V:
203 case SWS_OP_LUT_3D:
204 9477091 return false;
205 ✗ case SWS_OP_TYPE_NB:
206 ✗ break;
207 }
208
209 ✗ av_unreachable("Invalid operation type!");
210 return false;
211 }
212
213 /* returns log2(x) only if x is a power of two, or 0 otherwise */
214 1065664 static int exact_log2(const int x)
215 {
216 int p;
217
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1065664 times.
1065664 if (x <= 0)
218 ✗ return 0;
219 1065664 p = av_log2(x);
220
2/2
✓ Branch 0 taken 424477 times.
✓ Branch 1 taken 641187 times.
1065664 return (1 << p) == x ? p : 0;
221 }
222
223 2706542 static int exact_log2_q64(const AVRational64 x)
224 {
225
2/2
✓ Branch 0 taken 568880 times.
✓ Branch 1 taken 2137662 times.
2706542 if (x.den == 1)
226 568880 return exact_log2(x.num);
227
2/2
✓ Branch 0 taken 496784 times.
✓ Branch 1 taken 1640878 times.
2137662 else if (x.num == 1)
228 496784 return -exact_log2(x.den);
229 else
230 1640878 return 0;
231 }
232
233 /**
234 * If a linear operation can be reduced to a scalar multiplication, returns
235 * the corresponding scaling factor, or 0 otherwise.
236 */
237 3731166 static bool extract_scalar(const SwsLinearOp *c,
238 const SwsComps *comps, const SwsComps *prev,
239 SwsScaleOp *out_scale)
240 {
241 3731166 SwsScaleOp scale = {0};
242
243 /* There are components not on the main diagonal */
244
2/2
✓ Branch 1 taken 2673598 times.
✓ Branch 2 taken 1057568 times.
3731166 if (ff_sws_linear_mask(c) & ~SWS_MASK_DIAG4)
245 2673598 return false;
246
247
2/2
✓ Branch 0 taken 3373715 times.
✓ Branch 1 taken 287008 times.
3660723 for (int i = 0; i < 4; i++) {
248 3373715 const AVRational64 s = c->m[i][i];
249
1/2
✓ Branch 0 taken 3373715 times.
✗ Branch 1 not taken.
3373715 if ((prev->flags[i] & SWS_COMP_ZERO) ||
250
2/2
✓ Branch 0 taken 293308 times.
✓ Branch 1 taken 3080407 times.
3373715 (comps->flags[i] & SWS_COMP_GARBAGE))
251 293308 continue;
252
4/4
✓ Branch 0 taken 2022839 times.
✓ Branch 1 taken 1057568 times.
✓ Branch 3 taken 770560 times.
✓ Branch 4 taken 1252279 times.
3080407 if (scale.factor.den && ff_cmp_q64(s, scale.factor))
253 770560 return false;
254 2309847 scale.factor = s;
255 }
256
257
1/2
✓ Branch 0 taken 287008 times.
✗ Branch 1 not taken.
287008 if (scale.factor.den)
258 287008 *out_scale = scale;
259 287008 return scale.factor.den;
260 }
261
262 /* Extracts an integer clear operation (subset) from the given linear op. */
263 3929111 static bool extract_constant_rows(SwsLinearOp *c, const SwsComps *prev,
264 SwsClearOp *out_clear)
265 {
266 3929111 const uint32_t mask = ff_sws_linear_mask(c);
267 3929111 SwsClearOp clear = {0};
268 3929111 bool ret = false;
269
270
2/2
✓ Branch 0 taken 15716444 times.
✓ Branch 1 taken 3929111 times.
19645555 for (int i = 0; i < 4; i++) {
271 15716444 bool const_row = c->m[i][4].den == 1; /* offset is integer */
272
2/2
✓ Branch 0 taken 62865776 times.
✓ Branch 1 taken 15716444 times.
78582220 for (int j = 0; j < 4; j++) {
273
2/2
✓ Branch 0 taken 25774277 times.
✓ Branch 1 taken 37091499 times.
88640053 const_row &= c->m[i][j].num == 0 || /* scalar is zero */
274
2/2
✓ Branch 0 taken 382457 times.
✓ Branch 1 taken 25391820 times.
25774277 (prev->flags[j] & SWS_COMP_ZERO); /* input is zero */
275 }
276
3/4
✓ Branch 0 taken 234626 times.
✓ Branch 1 taken 15481818 times.
✓ Branch 2 taken 234626 times.
✗ Branch 3 not taken.
15716444 if (const_row && (mask & SWS_MASK_ROW(i))) {
277 234626 clear.mask |= SWS_COMP(i);
278 234626 clear.value[i] = c->m[i][4];
279
2/2
✓ Branch 0 taken 1173130 times.
✓ Branch 1 taken 234626 times.
1407756 for (int j = 0; j < 5; j++)
280 1173130 c->m[i][j] = Q(i == j);
281 234626 ret = true;
282 }
283 }
284
285
2/2
✓ Branch 0 taken 197945 times.
✓ Branch 1 taken 3731166 times.
3929111 if (ret)
286 197945 *out_clear = clear;
287 3929111 return ret;
288 }
289
290 /* Unswizzle a linear operation by aligning single-input rows with
291 * their corresponding diagonal */
292 3444158 static bool extract_swizzle(SwsLinearOp *op, const SwsComps *prev,
293 SwsSwizzleOp *out_swiz)
294 {
295 3444158 SwsSwizzleOp swiz = SWS_SWIZZLE(0, 1, 2, 3);
296 3444158 SwsLinearOp c = *op;
297
298 /* Find non-zero coefficients in the main 4x4 matrix */
299 3444158 uint32_t nonzero = 0;
300
2/2
✓ Branch 0 taken 13776632 times.
✓ Branch 1 taken 3444158 times.
17220790 for (int i = 0; i < 4; i++) {
301
2/2
✓ Branch 0 taken 55106528 times.
✓ Branch 1 taken 13776632 times.
68883160 for (int j = 0; j < 4; j++) {
302
4/4
✓ Branch 0 taken 23476196 times.
✓ Branch 1 taken 31630332 times.
✓ Branch 2 taken 124980 times.
✓ Branch 3 taken 23351216 times.
55106528 if (!c.m[i][j].num || (prev->flags[j] & SWS_COMP_ZERO))
303 31755312 continue;
304 23351216 nonzero |= SWS_MASK(i, j);
305 }
306 }
307
308 /* If a value is unique in its row and the target column is
309 * empty, move it there and update the input swizzle */
310
2/2
✓ Branch 0 taken 13776632 times.
✓ Branch 1 taken 3444158 times.
17220790 for (int i = 0; i < 4; i++) {
311
2/2
✓ Branch 0 taken 13644116 times.
✓ Branch 1 taken 132516 times.
13776632 if (nonzero & SWS_MASK_COL(i))
312 13644116 continue; /* target column is not empty */
313
1/2
✓ Branch 0 taken 132516 times.
✗ Branch 1 not taken.
132516 for (int j = 0; j < 4; j++) {
314
1/2
✓ Branch 0 taken 132516 times.
✗ Branch 1 not taken.
132516 if ((nonzero & SWS_MASK_ROW(i)) == SWS_MASK(i, j)) {
315 /* Move coefficient to the diagonal */
316 132516 c.m[i][i] = c.m[i][j];
317 132516 c.m[i][j] = Q(0);
318 132516 swiz.in[i] = j;
319 132516 break;
320 }
321 }
322 }
323
324
2/2
✓ Branch 0 taken 3377900 times.
✓ Branch 1 taken 66258 times.
3444158 if (swiz.mask == SWS_SWIZZLE(0, 1, 2, 3).mask)
325 3377900 return false; /* no swizzle was identified */
326
327 66258 *out_swiz = swiz;
328 66258 *op = c;
329 66258 return true;
330 }
331
332 186568 static int op_result_is_exact(const SwsOp *op)
333 {
334
2/2
✓ Branch 0 taken 231301 times.
✓ Branch 1 taken 14043 times.
245344 for (int i = 0; i < 4; i++) {
335
4/4
✓ Branch 0 taken 212110 times.
✓ Branch 1 taken 19191 times.
✓ Branch 2 taken 172525 times.
✓ Branch 3 taken 39585 times.
231301 if (SWS_OP_NEEDED(op, i) && !(op->comps.flags[i] & SWS_COMP_EXACT))
336 172525 return false;
337 }
338
339 14043 return true;
340 }
341
342 1795943 int ff_sws_op_list_optimize(SwsOpList *ops)
343 {
344 int ret;
345
346 11870073 retry:
347 13666016 ff_sws_op_list_update_comps(ops);
348
349 /* Try to push filters towards the input; do this first to unblock
350 * in-place optimizations like linear op fusion */
351
2/2
✓ Branch 0 taken 127251111 times.
✓ Branch 1 taken 11915179 times.
139166290 for (int n = 1; n < ops->num_ops; n++) {
352 127251111 SwsOp *op = &ops->ops[n];
353 127251111 SwsOp *prev = &ops->ops[n - 1];
354
355
2/2
✓ Branch 0 taken 10782018 times.
✓ Branch 1 taken 116469093 times.
127251111 switch (op->op) {
356 10782018 case SWS_OP_FILTER_H:
357 case SWS_OP_FILTER_V:
358
2/2
✓ Branch 1 taken 1304927 times.
✓ Branch 2 taken 9477091 times.
10782018 if (op_commute_filter(op, prev)) {
359 1304927 FFSWAP(SwsOp, *op, *prev);
360 1304927 goto retry;
361 }
362
363 /* Merge filter with prior conversion */
364
2/2
✓ Branch 0 taken 1374746 times.
✓ Branch 1 taken 8102345 times.
9477091 if (prev->op == SWS_OP_CONVERT) {
365 1374746 int size_from = ff_sws_pixel_type_size(prev->type);
366 1374746 int size_to = ff_sws_pixel_type_size(op->type);
367 av_assert1(prev->convert.to == op->type);
368
2/2
✓ Branch 0 taken 445910 times.
✓ Branch 1 taken 928836 times.
1374746 if (size_from < size_to) {
369 445910 op->type = prev->type;
370 445910 ff_sws_op_list_remove_at(ops, n - 1, 1);
371 445910 goto retry;
372 }
373 }
374 9031181 break;
375 }
376 }
377
378 /* Apply all in-place optimizations (that do not re-order the list) */
379
2/2
✓ Branch 0 taken 67670799 times.
✓ Branch 1 taken 3215710 times.
70886509 for (int n = 0; n < ops->num_ops; n++) {
380 67670799 SwsOp dummy = {0};
381 67670799 SwsOp *op = &ops->ops[n];
382
2/2
✓ Branch 0 taken 55755620 times.
✓ Branch 1 taken 11915179 times.
67670799 SwsOp *prev = n ? &ops->ops[n - 1] : &dummy;
383
2/2
✓ Branch 0 taken 64455089 times.
✓ Branch 1 taken 3215710 times.
67670799 SwsOp *next = n + 1 < ops->num_ops ? &ops->ops[n + 1] : &dummy;
384
385 /* common helper variable */
386 67670799 const SwsCompMask needed = ff_sws_comp_mask_needed(op);
387 67670799 bool noop = true;
388
389
4/4
✓ Branch 0 taken 3755338 times.
✓ Branch 1 taken 63915461 times.
✓ Branch 2 taken 539628 times.
✓ Branch 3 taken 3215710 times.
67670799 if (!needed && op->op != SWS_OP_WRITE) {
390 /* Remove any operation whose output is not needed */
391 539628 ff_sws_op_list_remove_at(ops, n, 1);
392 8699469 goto retry;
393 }
394
395
15/15
✓ Branch 0 taken 11215635 times.
✓ Branch 1 taken 4980367 times.
✓ Branch 2 taken 1898165 times.
✓ Branch 3 taken 980780 times.
✓ Branch 4 taken 3954580 times.
✓ Branch 5 taken 7323647 times.
✓ Branch 6 taken 7273589 times.
✓ Branch 7 taken 3109633 times.
✓ Branch 8 taken 2132801 times.
✓ Branch 9 taken 3362922 times.
✓ Branch 10 taken 6324867 times.
✓ Branch 11 taken 2706542 times.
✓ Branch 12 taken 6951704 times.
✓ Branch 13 taken 1174208 times.
✓ Branch 14 taken 3741731 times.
67131171 switch (op->op) {
396 11215635 case SWS_OP_READ:
397 /* "Compress" planar reads where not all components are needed */
398
2/2
✓ Branch 0 taken 6652655 times.
✓ Branch 1 taken 4562980 times.
11215635 if (op->rw.mode == SWS_RW_PLANAR) {
399 6652655 SwsSwizzleOp swiz = SWS_SWIZZLE(0, 1, 2, 3);
400 6652655 int nb_planes = 0;
401
2/2
✓ Branch 0 taken 16888084 times.
✓ Branch 1 taken 6652655 times.
23540739 for (int i = 0; i < op->rw.elems; i++) {
402
2/2
✓ Branch 0 taken 98039 times.
✓ Branch 1 taken 16790045 times.
16888084 if (!SWS_OP_NEEDED(op, i)) {
403 98039 swiz.in[i] = 3 - (i - nb_planes); /* map to unused plane */
404 98039 continue;
405 }
406
407 16790045 const int idx = nb_planes++;
408 av_assert1(idx <= i);
409 16790045 ops->plane_src[idx] = ops->plane_src[i];
410 16790045 swiz.in[i] = idx;
411 }
412
413
2/2
✓ Branch 0 taken 82180 times.
✓ Branch 1 taken 6570475 times.
6652655 if (nb_planes < op->rw.elems) {
414 82180 op->rw.elems = nb_planes;
415
3/4
✓ Branch 0 taken 4443 times.
✓ Branch 1 taken 77737 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 82180 times.
82180 RET(ff_sws_op_list_insert_at(ops, n + 1, &(SwsOp) {
416 .op = SWS_OP_SWIZZLE,
417 .type = op->rw.filter.op ? op->rw.filter.type : op->type,
418 .swizzle = swiz,
419 }));
420 82180 goto retry;
421 }
422 }
423 11133455 break;
424
425 4980367 case SWS_OP_SWAP_BYTES:
426 /* Redundant (double) swap */
427
2/2
✓ Branch 0 taken 1107 times.
✓ Branch 1 taken 4979260 times.
4980367 if (next->op == SWS_OP_SWAP_BYTES) {
428 1107 ff_sws_op_list_remove_at(ops, n, 2);
429 1107 goto retry;
430 }
431 4979260 break;
432
433 1898165 case SWS_OP_UNPACK:
434 /* Redundant unpack+pack */
435
3/4
✓ Branch 0 taken 258 times.
✓ Branch 1 taken 1897907 times.
✓ Branch 2 taken 258 times.
✗ Branch 3 not taken.
1898165 if (next->op == SWS_OP_PACK && next->type == op->type &&
436
1/2
✓ Branch 0 taken 258 times.
✗ Branch 1 not taken.
258 next->pack.pattern[0] == op->pack.pattern[0] &&
437
1/2
✓ Branch 0 taken 258 times.
✗ Branch 1 not taken.
258 next->pack.pattern[1] == op->pack.pattern[1] &&
438
1/2
✓ Branch 0 taken 258 times.
✗ Branch 1 not taken.
258 next->pack.pattern[2] == op->pack.pattern[2] &&
439
1/2
✓ Branch 0 taken 258 times.
✗ Branch 1 not taken.
258 next->pack.pattern[3] == op->pack.pattern[3])
440 {
441 258 ff_sws_op_list_remove_at(ops, n, 2);
442 258 goto retry;
443 }
444 1897907 break;
445
446 980780 case SWS_OP_LSHIFT:
447 case SWS_OP_RSHIFT:
448 /* Two shifts in the same direction */
449
2/2
✓ Branch 0 taken 1044 times.
✓ Branch 1 taken 979736 times.
980780 if (next->op == op->op) {
450 1044 op->shift.amount += next->shift.amount;
451 1044 ff_sws_op_list_remove_at(ops, n + 1, 1);
452 1044 goto retry;
453 }
454
455 /* No-op shift */
456
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 979736 times.
979736 if (!op->shift.amount) {
457 ✗ ff_sws_op_list_remove_at(ops, n, 1);
458 ✗ goto retry;
459 }
460 979736 break;
461
462 3954580 case SWS_OP_CLEAR:
463
2/2
✓ Branch 0 taken 15818320 times.
✓ Branch 1 taken 3954580 times.
19772900 for (int i = 0; i < 4; i++) {
464
2/2
✓ Branch 0 taken 10621399 times.
✓ Branch 1 taken 5196921 times.
15818320 if (!SWS_COMP_TEST(op->clear.mask, i))
465 10621399 continue;
466
467
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5196921 times.
5196921 if ((prev->comps.flags[i] & SWS_COMP_ZERO) &&
468 ✗ !(prev->comps.flags[i] & SWS_COMP_GARBAGE) &&
469 ✗ op->clear.value[i].num == 0)
470 {
471 /* Redundant clear-to-zero of zero component */
472 ✗ op->clear.mask ^= SWS_COMP(i);
473
2/2
✓ Branch 0 taken 830798 times.
✓ Branch 1 taken 4366123 times.
5196921 } else if (!SWS_OP_NEEDED(op, i)) {
474 /* Unnecessary clear of unused component */
475 830798 op->clear.mask ^= SWS_COMP(i);
476 } else {
477 4366123 noop = false;
478 }
479 }
480
481
2/2
✓ Branch 0 taken 754692 times.
✓ Branch 1 taken 3199888 times.
3954580 if (noop) {
482 754692 ff_sws_op_list_remove_at(ops, n, 1);
483 754692 goto retry;
484 }
485
486 /* Transitive clear */
487
2/2
✓ Branch 0 taken 3090 times.
✓ Branch 1 taken 3196798 times.
3199888 if (next->op == SWS_OP_CLEAR) {
488
2/2
✓ Branch 0 taken 12360 times.
✓ Branch 1 taken 3090 times.
15450 for (int i = 0; i < 4; i++) {
489
2/2
✓ Branch 0 taken 3090 times.
✓ Branch 1 taken 9270 times.
12360 if (SWS_COMP_TEST(next->clear.mask, i))
490 3090 op->clear.value[i] = next->clear.value[i];
491 }
492 3090 op->clear.mask |= next->clear.mask;
493 3090 ff_sws_op_list_remove_at(ops, n + 1, 1);
494 3090 goto retry;
495 }
496
497 /* Fold into linear op */
498
2/2
✓ Branch 0 taken 11141 times.
✓ Branch 1 taken 3185657 times.
3196798 if (next->op == SWS_OP_LINEAR) {
499
2/2
✓ Branch 0 taken 44564 times.
✓ Branch 1 taken 11141 times.
55705 for (int j = 0; j < 4; j++) {
500
2/2
✓ Branch 0 taken 24737 times.
✓ Branch 1 taken 19827 times.
44564 if (!SWS_COMP_TEST(op->clear.mask, j))
501 24737 continue;
502
503 19827 const AVRational64 x = op->clear.value[j];
504
2/2
✓ Branch 0 taken 79308 times.
✓ Branch 1 taken 19827 times.
99135 for (int i = 0; i < 4; i++) {
505 79308 const AVRational64 kx = ff_mul_q64(next->lin.m[i][j], x);
506 79308 next->lin.m[i][4] = ff_add_q64(next->lin.m[i][4], kx);
507 79308 next->lin.m[i][j] = Q(0);
508 }
509 }
510
511 11141 ff_sws_op_list_remove_at(ops, n, 1);
512 11141 goto retry;
513 }
514 3185657 break;
515
516 7323647 case SWS_OP_SWIZZLE:
517
2/2
✓ Branch 0 taken 29294588 times.
✓ Branch 1 taken 7323647 times.
36618235 for (int i = 0; i < 4; i++) {
518
2/2
✓ Branch 0 taken 7273094 times.
✓ Branch 1 taken 22021494 times.
29294588 if (!SWS_OP_NEEDED(op, i))
519 7273094 continue;
520
2/2
✓ Branch 0 taken 15039488 times.
✓ Branch 1 taken 6982006 times.
22021494 if (op->swizzle.in[i] != i)
521 15039488 noop = false;
522 }
523
524 /* Identity swizzle */
525
2/2
✓ Branch 0 taken 1142950 times.
✓ Branch 1 taken 6180697 times.
7323647 if (noop) {
526 1142950 ff_sws_op_list_remove_at(ops, n, 1);
527 1142950 goto retry;
528 }
529
530 /* Transitive swizzle */
531
2/2
✓ Branch 0 taken 121154 times.
✓ Branch 1 taken 6059543 times.
6180697 if (next->op == SWS_OP_SWIZZLE) {
532 121154 const SwsSwizzleOp orig = op->swizzle;
533
2/2
✓ Branch 0 taken 484616 times.
✓ Branch 1 taken 121154 times.
605770 for (int i = 0; i < 4; i++)
534 484616 op->swizzle.in[i] = orig.in[next->swizzle.in[i]];
535 121154 ff_sws_op_list_remove_at(ops, n + 1, 1);
536 121154 goto retry;
537 }
538
539 /* Swizzle planes instead of components, if possible */
540
4/4
✓ Branch 0 taken 888765 times.
✓ Branch 1 taken 5170778 times.
✓ Branch 2 taken 391619 times.
✓ Branch 3 taken 497146 times.
6059543 if (prev->op == SWS_OP_READ && prev->rw.mode == SWS_RW_PLANAR) {
541
2/2
✓ Branch 0 taken 546333 times.
✓ Branch 1 taken 107586 times.
653919 for (int dst = 0; dst < prev->rw.elems; dst++) {
542 546333 const int src = op->swizzle.in[dst];
543
4/4
✓ Branch 0 taken 294268 times.
✓ Branch 1 taken 252065 times.
✓ Branch 2 taken 284033 times.
✓ Branch 3 taken 10235 times.
546333 if (src > dst && src < prev->rw.elems) {
544 284033 FFSWAP(int, ops->plane_src[dst], ops->plane_src[src]);
545
2/2
✓ Branch 0 taken 1014761 times.
✓ Branch 1 taken 284033 times.
1298794 for (int i = dst; i < 4; i++) {
546
2/2
✓ Branch 0 taken 297283 times.
✓ Branch 1 taken 717478 times.
1014761 if (op->swizzle.in[i] == dst)
547 297283 op->swizzle.in[i] = src;
548
2/2
✓ Branch 0 taken 284033 times.
✓ Branch 1 taken 433445 times.
717478 else if (op->swizzle.in[i] == src)
549 284033 op->swizzle.in[i] = dst;
550 }
551 284033 goto retry;
552 }
553 }
554 }
555
556
4/4
✓ Branch 0 taken 863089 times.
✓ Branch 1 taken 4912421 times.
✓ Branch 2 taken 561309 times.
✓ Branch 3 taken 301780 times.
5775510 if (next->op == SWS_OP_WRITE && next->rw.mode == SWS_RW_PLANAR) {
557
2/2
✓ Branch 0 taken 771527 times.
✓ Branch 1 taken 166363 times.
937890 for (int dst = 0; dst < next->rw.elems; dst++) {
558 771527 const int src = op->swizzle.in[dst];
559
4/4
✓ Branch 0 taken 537859 times.
✓ Branch 1 taken 233668 times.
✓ Branch 2 taken 394946 times.
✓ Branch 3 taken 142913 times.
771527 if (src > dst && src < next->rw.elems) {
560 394946 FFSWAP(int, ops->plane_dst[dst], ops->plane_dst[src]);
561 394946 FFSWAP(int, op->swizzle.in[dst], op->swizzle.in[src]);
562 394946 goto retry;
563 }
564 }
565 }
566 5380564 break;
567
568 7273589 case SWS_OP_CONVERT:
569 /* No-op conversion */
570
2/2
✓ Branch 0 taken 193274 times.
✓ Branch 1 taken 7080315 times.
7273589 if (op->type == op->convert.to) {
571 193274 ff_sws_op_list_remove_at(ops, n, 1);
572 193274 goto retry;
573 }
574
575 /* Transitive conversion */
576
2/2
✓ Branch 0 taken 170467 times.
✓ Branch 1 taken 6909848 times.
7080315 if (next->op == SWS_OP_CONVERT) {
577 av_assert1(op->convert.to == next->type);
578 170467 op->convert.to = next->convert.to;
579 170467 ff_sws_op_list_remove_at(ops, n + 1, 1);
580 170467 goto retry;
581 }
582 6909848 break;
583
584 3109633 case SWS_OP_MIN:
585
2/2
✓ Branch 0 taken 12438532 times.
✓ Branch 1 taken 3109633 times.
15548165 for (int i = 0; i < 4; i++) {
586
4/4
✓ Branch 0 taken 9304363 times.
✓ Branch 1 taken 3134169 times.
✓ Branch 2 taken 543306 times.
✓ Branch 3 taken 8761057 times.
12438532 if (!SWS_OP_NEEDED(op, i) || !op->clamp.limit[i].den)
587 3677475 continue;
588
2/2
✓ Branch 1 taken 1073157 times.
✓ Branch 2 taken 7687900 times.
8761057 if (ff_cmp_q64(op->clamp.limit[i], prev->comps.max[i]) >= 0)
589 1073157 op->clamp.limit[i] = (AVRational64) {0}; /* no-op */
590 else
591 7687900 noop = false;
592 }
593
594
2/2
✓ Branch 0 taken 304779 times.
✓ Branch 1 taken 2804854 times.
3109633 if (noop) {
595 304779 ff_sws_op_list_remove_at(ops, n, 1);
596 304779 goto retry;
597 }
598 2804854 break;
599
600 2132801 case SWS_OP_MAX:
601
2/2
✓ Branch 0 taken 8531204 times.
✓ Branch 1 taken 2132801 times.
10664005 for (int i = 0; i < 4; i++) {
602
4/4
✓ Branch 0 taken 6370659 times.
✓ Branch 1 taken 2160545 times.
✓ Branch 2 taken 277261 times.
✓ Branch 3 taken 6093398 times.
8531204 if (!SWS_OP_NEEDED(op, i) || !op->clamp.limit[i].den)
603 2437806 continue;
604
2/2
✓ Branch 1 taken 1650693 times.
✓ Branch 2 taken 4442705 times.
6093398 if (ff_cmp_q64(prev->comps.min[i], op->clamp.limit[i]) >= 0)
605 1650693 op->clamp.limit[i] = (AVRational64) {0};
606 else
607 4442705 noop = false;
608 }
609
610
2/2
✓ Branch 0 taken 506079 times.
✓ Branch 1 taken 1626722 times.
2132801 if (noop) {
611 506079 ff_sws_op_list_remove_at(ops, n, 1);
612 506079 goto retry;
613 }
614 1626722 break;
615
616 3362922 case SWS_OP_DITHER:
617
2/2
✓ Branch 0 taken 13084822 times.
✓ Branch 1 taken 2739263 times.
15824085 for (int i = 0; i < 4; i++) {
618
2/2
✓ Branch 0 taken 3792101 times.
✓ Branch 1 taken 9292721 times.
13084822 if (op->dither.y_offset[i] < 0)
619 3792101 continue;
620
4/4
✓ Branch 0 taken 8855688 times.
✓ Branch 1 taken 437033 times.
✓ Branch 2 taken 186626 times.
✓ Branch 3 taken 8669062 times.
9292721 if (!SWS_OP_NEEDED(op, i) || (prev->comps.flags[i] & SWS_COMP_EXACT)) {
621 623659 op->dither.y_offset[i] = -1; /* unnecessary dither */
622 623659 goto retry;
623 } else {
624 8669062 noop = false;
625 }
626 }
627
628
2/2
✓ Branch 0 taken 12292 times.
✓ Branch 1 taken 2726971 times.
2739263 if (noop) {
629 12292 ff_sws_op_list_remove_at(ops, n, 1);
630 12292 goto retry;
631 }
632 2726971 break;
633
634 6324867 case SWS_OP_LINEAR: {
635 6324867 const uint32_t mask = ff_sws_linear_mask(&op->lin);
636 SwsSwizzleOp swizzle;
637 SwsClearOp clear;
638 SwsScaleOp scale;
639
640 /* No-op (identity) linear operation */
641
2/2
✓ Branch 0 taken 73254 times.
✓ Branch 1 taken 6251613 times.
6324867 if (!mask) {
642 73254 ff_sws_op_list_remove_at(ops, n, 1);
643 2946967 goto retry;
644 }
645
646
2/2
✓ Branch 0 taken 1441141 times.
✓ Branch 1 taken 4810472 times.
6251613 if (next->op == SWS_OP_LINEAR) {
647 /* 5x5 matrix multiplication after appending [ 0 0 0 0 1 ] */
648 1441141 const SwsLinearOp m1 = op->lin;
649 1441141 const SwsLinearOp m2 = next->lin;
650
2/2
✓ Branch 0 taken 5764564 times.
✓ Branch 1 taken 1441141 times.
7205705 for (int i = 0; i < 4; i++) {
651
2/2
✓ Branch 0 taken 28822820 times.
✓ Branch 1 taken 5764564 times.
34587384 for (int j = 0; j < 5; j++) {
652 28822820 AVRational64 sum = Q(0);
653
2/2
✓ Branch 0 taken 115291280 times.
✓ Branch 1 taken 28822820 times.
144114100 for (int k = 0; k < 4; k++)
654 115291280 sum = ff_add_q64(sum, ff_mul_q64(m2.m[i][k], m1.m[k][j]));
655
2/2
✓ Branch 0 taken 5764564 times.
✓ Branch 1 taken 23058256 times.
28822820 if (j == 4) /* m1.m[4][j] == 1 */
656 5764564 sum = ff_add_q64(sum, m2.m[i][4]);
657 28822820 op->lin.m[i][j] = sum;
658 }
659 }
660 1441141 ff_sws_op_list_remove_at(ops, n + 1, 1);
661 1441141 goto retry;
662 }
663
664 /* Optimize away zero columns */
665
2/2
✓ Branch 0 taken 18980822 times.
✓ Branch 1 taken 4536129 times.
23516951 for (int j = 0; j < 4; j++) {
666 18980822 const uint32_t col = SWS_MASK_COL(j);
667
4/4
✓ Branch 0 taken 895510 times.
✓ Branch 1 taken 18085312 times.
✓ Branch 2 taken 621167 times.
✓ Branch 3 taken 274343 times.
18980822 if (!(prev->comps.flags[j] & SWS_COMP_ZERO) || !(mask & col))
668 18706479 continue;
669
2/2
✓ Branch 0 taken 1097372 times.
✓ Branch 1 taken 274343 times.
1371715 for (int i = 0; i < 4; i++)
670 1097372 op->lin.m[i][j] = Q(i == j);
671 274343 goto retry;
672 }
673
674 /* Optimize away unused rows */
675
2/2
✓ Branch 0 taken 17860974 times.
✓ Branch 1 taken 3929111 times.
21790085 for (int i = 0; i < 4; i++) {
676 17860974 const uint32_t row = SWS_MASK_ROW(i);
677
4/4
✓ Branch 0 taken 5592567 times.
✓ Branch 1 taken 12268407 times.
✓ Branch 2 taken 4985549 times.
✓ Branch 3 taken 607018 times.
17860974 if (SWS_OP_NEEDED(op, i) || !(mask & row))
678 17253956 continue;
679
2/2
✓ Branch 0 taken 3035090 times.
✓ Branch 1 taken 607018 times.
3642108 for (int j = 0; j < 5; j++)
680 3035090 op->lin.m[i][j] = Q(i == j);
681 607018 goto retry;
682 }
683
684 /* Convert constant rows to explicit clear instruction */
685
2/2
✓ Branch 1 taken 197945 times.
✓ Branch 2 taken 3731166 times.
3929111 if (extract_constant_rows(&op->lin, &prev->comps, &clear)) {
686
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 197945 times.
197945 RET(ff_sws_op_list_insert_at(ops, n + 1, &(SwsOp) {
687 .op = SWS_OP_CLEAR,
688 .type = op->type,
689 .comps = op->comps,
690 .clear = clear,
691 }));
692 197945 goto retry;
693 }
694
695 /* Multiplication by scalar constant */
696
2/2
✓ Branch 1 taken 287008 times.
✓ Branch 2 taken 3444158 times.
3731166 if (extract_scalar(&op->lin, &op->comps, &prev->comps, &scale)) {
697 287008 op->op = SWS_OP_SCALE;
698 287008 op->scale = scale;
699 287008 goto retry;
700 }
701
702 /* Swizzle by fixed pattern */
703
2/2
✓ Branch 1 taken 66258 times.
✓ Branch 2 taken 3377900 times.
3444158 if (extract_swizzle(&op->lin, &prev->comps, &swizzle)) {
704
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 66258 times.
66258 RET(ff_sws_op_list_insert_at(ops, n, &(SwsOp) {
705 .op = SWS_OP_SWIZZLE,
706 .type = op->type,
707 .swizzle = swizzle,
708 }));
709 66258 goto retry;
710 }
711 3377900 break;
712 }
713
714 2706542 case SWS_OP_SCALE: {
715 2706542 const int factor2 = exact_log2_q64(op->scale.factor);
716
717 /* No-op scaling */
718
3/4
✓ Branch 0 taken 496784 times.
✓ Branch 1 taken 2209758 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 496784 times.
2706542 if (op->scale.factor.num == 1 && op->scale.factor.den == 1) {
719 ✗ ff_sws_op_list_remove_at(ops, n, 1);
720 ✗ goto retry;
721 }
722
723 /* Merge consecutive scaling operations */
724
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2706542 times.
2706542 if (next->op == SWS_OP_SCALE) {
725 ✗ op->scale.factor = ff_mul_q64(op->scale.factor, next->scale.factor);
726 ✗ ff_sws_op_list_remove_at(ops, n + 1, 1);
727 ✗ goto retry;
728 }
729
730 /* Scaling by exact power of two */
731
4/4
✓ Branch 0 taken 424477 times.
✓ Branch 1 taken 2282065 times.
✓ Branch 2 taken 5082 times.
✓ Branch 3 taken 419395 times.
2706542 if (factor2 && ff_sws_pixel_type_is_int(op->type)) {
732
1/2
✓ Branch 0 taken 5082 times.
✗ Branch 1 not taken.
5082 op->op = factor2 > 0 ? SWS_OP_LSHIFT : SWS_OP_RSHIFT;
733 5082 op->shift.amount = FFABS(factor2);
734 5082 goto retry;
735 }
736 2701460 break;
737 }
738
739 6951704 case SWS_OP_FILTER_H:
740 case SWS_OP_FILTER_V:
741 /* Merge with prior simple planar read */
742
4/4
✓ Branch 0 taken 2114957 times.
✓ Branch 1 taken 4836747 times.
✓ Branch 2 taken 1584158 times.
✓ Branch 3 taken 530799 times.
6951704 if (prev->op == SWS_OP_READ && !prev->rw.filter.op &&
743
4/4
✓ Branch 0 taken 665783 times.
✓ Branch 1 taken 918375 times.
✓ Branch 2 taken 599909 times.
✓ Branch 3 taken 65874 times.
1584158 prev->rw.mode == SWS_RW_PLANAR && !prev->rw.frac) {
744 599909 prev->rw.filter.op = op->op;
745 599909 prev->rw.filter.kernel = av_refstruct_ref(op->filter.kernel);
746 599909 prev->rw.filter.type = op->filter.type;
747 599909 ff_sws_op_list_remove_at(ops, n, 1);
748 599909 goto retry;
749 }
750 6351795 break;
751
752 1174208 case SWS_OP_LUT_3D:
753 /* Eliminate unnecessary 3DLUT */
754
2/2
✓ Branch 0 taken 738 times.
✓ Branch 1 taken 1173470 times.
1174208 if (!(needed & SWS_COMP_ELEMS(3))) {
755 738 ff_sws_op_list_remove_at(ops, n, 1);
756 738 goto retry;
757 }
758 1173470 break;
759 }
760 }
761
762 /* Push clears to the back to void any unused components */
763
2/2
✓ Branch 0 taken 21954252 times.
✓ Branch 1 taken 2542297 times.
24496549 for (int n = 0; n < ops->num_ops - 1; n++) {
764 21954252 SwsOp *op = &ops->ops[n];
765 21954252 SwsOp *next = &ops->ops[n + 1];
766
767
2/2
✓ Branch 0 taken 1375911 times.
✓ Branch 1 taken 20578341 times.
21954252 switch (op->op) {
768 1375911 case SWS_OP_CLEAR:
769
2/2
✓ Branch 1 taken 673413 times.
✓ Branch 2 taken 702498 times.
1375911 if (op_commute_clear(op, next)) {
770 673413 FFSWAP(SwsOp, *op, *next);
771 673413 goto retry;
772 }
773 702498 break;
774 }
775 }
776
777 /* Apply any remaining preferential re-ordering optimizations; do these
778 * last because they are more likely to block other optimizations if done
779 * too aggressively */
780
2/2
✓ Branch 0 taken 14635154 times.
✓ Branch 1 taken 1795943 times.
16431097 for (int n = 0; n < ops->num_ops - 1; n++) {
781 14635154 SwsOp *op = &ops->ops[n];
782 14635154 SwsOp *next = &ops->ops[n + 1];
783
784
4/4
✓ Branch 0 taken 1621740 times.
✓ Branch 1 taken 856568 times.
✓ Branch 2 taken 1037859 times.
✓ Branch 3 taken 11118987 times.
14635154 switch (op->op) {
785 1621740 case SWS_OP_SWIZZLE: {
786 /* Try to push swizzles towards the output */
787
2/2
✓ Branch 1 taken 732311 times.
✓ Branch 2 taken 889429 times.
1621740 if (op_commute_swizzle(op, next)) {
788 732311 FFSWAP(SwsOp, *op, *next);
789 732311 goto retry;
790 }
791 889429 break;
792 }
793
794 856568 case SWS_OP_SCALE:
795 /* Exact integer multiplication */
796
4/4
✓ Branch 0 taken 206466 times.
✓ Branch 1 taken 650102 times.
✓ Branch 2 taken 27912 times.
✓ Branch 3 taken 178554 times.
856568 if (op->scale.factor.den == 1 && next->op == SWS_OP_CONVERT &&
797
3/4
✓ Branch 0 taken 27912 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9483 times.
✓ Branch 3 taken 18429 times.
55824 ff_sws_pixel_type_is_int(next->convert.to) &&
798 27912 op_result_is_exact(op))
799 {
800 9483 op->type = next->convert.to;
801 9483 FFSWAP(SwsOp, *op, *next);
802 9483 goto retry;
803 }
804 847085 break;
805
806 1037859 case SWS_OP_LINEAR:
807 /* Exact integer linear transformation */
808
2/2
✓ Branch 0 taken 158656 times.
✓ Branch 1 taken 879203 times.
1037859 if (next->op == SWS_OP_CONVERT &&
809
3/4
✓ Branch 0 taken 158656 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4560 times.
✓ Branch 3 taken 154096 times.
317312 ff_sws_pixel_type_is_int(next->convert.to) &&
810 158656 op_result_is_exact(op))
811 {
812 4560 op->type = next->convert.to;
813 4560 FFSWAP(SwsOp, *op, *next);
814 4560 goto retry;
815 }
816 1033299 break;
817 }
818 }
819
820 1795943 return 0;
821 }
822
823 134366 static int select_planes(SwsOpList *ops, SwsCompMask planes)
824 {
825 134366 SwsSwizzleOp swiz = SWS_SWIZZLE(0, 1, 2, 3);
826 134366 SwsOp *write = &ops->ops[ops->num_ops - 1];
827
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 134366 times.
134366 av_assert0(write->op == SWS_OP_WRITE);
828
829 134366 write->rw.elems = 0;
830
2/2
✓ Branch 0 taken 537464 times.
✓ Branch 1 taken 134366 times.
671830 for (int src = 0; src < 4; src++) {
831
2/2
✓ Branch 0 taken 277747 times.
✓ Branch 1 taken 259717 times.
537464 if (!SWS_COMP_TEST(planes, src))
832 277747 continue; /* plane not selected */
833 259717 const int dst = write->rw.elems++;
834 av_assert2(src >= dst);
835 259717 swiz.in[dst] = src;
836 259717 FFSWAP(int, ops->plane_dst[dst], ops->plane_dst[src]);
837 }
838
839 /* Insert swizzle to select desired planes */
840 134366 int ret = ff_sws_op_list_insert_at(ops, ops->num_ops - 1, &(SwsOp) {
841 .op = SWS_OP_SWIZZLE,
842 134366 .type = write->type,
843 .swizzle = swiz,
844 });
845
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 134366 times.
134366 if (ret < 0)
846 ✗ return ret;
847
848 /* The optimizer will take care of the rest */
849 134366 return ff_sws_op_list_optimize(ops);
850 }
851
852 1717714 int ff_sws_op_list_split_planes(SwsOpList *ops1, SwsOpList **out_ops2, SwsCompMask planes)
853 {
854 1717714 const SwsOp *write = ff_sws_op_list_output(ops1);
855
3/4
✓ Branch 0 taken 1717714 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 531587 times.
✓ Branch 3 taken 1186127 times.
1717714 if (!write || write->rw.mode != SWS_RW_PLANAR) {
856 531587 *out_ops2 = NULL;
857 531587 return 0;
858 }
859
860 1186127 const SwsCompMask full = SWS_COMP_ELEMS(write->rw.elems);
861 1186127 const SwsCompMask mask1 = planes & full;
862 1186127 const SwsCompMask mask2 = full ^ mask1;
863
4/4
✓ Branch 0 taken 134780 times.
✓ Branch 1 taken 1051347 times.
✓ Branch 2 taken 67597 times.
✓ Branch 3 taken 67183 times.
1186127 if (!mask1 || !mask2) {
864 /* Nothing to filter */
865 1118944 *out_ops2 = NULL;
866 1118944 return 0;
867 }
868
869 67183 SwsOpList *ops2 = ff_sws_op_list_duplicate(ops1);
870
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 67183 times.
67183 if (!ops2)
871 ✗ return AVERROR(ENOMEM);
872
873 int ret;
874
2/4
✓ Branch 1 taken 67183 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 67183 times.
134366 if ((ret = select_planes(ops1, mask1)) < 0 ||
875 67183 (ret = select_planes(ops2, mask2)) < 0)
876 {
877 ✗ ff_sws_op_list_free(&ops2);
878 ✗ return ret;
879 }
880
881 67183 *out_ops2 = ops2;
882 67183 return 0;
883 }
884
885 32560 int ff_sws_shuffle_mask(const SwsUOp *uop, int8_t shuffle[], int size)
886 {
887 32560 const SwsShuffleUOp *par = &uop->par.shuffle;
888 av_assert1(uop->uop == SWS_UOP_RW_SHUFFLE);
889 av_assert1(par->write_size <= sizeof(uop->data.shuffle.mask));
890 av_assert1(size <= INT8_MAX);
891
892 32560 const int num_groups = size / FFMAX(par->read_size, par->write_size);
893
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 32560 times.
32560 if (!num_groups)
894 ✗ return AVERROR(EINVAL);
895
896 32560 memset(shuffle, 0, size);
897
2/2
✓ Branch 0 taken 178194 times.
✓ Branch 1 taken 32560 times.
210754 for (int n = 0; n < num_groups; n++) {
898 178194 const int base_in = n * par->read_size;
899 178194 const int base_out = n * par->write_size;
900
2/2
✓ Branch 0 taken 420996 times.
✓ Branch 1 taken 178194 times.
599190 for (int i = 0; i < par->write_size; i++) {
901 420996 const int8_t idx = uop->data.shuffle.mask[i];
902 420996 shuffle[base_out + i] = idx + (idx >= 0) * base_in;
903 }
904 }
905
906 32560 return num_groups;
907 }
908
909 971 static bool pixel_is_repeating(SwsPixelType type, SwsPixel val)
910 {
911
3/4
✓ Branch 0 taken 471 times.
✓ Branch 1 taken 413 times.
✓ Branch 2 taken 87 times.
✗ Branch 3 not taken.
971 switch (ff_sws_pixel_type_size(type)) {
912 471 case 1: return true;
913 413 case 2: return val.u16 == val.u8 * 0x101ul;
914 87 case 4: return val.u32 == val.u8 * 0x1010101ul;
915 ✗ default: break;
916 }
917
918 ✗ av_unreachable("Invalid pixel type!");
919 return false;
920 }
921
922 886401 static int solve_shuffle(const SwsUOpList *const uops, SwsUOp *out)
923 {
924
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 886401 times.
886401 if (!uops->num_ops)
925 ✗ return AVERROR(EINVAL);
926 886401 const SwsUOp *read = &uops->ops[0];
927
3/3
✓ Branch 0 taken 134940 times.
✓ Branch 1 taken 234245 times.
✓ Branch 2 taken 517216 times.
886401 switch (read->uop) {
928 134940 case SWS_UOP_READ_PACKED:
929 134940 break;
930 234245 case SWS_UOP_READ_PLANAR:
931
2/2
✓ Branch 0 taken 116501 times.
✓ Branch 1 taken 117744 times.
234245 if (read->mask != SWS_COMP_ELEMS(1))
932 116501 return AVERROR(ENOTSUP);
933 117744 break;
934 517216 default:
935 517216 return AVERROR(ENOTSUP);
936 }
937
938 252684 const int read_size = ff_sws_pixel_type_size(read->type);
939 252684 uint32_t mask[4] = {0};
940 252684 int clear_val = -1;
941 252684 int read_elems = 0;
942
2/2
✓ Branch 0 taken 1010736 times.
✓ Branch 1 taken 252684 times.
1263420 for (int i = 0; i < 4; i++) {
943
2/2
✓ Branch 0 taken 588663 times.
✓ Branch 1 taken 422073 times.
1010736 if (SWS_COMP_TEST(read->mask, i)) {
944 588663 mask[i] = 0x01010101 * i * read_size + 0x03020100;
945 588663 read_elems++;
946 }
947 }
948
949
1/2
✓ Branch 0 taken 373081 times.
✗ Branch 1 not taken.
373081 for (int opidx = 1; opidx < uops->num_ops; opidx++) {
950 373081 const SwsUOp *uop = &uops->ops[opidx];
951 373081 const SwsUOpParams *par = &uop->par;
952
7/7
✓ Branch 0 taken 17730 times.
✓ Branch 1 taken 101011 times.
✓ Branch 2 taken 966 times.
✓ Branch 3 taken 808 times.
✓ Branch 4 taken 111804 times.
✓ Branch 5 taken 1903 times.
✓ Branch 6 taken 138859 times.
373081 switch (uop->uop) {
953 17730 case SWS_UOP_COPY:
954 case SWS_UOP_PERMUTE: {
955 uint32_t tmp;
956
2/2
✓ Branch 0 taken 21848 times.
✓ Branch 1 taken 17730 times.
39578 for (int i = 0; i < par->move.num_moves; i++) {
957 21848 const int dst_idx = par->move.dst[i];
958 21848 const int src_idx = par->move.src[i];
959
2/2
✓ Branch 0 taken 819 times.
✓ Branch 1 taken 21029 times.
21848 uint32_t *src = src_idx < 0 ? &tmp : &mask[src_idx];
960
2/2
✓ Branch 0 taken 819 times.
✓ Branch 1 taken 21029 times.
21848 uint32_t *dst = dst_idx < 0 ? &tmp : &mask[dst_idx];
961 21848 *dst = *src;
962 }
963 17730 break;
964 }
965
966 101011 case SWS_UOP_SWAP_BYTES:
967
2/2
✓ Branch 0 taken 404044 times.
✓ Branch 1 taken 101011 times.
505055 for (int i = 0; i < 4; i++) {
968
2/3
✓ Branch 0 taken 280004 times.
✓ Branch 1 taken 124040 times.
✗ Branch 2 not taken.
404044 switch (ff_sws_pixel_type_size(uop->type)) {
969 280004 case 2: mask[i] = av_bswap16(mask[i]); break;
970 124040 case 4: mask[i] = av_bswap32(mask[i]); break;
971 }
972 }
973 101011 break;
974
975 966 case SWS_UOP_CLEAR:
976
2/2
✓ Branch 0 taken 3824 times.
✓ Branch 1 taken 848 times.
4672 for (int i = 0; i < 4; i++) {
977
2/2
✓ Branch 0 taken 2853 times.
✓ Branch 1 taken 971 times.
3824 if (!SWS_COMP_TEST(uop->mask, i))
978 2853 continue;
979 971 SwsPixel val = uop->data.vec4[i];
980
4/4
✓ Branch 1 taken 853 times.
✓ Branch 2 taken 118 times.
✓ Branch 3 taken 5 times.
✓ Branch 4 taken 848 times.
971 if (!pixel_is_repeating(uop->type, val) ||
981
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 (clear_val >= 0 && clear_val != val.u8))
982 118 return AVERROR(ENOTSUP); /* would require different bytes */
983 853 mask[i] = 0xFFFFFFFFul; /* (uint8_t[4]) { -1, -1, -1, -1 } */
984 853 clear_val = val.u8;
985 }
986 848 break;
987
988 808 case SWS_UOP_EXPAND_PAIR:
989 case SWS_UOP_EXPAND_QUAD:
990
2/2
✓ Branch 0 taken 3232 times.
✓ Branch 1 taken 808 times.
4040 for (int i = 0; i < 4; i++)
991 3232 mask[i] = 0x01010101 * (mask[i] & 0xFF);
992 808 break;
993
994 111804 case SWS_UOP_WRITE_PLANAR:
995
2/2
✓ Branch 0 taken 83794 times.
✓ Branch 1 taken 28010 times.
111804 if (uop->mask != SWS_COMP_ELEMS(1))
996 83794 return AVERROR(ENOTSUP);
997 av_fallthrough;
998 case SWS_UOP_WRITE_PACKED: {
999 29913 const int write_elems = av_popcount(uop->mask);
1000 29913 const int write_size = ff_sws_pixel_type_size(uop->type);
1001 29913 *out = (SwsUOp) {
1002 .uop = SWS_UOP_RW_SHUFFLE,
1003 .type = SWS_PIXEL_U8,
1004 .mask = SWS_COMP_ELEMS(1), /* single plane for now */
1005 };
1006
1007 29913 SwsShuffleUOp *par = &out->par.shuffle;
1008 29913 SwsShuffleMask *data = &out->data.shuffle;
1009 29913 *par = (SwsShuffleUOp) {
1010 .read_size = read_elems * read_size,
1011 .write_size = write_elems * write_size,
1012 29913 .clear_value = clear_val >= 0 ? clear_val : 0,
1013 };
1014
1015 /* Generate baseline shuffle for a single pixel */
1016 29913 data->pixels = 1;
1017
2/2
✓ Branch 0 taken 34778 times.
✓ Branch 1 taken 29913 times.
64691 for (int i = 0; i < write_elems; i++) {
1018 34778 const int offset = i * write_size;
1019
2/2
✓ Branch 0 taken 77067 times.
✓ Branch 1 taken 34778 times.
111845 for (int b = 0; b < write_size; b++)
1020 77067 data->mask[offset + b] = mask[i] >> (b * 8);
1021 }
1022
1023 /* Expand as many times as needed to round up to the size of the
1024 * shuffle uop data mask */
1025 int8_t tmp[FF_ARRAY_ELEMS(data->mask)];
1026 29913 const int num_groups = ff_sws_shuffle_mask(out, tmp, sizeof(tmp));
1027
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 29913 times.
29913 if (num_groups < 0)
1028 ✗ return num_groups;
1029 29913 memcpy(data->mask, tmp, sizeof(tmp));
1030 29913 par->read_size *= num_groups;
1031 29913 par->write_size *= num_groups;
1032 29913 data->pixels = num_groups;
1033 29913 return 0;
1034 }
1035
1036 138859 default:
1037 138859 return AVERROR(ENOTSUP);
1038 }
1039 }
1040
1041 ✗ return AVERROR(EINVAL);
1042 }
1043
1044 /* Only checks exact integer scale ops */
1045 497814 static bool is_scale(const SwsUOp *op, int64_t val)
1046 {
1047
2/2
✓ Branch 0 taken 52554 times.
✓ Branch 1 taken 445260 times.
497814 if (op->uop != SWS_UOP_SCALE)
1048 52554 return false;
1049
1050
4/4
✓ Branch 0 taken 739 times.
✓ Branch 1 taken 4658 times.
✓ Branch 2 taken 478 times.
✓ Branch 3 taken 439385 times.
445260 switch (op->type) {
1051 739 case SWS_PIXEL_U8: return op->data.scalar.u8 == val;
1052 4658 case SWS_PIXEL_U16: return op->data.scalar.u16 == val;
1053 478 case SWS_PIXEL_U32: return op->data.scalar.u32 == val;
1054 439385 default: return false;
1055 }
1056 }
1057
1058 1919274 int ff_sws_uop_list_optimize(SwsContext *ctx, SwsUOpFlags flags, SwsUOpList *uops)
1059 {
1060 static const SwsUOp dummy = {0};
1061
1062 2697 retry:
1063
2/2
✓ Branch 0 taken 10497920 times.
✓ Branch 1 taken 1919274 times.
12417194 for (int i = 0; i < uops->num_ops; i++) {
1064
2/2
✓ Branch 0 taken 8578646 times.
✓ Branch 1 taken 1919274 times.
10497920 const SwsUOp *next = i < uops->num_ops - 1 ? &uops->ops[i + 1] : &dummy;
1065 10497920 SwsUOp *op = &uops->ops[i];
1066
1067
4/4
✓ Branch 0 taken 661384 times.
✓ Branch 1 taken 61272 times.
✓ Branch 2 taken 446974 times.
✓ Branch 3 taken 9328290 times.
10497920 switch (op->uop) {
1068 661384 case SWS_UOP_TO_U16:
1069
4/4
✓ Branch 0 taken 54408 times.
✓ Branch 1 taken 606976 times.
✓ Branch 3 taken 2332 times.
✓ Branch 4 taken 52076 times.
661384 if (ff_sws_pixel_type_is_int(op->type) && is_scale(next, 0x101)) {
1070 2332 op->uop = SWS_UOP_EXPAND_PAIR;
1071 2332 ff_sws_uop_list_remove_at(uops, i + 1, 1);
1072 2332 goto retry;
1073 }
1074 659052 break;
1075
1076 61272 case SWS_UOP_TO_U32:
1077
3/4
✓ Branch 0 taken 1328 times.
✓ Branch 1 taken 59944 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1328 times.
61272 if (ff_sws_pixel_type_is_int(op->type) && is_scale(next, 0x1010101)) {
1078 ✗ op->uop = SWS_UOP_EXPAND_QUAD;
1079 ✗ ff_sws_uop_list_remove_at(uops, i + 1, 1);
1080 ✗ goto retry;
1081 }
1082 61272 break;
1083
1084 446974 case SWS_UOP_SCALE:
1085
2/2
✓ Branch 0 taken 442078 times.
✓ Branch 1 taken 4896 times.
446974 if (flags & SWS_UOP_FLAG_EXPAND_BIT) {
1086 442078 const int bits = 8 * ff_sws_pixel_type_size(op->type);
1087
2/2
✓ Branch 1 taken 365 times.
✓ Branch 2 taken 441713 times.
442078 if (is_scale(op, UINT64_MAX >> (64 - bits))) {
1088 365 op->uop = SWS_UOP_EXPAND_BIT;
1089 365 memset(&op->par, 0, sizeof(op->par));
1090 365 goto retry;
1091 }
1092 }
1093 446609 break;
1094 }
1095 }
1096
1097 /* Try promoting the entire uop list to a packed shuffle operation */
1098
2/2
✓ Branch 0 taken 886401 times.
✓ Branch 1 taken 1032873 times.
1919274 if (flags & SWS_UOP_FLAG_PSHUFB) {
1099 SwsUOp shuffle;
1100 886401 int ret = solve_shuffle(uops, &shuffle);
1101
2/2
✓ Branch 0 taken 29913 times.
✓ Branch 1 taken 856488 times.
886401 if (ret >= 0) {
1102 29913 ff_sws_uop_list_remove_at(uops, 0, uops->num_ops);
1103 29913 return ff_sws_uop_list_append(uops, &shuffle);
1104
2/4
✓ Branch 0 taken 856488 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 856488 times.
856488 } else if (ret < 0 && ret != AVERROR(ENOTSUP)) {
1105 ✗ return ret;
1106 }
1107 }
1108
1109 1889361 return 0;
1110 }
1111
1112 /**
1113 * Determine a suitable intermediate buffer format for a given combination
1114 * of pixel types and number of planes. The exact interpretation of these
1115 * formats does not matter at all; since they will only ever be used as
1116 * temporary intermediate buffers. We still need to pick *some* format as
1117 * a consequence of ff_sws_graph_add_pass() taking an AVPixelFormat for the
1118 * output buffer.
1119 */
1120 481793 static enum AVPixelFormat get_planar_fmt(SwsPixelType type, int nb_planes)
1121 {
1122
3/4
✓ Branch 0 taken 120387 times.
✓ Branch 1 taken 180364 times.
✓ Branch 2 taken 181042 times.
✗ Branch 3 not taken.
481793 switch (ff_sws_pixel_type_size(type)) {
1123 120387 case 1:
1124
4/5
✓ Branch 0 taken 10138 times.
✓ Branch 1 taken 1505 times.
✓ Branch 2 taken 99654 times.
✓ Branch 3 taken 9090 times.
✗ Branch 4 not taken.
120387 switch (nb_planes) {
1125 10138 case 1: return AV_PIX_FMT_GRAY8;
1126 1505 case 2: return AV_PIX_FMT_YUV444P; // FIXME: no 2-plane planar fmt
1127 99654 case 3: return AV_PIX_FMT_YUV444P;
1128 9090 case 4: return AV_PIX_FMT_YUVA444P;
1129 }
1130 ✗ break;
1131 180364 case 2:
1132
4/5
✓ Branch 0 taken 28379 times.
✓ Branch 1 taken 2925 times.
✓ Branch 2 taken 132884 times.
✓ Branch 3 taken 16176 times.
✗ Branch 4 not taken.
180364 switch (nb_planes) {
1133 28379 case 1: return AV_PIX_FMT_GRAY16;
1134 2925 case 2: return AV_PIX_FMT_YUV444P16; // FIXME: no 2-plane planar fmt
1135 132884 case 3: return AV_PIX_FMT_YUV444P16;
1136 16176 case 4: return AV_PIX_FMT_YUVA444P16;
1137 }
1138 ✗ break;
1139 181042 case 4:
1140
4/5
✓ Branch 0 taken 32897 times.
✓ Branch 1 taken 5363 times.
✓ Branch 2 taken 123895 times.
✓ Branch 3 taken 18887 times.
✗ Branch 4 not taken.
181042 switch (nb_planes) {
1141 32897 case 1: return AV_PIX_FMT_GRAYF32;
1142 5363 case 2: return AV_PIX_FMT_GBRPF32; // FIXME: no 2-plane planar fmt
1143 123895 case 3: return AV_PIX_FMT_GBRPF32;
1144 18887 case 4: return AV_PIX_FMT_GBRAPF32;
1145 }
1146 ✗ break;
1147 }
1148
1149 ✗ av_unreachable("Invalid pixel type or number of planes?");
1150 return AV_PIX_FMT_NONE;
1151 }
1152
1153 481793 static void get_input_size(const SwsOpList *ops, SwsFormat *fmt)
1154 {
1155 481793 fmt->width = ops->src.width;
1156 481793 fmt->height = ops->src.height;
1157
1158 481793 const SwsOp *read = ff_sws_op_list_input(ops);
1159
2/4
✓ Branch 0 taken 481793 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 481793 times.
481793 if (read && read->rw.filter.op == SWS_OP_FILTER_V) {
1160 ✗ fmt->height = read->rw.filter.kernel->dst_size;
1161
3/4
✓ Branch 0 taken 481793 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 149359 times.
✓ Branch 3 taken 332434 times.
481793 } else if (read && read->rw.filter.op == SWS_OP_FILTER_H) {
1162 149359 fmt->width = read->rw.filter.kernel->dst_size;
1163 }
1164 481793 }
1165
1166 481793 int ff_sws_op_list_split_at(SwsOpList *ops1, SwsOpList **out_ops2, int index)
1167 {
1168 int ret;
1169
2/4
✓ Branch 0 taken 481793 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 481793 times.
481793 if (index <= 0 || index >= ops1->num_ops) {
1170 ✗ *out_ops2 = NULL;
1171 ✗ return 0;
1172 }
1173
1174 481793 const SwsOp *op = &ops1->ops[index];
1175 481793 const SwsOp *prev = &ops1->ops[index - 1];
1176
1177 481793 SwsOpList *ops2 = ff_sws_op_list_duplicate(ops1);
1178
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 481793 times.
481793 if (!ops2)
1179 ✗ return AVERROR(ENOMEM);
1180
1181 /**
1182 * Not all components may be needed; but we need the ones that *are*
1183 * used to be contiguous for the write/read operations. So, first
1184 * compress them into a linearly ascending list of components
1185 */
1186 481793 int nb_planes = 0;
1187 481793 SwsSwizzleOp swiz_wr = SWS_SWIZZLE(0, 1, 2, 3);
1188 481793 SwsSwizzleOp swiz_rd = SWS_SWIZZLE(0, 1, 2, 3);
1189
2/2
✓ Branch 0 taken 1927172 times.
✓ Branch 1 taken 481793 times.
2408965 for (int i = 0; i < 4; i++) {
1190
2/2
✓ Branch 0 taken 1336911 times.
✓ Branch 1 taken 590261 times.
1927172 if (SWS_OP_NEEDED(prev, i)) {
1191 1336911 const int o = nb_planes++;
1192 1336911 swiz_wr.in[o] = i;
1193 1336911 swiz_rd.in[i] = o;
1194 }
1195 }
1196
1197 /* Determine metadata for the intermediate format */
1198 481793 const SwsPixelType type = op->type;
1199 481793 ops2->src.format = get_planar_fmt(type, nb_planes);
1200 481793 ops2->src.desc = av_pix_fmt_desc_get(ops2->src.format);
1201 481793 get_input_size(ops1, &ops2->src);
1202 481793 ops1->dst = ops2->src;
1203
1204
2/2
✓ Branch 0 taken 1336911 times.
✓ Branch 1 taken 481793 times.
1818704 for (int i = 0; i < nb_planes; i++) {
1205 1336911 const int idx = swiz_wr.in[i];
1206 1336911 ops1->plane_dst[i] = ops2->plane_src[i] = i;
1207 1336911 ops2->comps_src.flags[i] = prev->comps.flags[idx];
1208 1336911 ops2->comps_src.min[i] = prev->comps.min[idx];
1209 1336911 ops2->comps_src.max[i] = prev->comps.max[idx];
1210 }
1211
1212 481793 ff_sws_op_list_remove_at(ops1, index, ops1->num_ops - index);
1213 481793 ff_sws_op_list_remove_at(ops2, 0, index);
1214 481793 op = NULL; /* the above command may invalidate op */
1215
1216
2/2
✓ Branch 0 taken 40669 times.
✓ Branch 1 taken 441124 times.
481793 if (swiz_wr.mask != SWS_SWIZZLE(0, 1, 2, 3).mask) {
1217 40669 ret = ff_sws_op_list_append(ops1, &(SwsOp) {
1218 .op = SWS_OP_SWIZZLE,
1219 .type = type,
1220 .swizzle = swiz_wr,
1221 });
1222
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 40669 times.
40669 if (ret < 0)
1223 ✗ goto fail;
1224 }
1225
1226 481793 ret = ff_sws_op_list_append(ops1, &(SwsOp) {
1227 .op = SWS_OP_WRITE,
1228 .type = type,
1229 .rw.elems = nb_planes,
1230 });
1231
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 481793 times.
481793 if (ret < 0)
1232 ✗ goto fail;
1233
1234 481793 ret = ff_sws_op_list_insert_at(ops2, 0, &(SwsOp) {
1235 .op = SWS_OP_READ,
1236 .type = type,
1237 .rw.elems = nb_planes,
1238 });
1239
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 481793 times.
481793 if (ret < 0)
1240 ✗ goto fail;
1241
1242
2/2
✓ Branch 0 taken 40669 times.
✓ Branch 1 taken 441124 times.
481793 if (swiz_rd.mask != SWS_SWIZZLE(0, 1, 2, 3).mask) {
1243 40669 ret = ff_sws_op_list_insert_at(ops2, 1, &(SwsOp) {
1244 .op = SWS_OP_SWIZZLE,
1245 .type = type,
1246 .swizzle = swiz_rd,
1247 });
1248
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 40669 times.
40669 if (ret < 0)
1249 ✗ goto fail;
1250 }
1251
1252 481793 ret = ff_sws_op_list_optimize(ops1);
1253
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 481793 times.
481793 if (ret < 0)
1254 ✗ goto fail;
1255
1256 481793 ret = ff_sws_op_list_optimize(ops2);
1257
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 481793 times.
481793 if (ret < 0)
1258 ✗ goto fail;
1259
1260 481793 *out_ops2 = ops2;
1261 481793 return 0;
1262
1263 ✗ fail:
1264 ✗ ff_sws_op_list_free(&ops2);
1265 ✗ return ret;
1266 }
1267