| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /** | ||
| 2 | * Copyright (C) 2026 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 <stdbool.h> | ||
| 22 | |||
| 23 | #include "libavutil/avassert.h" | ||
| 24 | #include "libavutil/mem.h" | ||
| 25 | #include "libavutil/refstruct.h" | ||
| 26 | |||
| 27 | #include "ops.h" | ||
| 28 | #include "uops.h" | ||
| 29 | #include "uops_list.h" | ||
| 30 | |||
| 31 | 152168309 | int ff_sws_uop_cmp(const SwsUOp *a, const SwsUOp *b) | |
| 32 | { | ||
| 33 |
2/2✓ Branch 0 taken 81967283 times.
✓ Branch 1 taken 70201026 times.
|
152168309 | if (a->type != b->type) |
| 34 | 81967283 | return (int) a->type - b->type; | |
| 35 |
2/2✓ Branch 0 taken 50131349 times.
✓ Branch 1 taken 20069677 times.
|
70201026 | if (a->uop != b->uop) |
| 36 | 50131349 | return (int) a->uop - b->uop; | |
| 37 |
2/2✓ Branch 0 taken 8730468 times.
✓ Branch 1 taken 11339209 times.
|
20069677 | if (a->mask != b->mask) |
| 38 | 8730468 | return (int) a->mask - b->mask; | |
| 39 | 11339209 | return memcmp(&a->par, &b->par, sizeof(a->par)); | |
| 40 | } | ||
| 41 | |||
| 42 | static const struct { | ||
| 43 | char abbr[32]; | ||
| 44 | } uop_names[SWS_UOP_TYPE_NB] = { | ||
| 45 | #define UOP_NAME(OP, ABBR) [OP] = { ABBR }, | ||
| 46 | UOPS_LIST(UOP_NAME) | ||
| 47 | #undef UOP_NAME | ||
| 48 | }; | ||
| 49 | |||
| 50 | 147787449 | static SwsPixel pixel_from_q64(SwsPixelType type, AVRational64 val) | |
| 51 | { | ||
| 52 | av_assert1(val.den != 0); | ||
| 53 |
4/6✓ Branch 0 taken 83367 times.
✓ Branch 1 taken 160586 times.
✓ Branch 2 taken 36464 times.
✓ Branch 3 taken 147507032 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
147787449 | switch (type) { |
| 54 | 147787449 | case SWS_PIXEL_U8: return (SwsPixel) { .u8 = val.num / val.den }; | |
| 55 | 160586 | case SWS_PIXEL_U16: return (SwsPixel) { .u16 = val.num / val.den }; | |
| 56 | 36464 | case SWS_PIXEL_U32: return (SwsPixel) { .u32 = val.num / val.den }; | |
| 57 | 147507032 | case SWS_PIXEL_F32: return (SwsPixel) { .f32 = (float) val.num / val.den }; | |
| 58 | ✗ | case SWS_PIXEL_NONE: | |
| 59 | ✗ | case SWS_PIXEL_TYPE_NB: break; | |
| 60 | } | ||
| 61 | |||
| 62 | ✗ | av_unreachable("Invalid pixel type!"); | |
| 63 | return (SwsPixel) {0}; | ||
| 64 | } | ||
| 65 | |||
| 66 | #define Q2PIXEL(val) pixel_from_q64(op->type, val) | ||
| 67 | |||
| 68 | 306265 | static bool pixel_is_1s(SwsPixelType type, SwsPixel val) | |
| 69 | { | ||
| 70 |
3/4✓ Branch 0 taken 46779 times.
✓ Branch 1 taken 130126 times.
✓ Branch 2 taken 129360 times.
✗ Branch 3 not taken.
|
306265 | switch (ff_sws_pixel_type_size(type)) { |
| 71 | 46779 | case 1: return val.u8 == UINT8_MAX; | |
| 72 | 130126 | case 2: return val.u16 == UINT16_MAX; | |
| 73 | 129360 | case 4: return val.u32 == UINT32_MAX; | |
| 74 | ✗ | default: break; | |
| 75 | } | ||
| 76 | |||
| 77 | ✗ | av_unreachable("Invalid pixel type!"); | |
| 78 | return false; | ||
| 79 | } | ||
| 80 | |||
| 81 | 1127637 | void ff_sws_uop_name(const SwsUOp *op, char buf[SWS_UOP_NAME_MAX]) | |
| 82 | { | ||
| 83 | AVBPrint bp; | ||
| 84 | 1127637 | av_bprint_init_for_buffer(&bp, buf, SWS_UOP_NAME_MAX); | |
| 85 | |||
| 86 |
1/2✓ Branch 0 taken 1127637 times.
✗ Branch 1 not taken.
|
1127637 | if (op->type != SWS_PIXEL_NONE) |
| 87 | 1127637 | av_bprintf(&bp, "%s_", ff_sws_pixel_type_name(op->type)); | |
| 88 | 1127637 | av_bprintf(&bp, "%s", uop_names[op->uop].abbr); | |
| 89 | |||
| 90 |
1/2✓ Branch 0 taken 1127637 times.
✗ Branch 1 not taken.
|
1127637 | if (op->mask) |
| 91 | 1127637 | av_bprintf(&bp, "_%s", ff_sws_comp_mask_str(op->mask)); | |
| 92 | |||
| 93 | 1127637 | const SwsUOpParams *par = &op->par; | |
| 94 |
10/10✓ Branch 0 taken 114278 times.
✓ Branch 1 taken 2609 times.
✓ Branch 2 taken 18014 times.
✓ Branch 3 taken 64587 times.
✓ Branch 4 taken 45109 times.
✓ Branch 5 taken 41264 times.
✓ Branch 6 taken 73360 times.
✓ Branch 7 taken 63659 times.
✓ Branch 8 taken 92 times.
✓ Branch 9 taken 704665 times.
|
1127637 | switch (op->uop) { |
| 95 | 114278 | case SWS_UOP_READ_PLANAR_FH: | |
| 96 | case SWS_UOP_READ_PLANAR_FV: | ||
| 97 | case SWS_UOP_READ_PLANAR_FV_FMA: | ||
| 98 | 114278 | av_bprintf(&bp, "_%s", ff_sws_pixel_type_name(par->filter.type)); | |
| 99 | 114278 | break; | |
| 100 | 2609 | case SWS_UOP_RW_SHUFFLE: | |
| 101 | 2609 | av_bprintf(&bp, "_%x_%u_%u", par->shuffle.clear_value, | |
| 102 | 2609 | par->shuffle.read_size, par->shuffle.write_size); | |
| 103 | 2609 | break; | |
| 104 | 18014 | case SWS_UOP_LSHIFT: | |
| 105 | case SWS_UOP_RSHIFT: | ||
| 106 | 18014 | av_bprintf(&bp, "_%u", par->shift.amount); | |
| 107 | 18014 | break; | |
| 108 | 64587 | case SWS_UOP_PERMUTE: | |
| 109 | case SWS_UOP_COPY: | ||
| 110 | 64587 | av_bprint_chars(&bp, '_', 1); | |
| 111 |
2/2✓ Branch 0 taken 172939 times.
✓ Branch 1 taken 64587 times.
|
237526 | for (int i = 0; i < par->move.num_moves; i++) |
| 112 | 172939 | av_bprint_chars(&bp, "txyzw"[par->move.dst[i] + 1], 1); | |
| 113 | 64587 | av_bprint_chars(&bp, '_', 1); | |
| 114 |
2/2✓ Branch 0 taken 172939 times.
✓ Branch 1 taken 64587 times.
|
237526 | for (int i = 0; i < par->move.num_moves; i++) |
| 115 | 172939 | av_bprint_chars(&bp, "txyzw"[par->move.src[i] + 1], 1); | |
| 116 | 64587 | break; | |
| 117 | 45109 | case SWS_UOP_PACK: | |
| 118 | case SWS_UOP_UNPACK: | ||
| 119 | 45109 | av_bprint_chars(&bp, '_', 1); | |
| 120 |
4/4✓ Branch 0 taken 180436 times.
✓ Branch 1 taken 14522 times.
✓ Branch 2 taken 149849 times.
✓ Branch 3 taken 30587 times.
|
194958 | for (int i = 0; i < 4 && par->pack.pattern[i]; i++) |
| 121 | 149849 | av_bprintf(&bp, "%x", par->pack.pattern[i]); | |
| 122 | 45109 | break; | |
| 123 | 41264 | case SWS_UOP_CLEAR: | |
| 124 | 41264 | av_bprint_chars(&bp, '_', 1); | |
| 125 |
2/2✓ Branch 0 taken 165056 times.
✓ Branch 1 taken 41264 times.
|
206320 | for (int i = 0; i < 4; i++) { |
| 126 |
2/2✓ Branch 0 taken 115080 times.
✓ Branch 1 taken 49976 times.
|
165056 | if (!SWS_COMP_TEST(op->mask, i)) |
| 127 | 115080 | continue; | |
| 128 |
2/2✓ Branch 0 taken 11754 times.
✓ Branch 1 taken 38222 times.
|
49976 | else if (SWS_COMP_TEST(par->clear.one, i)) |
| 129 | 11754 | av_bprint_chars(&bp, '1', 1); | |
| 130 |
2/2✓ Branch 0 taken 7723 times.
✓ Branch 1 taken 30499 times.
|
38222 | else if (SWS_COMP_TEST(par->clear.zero, i)) |
| 131 | 7723 | av_bprint_chars(&bp, '0', 1); | |
| 132 | else | ||
| 133 | 30499 | av_bprint_chars(&bp, 'x', 1); | |
| 134 | } | ||
| 135 | 41264 | break; | |
| 136 | 73360 | case SWS_UOP_LINEAR: | |
| 137 | case SWS_UOP_LINEAR_FMA: | ||
| 138 |
2/2✓ Branch 0 taken 293440 times.
✓ Branch 1 taken 73360 times.
|
366800 | for (int i = 0; i < 4; i++) { |
| 139 |
2/2✓ Branch 0 taken 107402 times.
✓ Branch 1 taken 186038 times.
|
293440 | if (!SWS_COMP_TEST(op->mask, i)) |
| 140 | 107402 | continue; | |
| 141 | 186038 | av_bprint_chars(&bp, '_', 1); | |
| 142 |
2/2✓ Branch 0 taken 930190 times.
✓ Branch 1 taken 186038 times.
|
1116228 | for (int j = 0; j < 5; j++) { |
| 143 |
2/2✓ Branch 0 taken 303 times.
✓ Branch 1 taken 929887 times.
|
930190 | if (par->lin.one & SWS_MASK(i, j)) |
| 144 | 303 | av_bprint_chars(&bp, '1', 1); | |
| 145 |
2/2✓ Branch 0 taken 385060 times.
✓ Branch 1 taken 544827 times.
|
929887 | else if (par->lin.zero & SWS_MASK(i, j)) |
| 146 | 385060 | av_bprint_chars(&bp, '0', 1); | |
| 147 |
2/2✓ Branch 0 taken 109220 times.
✓ Branch 1 taken 435607 times.
|
544827 | else if (par->lin.exact & SWS_MASK(i, j)) |
| 148 | 109220 | av_bprint_chars(&bp, 'X', 1); | |
| 149 | else | ||
| 150 | 435607 | av_bprint_chars(&bp, 'x', 1); | |
| 151 | } | ||
| 152 | } | ||
| 153 | 73360 | break; | |
| 154 | 63659 | case SWS_UOP_DITHER: | |
| 155 |
2/2✓ Branch 0 taken 254636 times.
✓ Branch 1 taken 63659 times.
|
318295 | for (int i = 0; i < 4; i++) { |
| 156 |
2/2✓ Branch 0 taken 171594 times.
✓ Branch 1 taken 83042 times.
|
254636 | if (SWS_COMP_TEST(op->mask, i)) |
| 157 | 171594 | av_bprintf(&bp, "_%d", par->dither.y_offset[i]); | |
| 158 | } | ||
| 159 | 63659 | const unsigned size = 1u << par->dither.size_log2; | |
| 160 | 63659 | av_bprintf(&bp, "_%ux%u", size, size); | |
| 161 | 63659 | break; | |
| 162 | 92 | case SWS_UOP_LUT_3D: | |
| 163 |
2/2✓ Branch 0 taken 46 times.
✓ Branch 1 taken 46 times.
|
92 | av_bprintf(&bp, "_%s", par->lut3d.dynamic ? "dynamic" : "static"); |
| 164 | 92 | break; | |
| 165 | } | ||
| 166 | |||
| 167 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1127637 times.
|
1127637 | av_assert0(av_bprint_is_complete(&bp)); |
| 168 | 1127637 | } | |
| 169 | |||
| 170 | 10793995 | static void uop_uninit(SwsUOp *uop) | |
| 171 | { | ||
| 172 |
4/4✓ Branch 0 taken 518245 times.
✓ Branch 1 taken 1101427 times.
✓ Branch 2 taken 280896 times.
✓ Branch 3 taken 8893427 times.
|
10793995 | switch (uop->uop) { |
| 173 | 518245 | case SWS_UOP_DITHER: | |
| 174 | 518245 | av_refstruct_unref(&uop->data.ptr); | |
| 175 | 518245 | break; | |
| 176 | 1101427 | case SWS_UOP_READ_PLANAR_FH: | |
| 177 | case SWS_UOP_READ_PLANAR_FV: | ||
| 178 | case SWS_UOP_READ_PLANAR_FV_FMA: | ||
| 179 | 1101427 | av_refstruct_unref(&uop->data.kernel); | |
| 180 | 1101427 | break; | |
| 181 | 280896 | case SWS_UOP_LUT_3D: | |
| 182 | 280896 | av_refstruct_unref(&uop->data.lut3d); | |
| 183 | 280896 | break; | |
| 184 | } | ||
| 185 | |||
| 186 | 10793995 | *uop = (SwsUOp) {0}; | |
| 187 | 10793995 | } | |
| 188 | |||
| 189 | 2292578 | void ff_sws_uop_list_free(SwsUOpList **p_ops) | |
| 190 | { | ||
| 191 | 2292578 | SwsUOpList *ops = *p_ops; | |
| 192 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2292578 times.
|
2292578 | if (!ops) |
| 193 | ✗ | return; | |
| 194 | |||
| 195 |
2/2✓ Branch 0 taken 10707492 times.
✓ Branch 1 taken 2292578 times.
|
13000070 | for (int i = 0; i < ops->num_ops; i++) |
| 196 | 10707492 | uop_uninit(&ops->ops[i]); | |
| 197 | |||
| 198 | 2292578 | av_freep(&ops->ops); | |
| 199 | 2292578 | av_free(ops); | |
| 200 | 2292578 | *p_ops = NULL; | |
| 201 | } | ||
| 202 | |||
| 203 | 2292578 | SwsUOpList *ff_sws_uop_list_alloc(void) | |
| 204 | { | ||
| 205 | 2292578 | return av_mallocz(sizeof(SwsUOpList)); | |
| 206 | } | ||
| 207 | |||
| 208 | 10793995 | int ff_sws_uop_list_append(SwsUOpList *uops, SwsUOp *uop) | |
| 209 | { | ||
| 210 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 10793995 times.
|
10793995 | if (!av_dynarray2_add((void **) &uops->ops, &uops->num_ops, |
| 211 | sizeof(*uop), (uint8_t *) uop)) | ||
| 212 | { | ||
| 213 | ✗ | uop_uninit(uop); | |
| 214 | ✗ | return AVERROR(ENOMEM); | |
| 215 | } | ||
| 216 | |||
| 217 | 10793995 | *uop = (SwsUOp) {0}; | |
| 218 | 10793995 | return 0; | |
| 219 | } | ||
| 220 | |||
| 221 | 29831 | void ff_sws_uop_list_remove_at(SwsUOpList *uops, int index, int count) | |
| 222 | { | ||
| 223 | 29831 | const int end = uops->num_ops - count; | |
| 224 | av_assert2(index >= 0 && count >= 0 && index + count <= uops->num_ops); | ||
| 225 |
2/2✓ Branch 0 taken 86503 times.
✓ Branch 1 taken 29831 times.
|
116334 | for (int i = 0; i < count; i++) |
| 226 | 86503 | uop_uninit(&uops->ops[index + i]); | |
| 227 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 29831 times.
|
29831 | for (int i = index; i < end; i++) |
| 228 | ✗ | uops->ops[i] = uops->ops[i + count]; | |
| 229 | 29831 | uops->num_ops = end; | |
| 230 | 29831 | } | |
| 231 | |||
| 232 | 522311 | int ff_sws_dither_height(const SwsDitherUOp *dither) | |
| 233 | { | ||
| 234 | 522311 | int max_offset = 0; | |
| 235 |
2/2✓ Branch 0 taken 2089244 times.
✓ Branch 1 taken 522311 times.
|
2611555 | for (int i = 0; i < 4; i++) |
| 236 | 2089244 | max_offset = FFMAX(max_offset, dither->y_offset[i]); | |
| 237 | 522311 | return (1 << dither->size_log2) + max_offset; | |
| 238 | } | ||
| 239 | |||
| 240 | 4751336 | static SwsPixelType pixel_type_to_int(const SwsPixelType type) | |
| 241 | { | ||
| 242 |
3/4✓ Branch 0 taken 910581 times.
✓ Branch 1 taken 2640357 times.
✓ Branch 2 taken 1200398 times.
✗ Branch 3 not taken.
|
4751336 | switch (ff_sws_pixel_type_size(type)) { |
| 243 | 910581 | case 1: return SWS_PIXEL_U8; | |
| 244 | 2640357 | case 2: return SWS_PIXEL_U16; | |
| 245 | 1200398 | case 4: return SWS_PIXEL_U32; | |
| 246 | ✗ | default: break; | |
| 247 | } | ||
| 248 | |||
| 249 | ✗ | av_unreachable("Invalid pixel type!"); | |
| 250 | return SWS_PIXEL_NONE; | ||
| 251 | } | ||
| 252 | |||
| 253 | 1583216 | static bool exact_product_f32(float a, float b) | |
| 254 | { | ||
| 255 | 1583216 | volatile float prod = a * b; | |
| 256 |
2/2✓ Branch 0 taken 801919 times.
✓ Branch 1 taken 781297 times.
|
1583216 | volatile float result = b ? prod / b : 0.0f; |
| 257 |
4/4✓ Branch 0 taken 801919 times.
✓ Branch 1 taken 781297 times.
✓ Branch 2 taken 797121 times.
✓ Branch 3 taken 4798 times.
|
1583216 | return !b || result == a; |
| 258 | } | ||
| 259 | |||
| 260 | 868434 | static bool exact_prod(SwsPixelType type, SwsPixel coef, | |
| 261 | const SwsComps *comps, int idx) | ||
| 262 | { | ||
| 263 | 868434 | const AVRational64 minq = comps->min[idx]; | |
| 264 | 868434 | const AVRational64 maxq = comps->max[idx]; | |
| 265 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 868434 times.
|
868434 | if (ff_sws_pixel_type_is_int(type)) |
| 266 | ✗ | return true; | |
| 267 |
3/4✓ Branch 0 taken 791844 times.
✓ Branch 1 taken 76590 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 791844 times.
|
868434 | else if (!minq.den || !maxq.den) |
| 268 | 76590 | return false; /* unknown bounds */ | |
| 269 | |||
| 270 | 791844 | const SwsPixel min = pixel_from_q64(type, minq); | |
| 271 | 791844 | const SwsPixel max = pixel_from_q64(type, maxq); | |
| 272 |
1/2✓ Branch 0 taken 791844 times.
✗ Branch 1 not taken.
|
791844 | switch (type) { |
| 273 | 791844 | case SWS_PIXEL_F32: | |
| 274 |
4/4✓ Branch 1 taken 791372 times.
✓ Branch 2 taken 472 times.
✓ Branch 3 taken 787046 times.
✓ Branch 4 taken 4326 times.
|
1583216 | return exact_product_f32(coef.f32, min.f32) && |
| 275 | 791372 | exact_product_f32(coef.f32, max.f32); | |
| 276 | } | ||
| 277 | |||
| 278 | ✗ | av_unreachable("Invalid pixel type!"); | |
| 279 | return false; | ||
| 280 | } | ||
| 281 | |||
| 282 | 477049 | static bool check_filter_fma(SwsContext *ctx, SwsUOpFlags flags, const SwsOp *op) | |
| 283 | { | ||
| 284 |
2/2✓ Branch 0 taken 247565 times.
✓ Branch 1 taken 229484 times.
|
477049 | if (!(flags & SWS_UOP_FLAG_FMA)) |
| 285 | 247565 | return false; | |
| 286 |
2/2✓ Branch 0 taken 155101 times.
✓ Branch 1 taken 74383 times.
|
229484 | if (!(ctx->flags & SWS_BITEXACT)) |
| 287 | 155101 | return true; | |
| 288 |
2/2✓ Branch 0 taken 41599 times.
✓ Branch 1 taken 32784 times.
|
74383 | if (!ff_sws_pixel_type_is_int(op->type)) |
| 289 | 41599 | return false; | |
| 290 | |||
| 291 | 32784 | const int bits = ff_sws_pixel_type_size(op->type) * 8; | |
| 292 | 32784 | const uint64_t max_val = UINT64_MAX >> (64 - bits); | |
| 293 | |||
| 294 | /* Maximum value representable losslessly as float. Note that this is | ||
| 295 | * currently true only for U8, but that may change if we ever update the | ||
| 296 | * value of SWS_FILTER_SCALE. */ | ||
| 297 | 32784 | return max_val * SWS_FILTER_SCALE <= (1 << 22); | |
| 298 | } | ||
| 299 | |||
| 300 | 4034860 | static int translate_rw_op(SwsContext *ctx, SwsUOpList *ops, SwsUOpFlags flags, | |
| 301 | const SwsOp *op) | ||
| 302 | { | ||
| 303 | 8069720 | SwsUOp uop = { | |
| 304 | 4034860 | .type = op->type, | |
| 305 |
6/6✓ Branch 0 taken 2973317 times.
✓ Branch 1 taken 1061543 times.
✓ Branch 2 taken 2832333 times.
✓ Branch 3 taken 1202527 times.
✓ Branch 4 taken 724422 times.
✓ Branch 5 taken 3310438 times.
|
4034860 | .mask = SWS_COMP_MASK(op->rw.elems > 0, op->rw.elems > 1, |
| 306 | op->rw.elems > 2, op->rw.elems > 3), | ||
| 307 | }; | ||
| 308 | |||
| 309 | /* Non-filtered reads don't care about the exact pixel contents */ | ||
| 310 |
2/2✓ Branch 0 taken 2933433 times.
✓ Branch 1 taken 1101427 times.
|
4034860 | if (!op->rw.filter.op) |
| 311 | 2933433 | uop.type = pixel_type_to_int(op->type); | |
| 312 | |||
| 313 | 4034860 | const bool is_read = op->op == SWS_OP_READ; | |
| 314 |
2/2✓ Branch 0 taken 1101427 times.
✓ Branch 1 taken 2933433 times.
|
4034860 | if (op->rw.filter.op) { |
| 315 |
3/6✓ Branch 0 taken 1101427 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1101427 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1101427 times.
|
1101427 | if (op->op == SWS_OP_WRITE || op->rw.frac || op->rw.mode != SWS_RW_PLANAR) |
| 316 | ✗ | return AVERROR(ENOTSUP); | |
| 317 | 1101427 | uop.par.filter.type = op->rw.filter.type; | |
| 318 | 1101427 | uop.data.kernel = av_refstruct_ref(op->rw.filter.kernel); | |
| 319 |
2/2✓ Branch 0 taken 624378 times.
✓ Branch 1 taken 477049 times.
|
1101427 | if (op->rw.filter.op == SWS_OP_FILTER_H) { |
| 320 | 624378 | uop.uop = SWS_UOP_READ_PLANAR_FH; | |
| 321 |
2/2✓ Branch 1 taken 166743 times.
✓ Branch 2 taken 310306 times.
|
477049 | } else if (check_filter_fma(ctx, flags, op)) { |
| 322 | 166743 | uop.uop = SWS_UOP_READ_PLANAR_FV_FMA; | |
| 323 | } else { | ||
| 324 | 310306 | uop.uop = SWS_UOP_READ_PLANAR_FV; | |
| 325 | } | ||
| 326 |
4/4✓ Branch 0 taken 1131836 times.
✓ Branch 1 taken 1801597 times.
✓ Branch 2 taken 669815 times.
✓ Branch 3 taken 462021 times.
|
2933433 | } else if (op->rw.mode == SWS_RW_PACKED && op->rw.elems > 1) { |
| 327 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 669815 times.
|
669815 | if (op->rw.frac) |
| 328 | ✗ | return AVERROR(ENOTSUP); | |
| 329 |
2/2✓ Branch 0 taken 394447 times.
✓ Branch 1 taken 275368 times.
|
669815 | uop.uop = is_read ? SWS_UOP_READ_PACKED : SWS_UOP_WRITE_PACKED; |
| 330 |
2/2✓ Branch 0 taken 9636 times.
✓ Branch 1 taken 2253982 times.
|
2263618 | } else if (op->rw.mode == SWS_RW_PALETTE) { |
| 331 |
2/4✓ Branch 0 taken 9636 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 9636 times.
|
9636 | if (op->rw.frac || !is_read) |
| 332 | ✗ | return AVERROR(ENOTSUP); | |
| 333 | 9636 | uop.uop = SWS_UOP_READ_PALETTE; | |
| 334 |
2/2✓ Branch 0 taken 34925 times.
✓ Branch 1 taken 2219057 times.
|
2253982 | } else if (op->rw.frac == 3) { |
| 335 |
2/2✓ Branch 0 taken 20504 times.
✓ Branch 1 taken 14421 times.
|
34925 | uop.uop = is_read ? SWS_UOP_READ_BIT : SWS_UOP_WRITE_BIT; |
| 336 |
2/2✓ Branch 0 taken 36189 times.
✓ Branch 1 taken 2182868 times.
|
2219057 | } else if (op->rw.frac == 1) { |
| 337 |
2/2✓ Branch 0 taken 21738 times.
✓ Branch 1 taken 14451 times.
|
36189 | uop.uop = is_read ? SWS_UOP_READ_NIBBLE : SWS_UOP_WRITE_NIBBLE; |
| 338 | } else { | ||
| 339 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2182868 times.
|
2182868 | av_assert0(!op->rw.frac); |
| 340 |
2/2✓ Branch 0 taken 661382 times.
✓ Branch 1 taken 1521486 times.
|
2182868 | uop.uop = is_read ? SWS_UOP_READ_PLANAR : SWS_UOP_WRITE_PLANAR; |
| 341 | } | ||
| 342 | |||
| 343 | 4034860 | const int planes = ff_sws_rw_op_planes(op); | |
| 344 |
2/2✓ Branch 0 taken 2209134 times.
✓ Branch 1 taken 1825726 times.
|
4034860 | if (op->op == SWS_OP_READ) { |
| 345 | 2209134 | ops->planes_in |= SWS_COMP_ELEMS(planes); | |
| 346 | } else { | ||
| 347 | 1825726 | ops->planes_out |= SWS_COMP_ELEMS(planes); | |
| 348 | } | ||
| 349 | |||
| 350 | 4034860 | return ff_sws_uop_list_append(ops, &uop); | |
| 351 | } | ||
| 352 | |||
| 353 | 2456809 | static int count_idx(const int *arr, size_t size, int val) | |
| 354 | { | ||
| 355 | 2456809 | int num = 0; | |
| 356 |
2/2✓ Branch 0 taken 12284045 times.
✓ Branch 1 taken 2456809 times.
|
14740854 | for (size_t i = 0; i < size; i++) { |
| 357 |
2/2✓ Branch 0 taken 3385957 times.
✓ Branch 1 taken 8898088 times.
|
12284045 | if (arr[i] == val) |
| 358 | 3385957 | num++; | |
| 359 | } | ||
| 360 | |||
| 361 | 2456809 | return num; | |
| 362 | } | ||
| 363 | |||
| 364 | 592726 | static int translate_swizzle(SwsUOpList *ops, const SwsOp *op) | |
| 365 | { | ||
| 366 | 1778178 | SwsUOp uop = { | |
| 367 | .uop = SWS_UOP_PERMUTE, | ||
| 368 | 592726 | .type = pixel_type_to_int(op->type), | |
| 369 | 592726 | .mask = ff_sws_comp_mask_needed(op), | |
| 370 | }; | ||
| 371 | 592726 | SwsMoveUOp *par = &uop.par.move; | |
| 372 | |||
| 373 | /* Mask of components that are not yet satisfied */ | ||
| 374 | 592726 | SwsCompMask todo = uop.mask; | |
| 375 |
2/2✓ Branch 0 taken 2370904 times.
✓ Branch 1 taken 592726 times.
|
2963630 | for (int i = 0; i < 4; i++) { |
| 376 |
2/2✓ Branch 0 taken 915965 times.
✓ Branch 1 taken 1454939 times.
|
2370904 | if (op->swizzle.in[i] == i) |
| 377 | 915965 | todo &= ~SWS_COMP(i); | |
| 378 | } | ||
| 379 | |||
| 380 | /* Mask of components whose value is required for the final output */ | ||
| 381 | 592726 | SwsCompMask needed = 0; | |
| 382 |
2/2✓ Branch 0 taken 2370904 times.
✓ Branch 1 taken 592726 times.
|
2963630 | for (int i = 0; i < 4; i++) { |
| 383 |
2/2✓ Branch 0 taken 1790587 times.
✓ Branch 1 taken 580317 times.
|
2370904 | if (SWS_OP_NEEDED(op, i)) |
| 384 | 1790587 | needed |= SWS_COMP(op->swizzle.in[i]); | |
| 385 | } | ||
| 386 | |||
| 387 | /* Current mapping of registers to components */ | ||
| 388 | 592726 | int idx[4 + 1] = { 0, 1, 2, 3, -1 }; /* +1 for tmp */ | |
| 389 | |||
| 390 | /* Decompose the swizzle mask into a series of register-register moves */ | ||
| 391 |
2/2✓ Branch 0 taken 1656633 times.
✓ Branch 1 taken 592726 times.
|
2249359 | while (todo) { |
| 392 | 1656633 | int dst = -1, src = -1; | |
| 393 | |||
| 394 | /* Find next unsatisfied dst <- src move that doesn't clobber a value */ | ||
| 395 |
2/2✓ Branch 0 taken 4270687 times.
✓ Branch 1 taken 353722 times.
|
4624409 | for (dst = 0; dst < 4; dst++) { |
| 396 |
2/2✓ Branch 0 taken 1813878 times.
✓ Branch 1 taken 2456809 times.
|
4270687 | if (!SWS_COMP_TEST(todo, dst)) |
| 397 | 1813878 | continue; /* already satisfied */ | |
| 398 | 2456809 | const int cur = idx[dst]; | |
| 399 |
4/4✓ Branch 1 taken 1527661 times.
✓ Branch 2 taken 929148 times.
✓ Branch 3 taken 1153898 times.
✓ Branch 4 taken 373763 times.
|
2456809 | if (count_idx(idx, FF_ARRAY_ELEMS(idx), cur) == 1 && SWS_COMP_TEST(needed, cur)) |
| 400 | 1153898 | continue; /* clobbers last remaining, still-needed value */ | |
| 401 |
1/2✓ Branch 0 taken 4039679 times.
✗ Branch 1 not taken.
|
4039679 | for (src = 0; src < FF_ARRAY_ELEMS(idx); src++) { |
| 402 |
2/2✓ Branch 0 taken 1302911 times.
✓ Branch 1 taken 2736768 times.
|
4039679 | if (idx[src] == op->swizzle.in[dst]) { |
| 403 | /* Prevent read-after-write dependency. */ | ||
| 404 |
4/4✓ Branch 0 taken 1031715 times.
✓ Branch 1 taken 271196 times.
✓ Branch 2 taken 384 times.
✓ Branch 3 taken 1031331 times.
|
1302911 | if (par->num_moves > 0 && src == par->dst[par->num_moves - 1]) |
| 405 | 384 | src = par->src[par->num_moves - 1]; | |
| 406 | 1302911 | break; | |
| 407 | } | ||
| 408 | } | ||
| 409 | av_assert1(src < FF_ARRAY_ELEMS(idx)); | ||
| 410 | 1302911 | todo &= ~SWS_COMP(dst); | |
| 411 | 1302911 | break; | |
| 412 | } | ||
| 413 | |||
| 414 |
2/2✓ Branch 0 taken 353722 times.
✓ Branch 1 taken 1302911 times.
|
1656633 | if (dst == 4) { |
| 415 | /* Stuck in a cycle, break it by saving to the scratch register */ | ||
| 416 | 353722 | dst = 4; | |
| 417 |
1/2✓ Branch 0 taken 386829 times.
✗ Branch 1 not taken.
|
386829 | for (src = 0; src < 4; src++) { |
| 418 |
2/2✓ Branch 0 taken 353722 times.
✓ Branch 1 taken 33107 times.
|
386829 | if (SWS_COMP_TEST(todo, src)) { |
| 419 | 353722 | needed &= ~SWS_COMP(idx[src]); | |
| 420 | 353722 | break; | |
| 421 | } | ||
| 422 | } | ||
| 423 | av_assert1(src < 4); | ||
| 424 | } | ||
| 425 | |||
| 426 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1656633 times.
|
1656633 | av_assert0(par->num_moves < SWS_UOP_MOVE_MAX); |
| 427 |
2/2✓ Branch 0 taken 1302911 times.
✓ Branch 1 taken 353722 times.
|
1656633 | par->dst[par->num_moves] = dst > 3 ? -1 : dst; |
| 428 |
2/2✓ Branch 0 taken 1302911 times.
✓ Branch 1 taken 353722 times.
|
1656633 | par->src[par->num_moves] = src > 3 ? -1 : src; |
| 429 | 1656633 | par->num_moves++; | |
| 430 | 1656633 | idx[dst] = idx[src]; | |
| 431 | } | ||
| 432 | |||
| 433 | /* Check for duplicates in the final register map */ | ||
| 434 | 592726 | SwsCompMask seen = 0; | |
| 435 |
2/2✓ Branch 0 taken 2180725 times.
✓ Branch 1 taken 495063 times.
|
2675788 | for (int i = 0; i < 4; i++) { |
| 436 |
2/2✓ Branch 0 taken 496095 times.
✓ Branch 1 taken 1684630 times.
|
2180725 | if (!SWS_COMP_TEST(uop.mask, i)) |
| 437 | 496095 | continue; | |
| 438 | av_assert2(idx[i] >= 0); /* should be no tmp register */ | ||
| 439 | 1684630 | const SwsCompMask bit = SWS_COMP(idx[i]); | |
| 440 |
2/2✓ Branch 0 taken 97663 times.
✓ Branch 1 taken 1586967 times.
|
1684630 | if (seen & bit) { |
| 441 | 97663 | uop.uop = SWS_UOP_COPY; | |
| 442 | 97663 | break; | |
| 443 | } | ||
| 444 | 1586967 | seen |= bit; | |
| 445 | } | ||
| 446 | |||
| 447 | /* Add any extra unused components to the mask, to prevent generating | ||
| 448 | * duplicate uops like permute_xyz_txy_xyt and permute_xyzw_txy_xyt */ | ||
| 449 |
2/2✓ Branch 0 taken 2370904 times.
✓ Branch 1 taken 592726 times.
|
2963630 | for (int i = 0; i < 4; i++) { |
| 450 | 2370904 | const SwsCompMask bit = SWS_COMP(i); | |
| 451 |
4/4✓ Branch 0 taken 783937 times.
✓ Branch 1 taken 1586967 times.
✓ Branch 2 taken 401880 times.
✓ Branch 3 taken 382057 times.
|
2370904 | if (!(seen & bit) && idx[i] == i) |
| 452 | 401880 | uop.mask |= bit; | |
| 453 | } | ||
| 454 | |||
| 455 | 592726 | return ff_sws_uop_list_append(ops, &uop); | |
| 456 | } | ||
| 457 | |||
| 458 | 616226 | static int translate_dither_op(SwsUOpList *ops, const SwsOp *op) | |
| 459 | { | ||
| 460 | 616226 | SwsUOp uop = { | |
| 461 | 616226 | .type = op->type, | |
| 462 | .uop = SWS_UOP_DITHER, | ||
| 463 | 616226 | .par.dither.size_log2 = op->dither.size_log2, | |
| 464 | }; | ||
| 465 | |||
| 466 |
2/2✓ Branch 0 taken 97981 times.
✓ Branch 1 taken 518245 times.
|
616226 | if (op->dither.size_log2 == 0) { |
| 467 | /* Constant offset */ | ||
| 468 | 97981 | const SwsPixel val = Q2PIXEL(op->dither.matrix[0]); | |
| 469 | 97981 | uop.uop = SWS_UOP_ADD; | |
| 470 |
2/2✓ Branch 0 taken 391924 times.
✓ Branch 1 taken 97981 times.
|
489905 | for (int i = 0; i < 4; i++) { |
| 471 |
4/4✓ Branch 0 taken 247344 times.
✓ Branch 1 taken 144580 times.
✓ Branch 2 taken 1312 times.
✓ Branch 3 taken 246032 times.
|
391924 | if (!SWS_OP_NEEDED(op, i) || op->dither.y_offset[i] < 0) |
| 472 | 145892 | continue; | |
| 473 | 246032 | uop.mask |= SWS_COMP(i); | |
| 474 | 246032 | uop.data.vec4[i] = val; | |
| 475 | } | ||
| 476 | |||
| 477 | 97981 | return ff_sws_uop_list_append(ops, &uop); | |
| 478 | } | ||
| 479 | |||
| 480 | 518245 | const int size = 1 << op->dither.size_log2; | |
| 481 |
2/2✓ Branch 0 taken 2072980 times.
✓ Branch 1 taken 518245 times.
|
2591225 | for (int i = 0; i < 4; i++) { |
| 482 |
4/4✓ Branch 0 taken 1462844 times.
✓ Branch 1 taken 610136 times.
✓ Branch 2 taken 40807 times.
✓ Branch 3 taken 1422037 times.
|
2072980 | if (!SWS_OP_NEEDED(op, i) || op->dither.y_offset[i] < 0) |
| 483 | 650943 | continue; | |
| 484 | 1422037 | const uint8_t off = op->dither.y_offset[i] & (size - 1); | |
| 485 | 1422037 | uop.mask |= SWS_COMP(i); | |
| 486 | 1422037 | uop.par.dither.y_offset[i] = off; | |
| 487 | } | ||
| 488 | |||
| 489 | /* Allocate extra rows to allow over-reading for row offsets. Note that | ||
| 490 | * y_offset is currently never larger than 5, so the extra space needed | ||
| 491 | * for this over-allocation is bounded by 5 * size * sizeof(float), | ||
| 492 | * typically 320 bytes for a 16x16 dither matrix. */ | ||
| 493 | 518245 | const int stride = size * sizeof(SwsPixel); | |
| 494 | 518245 | const int num_rows = ff_sws_dither_height(&uop.par.dither); | |
| 495 | 518245 | SwsPixel *matrix = uop.data.ptr = av_refstruct_allocz(num_rows * stride); | |
| 496 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 518245 times.
|
518245 | if (!matrix) |
| 497 | ✗ | return AVERROR(ENOMEM); | |
| 498 | |||
| 499 |
2/2✓ Branch 0 taken 132670720 times.
✓ Branch 1 taken 518245 times.
|
133188965 | for (int i = 0; i < size * size; i++) |
| 500 | 132670720 | matrix[i] = Q2PIXEL(op->dither.matrix[i]); | |
| 501 | 518245 | memcpy(&matrix[size * size], matrix, (num_rows - size) * stride); | |
| 502 | |||
| 503 | 518245 | return ff_sws_uop_list_append(ops, &uop); | |
| 504 | } | ||
| 505 | |||
| 506 | 751949 | static int translate_linear_op(SwsContext *ctx, SwsUOpList *ops, | |
| 507 | SwsUOpFlags flags, const SwsOp *op, | ||
| 508 | const SwsComps *input) | ||
| 509 | { | ||
| 510 | 751949 | SwsUOp uop = { | |
| 511 | 751949 | .type = op->type, | |
| 512 | .uop = SWS_UOP_LINEAR, | ||
| 513 | }; | ||
| 514 | |||
| 515 | 751949 | const uint32_t mask = ff_sws_linear_mask(&op->lin); | |
| 516 | 751949 | const bool bitexact = ctx->flags & SWS_BITEXACT; | |
| 517 | 751949 | uint32_t exact = 0; | |
| 518 | |||
| 519 |
2/2✓ Branch 0 taken 3007796 times.
✓ Branch 1 taken 751949 times.
|
3759745 | for (int i = 0; i < 4; i++) { |
| 520 |
4/4✓ Branch 0 taken 2117827 times.
✓ Branch 1 taken 889969 times.
✓ Branch 2 taken 90027 times.
✓ Branch 3 taken 2027800 times.
|
3007796 | if (!SWS_OP_NEEDED(op, i) || !(mask & SWS_MASK_ROW(i))) { |
| 521 | 979996 | uop.par.lin.zero |= SWS_MASK_ROW(i); | |
| 522 | 979996 | continue; | |
| 523 | } | ||
| 524 | 2027800 | uop.mask |= SWS_COMP(i); | |
| 525 | 2027800 | bool nonzero = (op->lin.m[i][4].num != 0); | |
| 526 |
2/2✓ Branch 0 taken 10139000 times.
✓ Branch 1 taken 2027800 times.
|
12166800 | for (int j = 0; j < 5; j++) { |
| 527 | 10139000 | const AVRational64 k = op->lin.m[i][j]; | |
| 528 | 10139000 | const SwsPixel px = Q2PIXEL(k); | |
| 529 | 10139000 | uop.data.mat4[i][j] = px; | |
| 530 |
2/2✓ Branch 0 taken 4643244 times.
✓ Branch 1 taken 5495756 times.
|
10139000 | if (k.num == 0) |
| 531 | 4643244 | uop.par.lin.zero |= SWS_MASK(i, j); | |
| 532 |
4/4✓ Branch 0 taken 4217270 times.
✓ Branch 1 taken 1278486 times.
✓ Branch 2 taken 1380 times.
✓ Branch 3 taken 4215890 times.
|
5495756 | else if (j < 4 && k.num == k.den) |
| 533 | 1380 | uop.par.lin.one |= SWS_MASK(i, j); | |
| 534 |
8/8✓ Branch 0 taken 4215890 times.
✓ Branch 1 taken 1278486 times.
✓ Branch 2 taken 3466576 times.
✓ Branch 3 taken 749314 times.
✓ Branch 4 taken 868434 times.
✓ Branch 5 taken 2598142 times.
✓ Branch 7 taken 787046 times.
✓ Branch 8 taken 81388 times.
|
5494376 | else if (j < 4 && nonzero && (!bitexact || exact_prod(uop.type, px, input, j))) |
| 535 | 3385188 | exact |= SWS_MASK(i, j); | |
| 536 |
2/2✓ Branch 0 taken 5495756 times.
✓ Branch 1 taken 4643244 times.
|
10139000 | if (k.num != 0) |
| 537 | 5495756 | nonzero = true; | |
| 538 | } | ||
| 539 | } | ||
| 540 | |||
| 541 |
2/2✓ Branch 0 taken 367142 times.
✓ Branch 1 taken 384807 times.
|
751949 | if (flags & SWS_UOP_FLAG_FMA) { |
| 542 | /* multiplication by 1 and 0 are always exact by definition */ | ||
| 543 | 367142 | uop.uop = SWS_UOP_LINEAR_FMA; | |
| 544 | 367142 | uop.par.lin.exact = exact | uop.par.lin.zero | uop.par.lin.one; | |
| 545 | } | ||
| 546 | |||
| 547 | 751949 | return ff_sws_uop_list_append(ops, &uop); | |
| 548 | } | ||
| 549 | |||
| 550 | 430414 | static bool is_expand_bit(SwsPixelType type, AVRational64 factor) | |
| 551 | { | ||
| 552 |
2/2✓ Branch 0 taken 352656 times.
✓ Branch 1 taken 77758 times.
|
430414 | if (factor.den != 1) |
| 553 | 352656 | return false; | |
| 554 | |||
| 555 |
4/6✓ Branch 0 taken 643 times.
✓ Branch 1 taken 1516 times.
✓ Branch 2 taken 230 times.
✓ Branch 3 taken 75369 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
77758 | switch (type) { |
| 556 | 643 | case SWS_PIXEL_U8: return factor.num == UINT8_MAX; | |
| 557 | 1516 | case SWS_PIXEL_U16: return factor.num == UINT16_MAX; | |
| 558 | 230 | case SWS_PIXEL_U32: return factor.num == UINT32_MAX; | |
| 559 | 75369 | case SWS_PIXEL_F32: return false; | |
| 560 | ✗ | case SWS_PIXEL_NONE: | |
| 561 | ✗ | case SWS_PIXEL_TYPE_NB: break; | |
| 562 | } | ||
| 563 | |||
| 564 | ✗ | av_unreachable("Invalid pixel type!"); | |
| 565 | return false; | ||
| 566 | } | ||
| 567 | |||
| 568 | 11231016 | static int translate_op(SwsContext *ctx, SwsUOpList *uops, SwsUOpFlags flags, | |
| 569 | const SwsOp *op, const SwsComps *input) | ||
| 570 | { | ||
| 571 |
6/6✓ Branch 0 taken 466852 times.
✓ Branch 1 taken 4034860 times.
✓ Branch 2 taken 592726 times.
✓ Branch 3 taken 616226 times.
✓ Branch 4 taken 751949 times.
✓ Branch 5 taken 4768403 times.
|
11231016 | switch (op->op) { |
| 572 | 466852 | case SWS_OP_FILTER_H: | |
| 573 | case SWS_OP_FILTER_V: | ||
| 574 | 466852 | return AVERROR(ENOTSUP); /* always handled by subpass splitting */ | |
| 575 | 4034860 | case SWS_OP_READ: | |
| 576 | case SWS_OP_WRITE: | ||
| 577 | 4034860 | return translate_rw_op(ctx, uops, flags, op); | |
| 578 | 592726 | case SWS_OP_SWIZZLE: | |
| 579 | 592726 | return translate_swizzle(uops, op); | |
| 580 | 616226 | case SWS_OP_DITHER: | |
| 581 | 616226 | return translate_dither_op(uops, op); | |
| 582 | 751949 | case SWS_OP_LINEAR: | |
| 583 | 751949 | return translate_linear_op(ctx, uops, flags, op, input); | |
| 584 | 4768403 | default: | |
| 585 | 4768403 | break; | |
| 586 | } | ||
| 587 | |||
| 588 | /* Default handling for "simple" ops */ | ||
| 589 | 9536806 | SwsUOp uop = { | |
| 590 | 4768403 | .type = op->type, | |
| 591 | .uop = SWS_UOP_INVALID, | ||
| 592 | 4768403 | .mask = ff_sws_comp_mask_needed(op), | |
| 593 | }; | ||
| 594 | |||
| 595 |
8/9✓ Branch 0 taken 1241492 times.
✓ Branch 1 taken 461701 times.
✓ Branch 2 taken 179496 times.
✓ Branch 3 taken 325676 times.
✓ Branch 4 taken 430414 times.
✓ Branch 5 taken 949227 times.
✓ Branch 6 taken 899501 times.
✓ Branch 7 taken 280896 times.
✗ Branch 8 not taken.
|
4768403 | switch (op->op) { |
| 596 | 1241492 | case SWS_OP_CONVERT: | |
| 597 |
2/2✓ Branch 0 taken 1908 times.
✓ Branch 1 taken 1239584 times.
|
1241492 | if (op->convert.expand) { |
| 598 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1908 times.
|
1908 | av_assert0(op->type == SWS_PIXEL_U8); |
| 599 |
1/3✓ Branch 0 taken 1908 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
|
1908 | switch (op->convert.to) { |
| 600 | 1908 | case SWS_PIXEL_U16: uop.uop = SWS_UOP_EXPAND_PAIR; break; | |
| 601 | ✗ | case SWS_PIXEL_U32: uop.uop = SWS_UOP_EXPAND_QUAD; break; | |
| 602 | } | ||
| 603 | } else { | ||
| 604 |
4/5✓ Branch 0 taken 320990 times.
✓ Branch 1 taken 650778 times.
✓ Branch 2 taken 59752 times.
✓ Branch 3 taken 208064 times.
✗ Branch 4 not taken.
|
1239584 | switch (op->convert.to) { |
| 605 | 320990 | case SWS_PIXEL_U8: uop.uop = SWS_UOP_TO_U8; break; | |
| 606 | 650778 | case SWS_PIXEL_U16: uop.uop = SWS_UOP_TO_U16; break; | |
| 607 | 59752 | case SWS_PIXEL_U32: uop.uop = SWS_UOP_TO_U32; break; | |
| 608 | 208064 | case SWS_PIXEL_F32: uop.uop = SWS_UOP_TO_F32; break; | |
| 609 | } | ||
| 610 | } | ||
| 611 | 1241492 | break; | |
| 612 | 461701 | case SWS_OP_UNPACK: | |
| 613 | case SWS_OP_PACK: | ||
| 614 |
2/2✓ Branch 0 taken 189861 times.
✓ Branch 1 taken 271840 times.
|
461701 | uop.uop = op->op == SWS_OP_PACK ? SWS_UOP_PACK : SWS_UOP_UNPACK; |
| 615 | 461701 | uop.mask = 0; | |
| 616 |
4/4✓ Branch 0 taken 1846804 times.
✓ Branch 1 taken 146052 times.
✓ Branch 2 taken 1531155 times.
✓ Branch 3 taken 315649 times.
|
1992856 | for (int i = 0; i < 4 && op->pack.pattern[i]; i++) { |
| 617 | 1531155 | uop.par.pack.pattern[i] = op->pack.pattern[i]; | |
| 618 |
4/4✓ Branch 0 taken 901484 times.
✓ Branch 1 taken 629671 times.
✓ Branch 2 taken 806326 times.
✓ Branch 3 taken 95158 times.
|
1531155 | if (op->op == SWS_OP_PACK || SWS_OP_NEEDED(op, i)) |
| 619 | 1435997 | uop.mask |= SWS_COMP(i); | |
| 620 | } | ||
| 621 | 461701 | break; | |
| 622 | 179496 | case SWS_OP_LSHIFT: | |
| 623 | case SWS_OP_RSHIFT: | ||
| 624 |
2/2✓ Branch 0 taken 76485 times.
✓ Branch 1 taken 103011 times.
|
179496 | uop.uop = op->op == SWS_OP_LSHIFT ? SWS_UOP_LSHIFT : SWS_UOP_RSHIFT; |
| 625 | 179496 | uop.par.shift.amount = op->shift.amount; | |
| 626 | 179496 | break; | |
| 627 | 325676 | case SWS_OP_CLEAR: | |
| 628 | 325676 | uop.uop = SWS_UOP_CLEAR; | |
| 629 | 325676 | uop.type = pixel_type_to_int(op->type); | |
| 630 | 325676 | uop.mask &= op->clear.mask; | |
| 631 |
2/2✓ Branch 0 taken 1302704 times.
✓ Branch 1 taken 325676 times.
|
1628380 | for (int i = 0; i < 4; i++) { |
| 632 |
2/2✓ Branch 0 taken 931236 times.
✓ Branch 1 taken 371468 times.
|
1302704 | if (!SWS_COMP_TEST(op->clear.mask, i)) |
| 633 | 931236 | continue; | |
| 634 | 371468 | const AVRational64 v = op->clear.value[i]; | |
| 635 | 371468 | const SwsPixel px = Q2PIXEL(op->clear.value[i]); | |
| 636 | 371468 | uop.data.vec4[i] = px; | |
| 637 |
2/2✓ Branch 0 taken 65203 times.
✓ Branch 1 taken 306265 times.
|
371468 | if (v.num == 0) |
| 638 | 65203 | uop.par.clear.zero |= SWS_COMP(i); | |
| 639 |
2/2✓ Branch 1 taken 76491 times.
✓ Branch 2 taken 229774 times.
|
306265 | else if (pixel_is_1s(op->type, px)) |
| 640 | 76491 | uop.par.clear.one |= SWS_COMP(i); | |
| 641 | } | ||
| 642 | 325676 | break; | |
| 643 | 430414 | case SWS_OP_SCALE: | |
| 644 |
2/2✓ Branch 1 taken 314 times.
✓ Branch 2 taken 430100 times.
|
430414 | if (is_expand_bit(op->type, op->scale.factor)) { |
| 645 | 314 | uop.uop = SWS_UOP_EXPAND_BIT; | |
| 646 | } else { | ||
| 647 | 430100 | uop.uop = SWS_UOP_SCALE; | |
| 648 | 430100 | uop.data.scalar = Q2PIXEL(op->scale.factor); | |
| 649 | } | ||
| 650 | 430414 | break; | |
| 651 | 949227 | case SWS_OP_MIN: | |
| 652 | case SWS_OP_MAX: | ||
| 653 |
2/2✓ Branch 0 taken 642610 times.
✓ Branch 1 taken 306617 times.
|
949227 | uop.uop = op->op == SWS_OP_MIN ? SWS_UOP_MIN : SWS_UOP_MAX; |
| 654 | 949227 | uop.mask &= ff_sws_comp_mask_q4(op->clamp.limit); | |
| 655 |
2/2✓ Branch 0 taken 3796908 times.
✓ Branch 1 taken 949227 times.
|
4746135 | for (int i = 0; i < 4; i++) { |
| 656 |
2/2✓ Branch 0 taken 2494492 times.
✓ Branch 1 taken 1302416 times.
|
3796908 | if (SWS_COMP_TEST(uop.mask, i)) |
| 657 | 2494492 | uop.data.vec4[i] = Q2PIXEL(op->clamp.limit[i]); | |
| 658 | } | ||
| 659 | 949227 | break; | |
| 660 | 899501 | case SWS_OP_SWAP_BYTES: | |
| 661 | 899501 | uop.uop = SWS_UOP_SWAP_BYTES; | |
| 662 | 899501 | uop.type = pixel_type_to_int(op->type); | |
| 663 | 899501 | break; | |
| 664 | 280896 | case SWS_OP_LUT_3D: | |
| 665 | 280896 | uop.uop = SWS_UOP_LUT_3D; | |
| 666 | 280896 | uop.par.lut3d.dynamic = op->lut3d.dynamic; | |
| 667 | 280896 | uop.data.lut3d = av_refstruct_ref_c(op->lut3d.lut); | |
| 668 | 280896 | break; | |
| 669 | ✗ | default: | |
| 670 | ✗ | return AVERROR(ENOTSUP); | |
| 671 | } | ||
| 672 | |||
| 673 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4768403 times.
|
4768403 | av_assert0(uop.uop != SWS_UOP_INVALID); |
| 674 | 4768403 | return ff_sws_uop_list_append(uops, &uop); | |
| 675 | } | ||
| 676 | |||
| 677 | 2292578 | int ff_sws_ops_translate(SwsContext *ctx, const SwsOpList *ops, | |
| 678 | SwsUOpFlags flags, SwsUOpList *uops) | ||
| 679 | { | ||
| 680 | 2292578 | SwsComps input = ops->comps_src; | |
| 681 |
2/2✓ Branch 0 taken 11231016 times.
✓ Branch 1 taken 1825726 times.
|
13056742 | for (int i = 0; i < ops->num_ops; i++) { |
| 682 | 11231016 | const SwsOp *op = &ops->ops[i]; | |
| 683 | 11231016 | const int pixel_size = ff_sws_pixel_type_size(op->type); | |
| 684 |
2/2✓ Branch 0 taken 3268800 times.
✓ Branch 1 taken 7962216 times.
|
11231016 | if (pixel_size > uops->pixel_size_max) |
| 685 | 3268800 | uops->pixel_size_max = pixel_size; | |
| 686 | |||
| 687 | 11231016 | int ret = translate_op(ctx, uops, flags, op, &input); | |
| 688 |
2/2✓ Branch 0 taken 466852 times.
✓ Branch 1 taken 10764164 times.
|
11231016 | if (ret < 0) |
| 689 | 466852 | return ret; | |
| 690 | 10764164 | input = ops->ops[i].comps; | |
| 691 | } | ||
| 692 | |||
| 693 | 1825726 | return ff_sws_uop_list_optimize(ctx, flags, uops); | |
| 694 | } | ||
| 695 |