filters/overlay/intel/masked_merge_sse41_impl.hpp
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | // AviSynth+ Copyright 2026- AviSynth+ Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | // | ||
| 4 | // SSE4.1 masked-merge implementation templates. | ||
| 5 | // | ||
| 6 | // Implementation-include — NO include guards intentionally. | ||
| 7 | // Each including TU gets its own compilation with that TU's SIMD flags. | ||
| 8 | // All definitions are static so each TU has its own private copy; | ||
| 9 | // the linker never sees them as the same symbol. | ||
| 10 | // | ||
| 11 | // Requires the following to be visible in the including TU before this file: | ||
| 12 | // SSE4.1 intrinsics (<intrin.h> or <x86intrin.h>, <smmintrin.h>) | ||
| 13 | // blend_common.h — MaskMode, MagicDiv, get_magic_div, magic_div_rt | ||
| 14 | // <vector> | ||
| 15 | |||
| 16 | #include "masked_rowprep_sse41.h" | ||
| 17 | |||
| 18 | // --------------------------------------------------------------------------- | ||
| 19 | // 8-bit row — mask already has opacity baked in by rowprep. | ||
| 20 | // 16-wide 16-bit mulhi arithmetic (fast, overflow-safe). | ||
| 21 | // --------------------------------------------------------------------------- | ||
| 22 | #if defined(GCC) || defined(CLANG) | ||
| 23 | __attribute__((__target__("sse4.1"))) | ||
| 24 | #endif | ||
| 25 | static AVS_FORCEINLINE void blend8_masked_sse41_row( | ||
| 26 | uint8_t* p1, const uint8_t* p2, const uint8_t* mask, | ||
| 27 | int width) | ||
| 28 | { | ||
| 29 | 166 | constexpr uint32_t half = 127u; | |
| 30 | 166 | constexpr uint32_t max_val = 255u; | |
| 31 | |||
| 32 | 166 | const __m128i v_half = _mm_set1_epi16((short)half); | |
| 33 | 166 | const __m128i v_max = _mm_set1_epi16((short)max_val); | |
| 34 | 166 | const __m128i v_magic = _mm_set1_epi16((short)0x8081); | |
| 35 | |||
| 36 | 470 | auto magic_byte = [&](__m128i x) { | |
| 37 | 1410 | return _mm_srli_epi16(_mm_mulhi_epu16(x, v_magic), 7); | |
| 38 | 166 | }; | |
| 39 | |||
| 40 | 166 | int x = 0; | |
| 41 |
8/8✓ Branch 45 → 21 taken 57 times.
✓ Branch 45 → 46 taken 31 times.
✓ Branch 46 → 22 taken 40 times.
✓ Branch 46 → 47 taken 40 times.
✓ Branch 432 → 408 taken 81 times.
✓ Branch 432 → 433 taken 43 times.
✓ Branch 434 → 410 taken 57 times.
✓ Branch 434 → 435 taken 52 times.
|
401 | for (; x <= width - 16; x += 16) { |
| 42 | 470 | __m128i mr = _mm_loadu_si128((__m128i*)(mask + x)); | |
| 43 | 235 | __m128i m_lo = _mm_cvtepu8_epi16(mr); | |
| 44 | 235 | __m128i m_hi = _mm_cvtepu8_epi16(_mm_srli_si128(mr, 8)); | |
| 45 | |||
| 46 | 235 | __m128i ar = _mm_loadu_si128((__m128i*)(p1 + x)); | |
| 47 | 235 | __m128i br = _mm_loadu_si128((__m128i*)(p2 + x)); | |
| 48 | |||
| 49 | 470 | auto blend16 = [&](__m128i a, __m128i b, __m128i m) { | |
| 50 | 470 | __m128i invm = _mm_sub_epi16(v_max, m); | |
| 51 | 2350 | return magic_byte(_mm_add_epi16( | |
| 52 | 470 | _mm_add_epi16(_mm_mullo_epi16(a, invm), _mm_mullo_epi16(b, m)), v_half)); | |
| 53 | 235 | }; | |
| 54 | |||
| 55 | 1410 | _mm_storeu_si128((__m128i*)(p1 + x), _mm_packus_epi16( | |
| 56 | blend16(_mm_cvtepu8_epi16(ar), _mm_cvtepu8_epi16(br), m_lo), | ||
| 57 | blend16(_mm_cvtepu8_epi16(_mm_srli_si128(ar, 8)), _mm_cvtepu8_epi16(_mm_srli_si128(br, 8)), m_hi))); | ||
| 58 | } | ||
| 59 |
8/8✓ Branch 48 → 47 taken 135 times.
✓ Branch 48 → 49 taken 31 times.
✓ Branch 49 → 48 taken 40 times.
✓ Branch 49 → 50 taken 40 times.
✓ Branch 435 → 434 taken 195 times.
✓ Branch 435 → 436 taken 43 times.
✓ Branch 437 → 436 taken 114 times.
✓ Branch 437 → 438 taken 52 times.
|
650 | for (; x < width; ++x) { |
| 60 | 484 | const uint32_t ms = mask[x]; | |
| 61 | 484 | const uint32_t a = p1[x], b_v = p2[x]; | |
| 62 | 484 | const uint32_t tr = a * (max_val - ms) + b_v * ms + half; | |
| 63 | 484 | p1[x] = (uint8_t)((tr * 0x8081u) >> 23); | |
| 64 | } | ||
| 65 | 166 | } | |
| 66 | |||
| 67 | // --------------------------------------------------------------------------- | ||
| 68 | // 16-bit row (10, 12, 14, 16 bits) — mask already has opacity baked in. | ||
| 69 | // 32-bit arithmetic, 4 pixels per step. | ||
| 70 | // --------------------------------------------------------------------------- | ||
| 71 | template<int bits_per_pixel> | ||
| 72 | #if defined(GCC) || defined(CLANG) | ||
| 73 | __attribute__((__target__("sse4.1"))) | ||
| 74 | #endif | ||
| 75 | static AVS_FORCEINLINE void blend16_masked_sse41_row( | ||
| 76 | uint16_t* p1, const uint16_t* p2, const uint16_t* mask, | ||
| 77 | int width) | ||
| 78 | { | ||
| 79 | 186 | constexpr MagicDiv m_div = get_magic_div(bits_per_pixel); | |
| 80 | 186 | constexpr uint32_t max_val = (1u << bits_per_pixel) - 1; | |
| 81 | 186 | constexpr uint32_t half = max_val / 2; | |
| 82 | |||
| 83 | 186 | const __m128i v_half = _mm_set1_epi32((int)half); | |
| 84 | 186 | const __m128i v_max = _mm_set1_epi32((int)max_val); | |
| 85 | |||
| 86 | 186 | int x = 0; | |
| 87 |
20/32✓ Branch 127 → 67 taken 20 times.
✓ Branch 127 → 128 taken 5 times.
✗ Branch 129 → 69 not taken.
✗ Branch 129 → 130 not taken.
✓ Branch 208 → 148 taken 20 times.
✓ Branch 208 → 209 taken 5 times.
✗ Branch 210 → 150 not taken.
✗ Branch 210 → 211 not taken.
✓ Branch 289 → 229 taken 20 times.
✓ Branch 289 → 290 taken 5 times.
✗ Branch 291 → 231 not taken.
✗ Branch 291 → 292 not taken.
✓ Branch 370 → 310 taken 114 times.
✓ Branch 370 → 371 taken 31 times.
✓ Branch 372 → 312 taken 100 times.
✓ Branch 372 → 373 taken 40 times.
✓ Branch 515 → 455 taken 20 times.
✓ Branch 515 → 516 taken 5 times.
✗ Branch 517 → 457 not taken.
✗ Branch 517 → 518 not taken.
✓ Branch 596 → 536 taken 20 times.
✓ Branch 596 → 597 taken 5 times.
✗ Branch 598 → 538 not taken.
✗ Branch 598 → 599 not taken.
✓ Branch 677 → 617 taken 20 times.
✓ Branch 677 → 678 taken 5 times.
✗ Branch 679 → 619 not taken.
✗ Branch 679 → 680 not taken.
✓ Branch 758 → 698 taken 150 times.
✓ Branch 758 → 759 taken 40 times.
✓ Branch 760 → 700 taken 120 times.
✓ Branch 760 → 761 taken 45 times.
|
790 | for (; x <= width - 4; x += 4) { |
| 88 | 1208 | __m128i m = _mm_cvtepu16_epi32(_mm_loadl_epi64((__m128i*)(mask + x))); | |
| 89 | 1208 | __m128i a = _mm_cvtepu16_epi32(_mm_loadl_epi64((__m128i*)(p1 + x))); | |
| 90 | 1812 | __m128i b = _mm_cvtepu16_epi32(_mm_loadl_epi64((__m128i*)(p2 + x))); | |
| 91 | 604 | __m128i invm = _mm_sub_epi32(v_max, m); | |
| 92 | 3020 | __m128i res = simd_magic_div_32( | |
| 93 | _mm_add_epi32(_mm_add_epi32(_mm_mullo_epi32(a, invm), _mm_mullo_epi32(b, m)), v_half), | ||
| 94 | 604 | m_div.div, m_div.shift); | |
| 95 | 604 | _mm_storel_epi64((__m128i*)(p1 + x), _mm_packus_epi32(res, res)); | |
| 96 | } | ||
| 97 |
20/32✓ Branch 132 → 129 taken 15 times.
✓ Branch 132 → 133 taken 5 times.
✗ Branch 134 → 131 not taken.
✗ Branch 134 → 135 not taken.
✓ Branch 213 → 210 taken 15 times.
✓ Branch 213 → 214 taken 5 times.
✗ Branch 215 → 212 not taken.
✗ Branch 215 → 216 not taken.
✓ Branch 294 → 291 taken 15 times.
✓ Branch 294 → 295 taken 5 times.
✗ Branch 296 → 293 not taken.
✗ Branch 296 → 297 not taken.
✓ Branch 375 → 372 taken 83 times.
✓ Branch 375 → 376 taken 31 times.
✓ Branch 377 → 374 taken 40 times.
✓ Branch 377 → 378 taken 40 times.
✓ Branch 520 → 517 taken 15 times.
✓ Branch 520 → 521 taken 5 times.
✗ Branch 522 → 519 not taken.
✗ Branch 522 → 523 not taken.
✓ Branch 601 → 598 taken 15 times.
✓ Branch 601 → 602 taken 5 times.
✗ Branch 603 → 600 not taken.
✗ Branch 603 → 604 not taken.
✓ Branch 682 → 679 taken 15 times.
✓ Branch 682 → 683 taken 5 times.
✗ Branch 684 → 681 not taken.
✗ Branch 684 → 685 not taken.
✓ Branch 763 → 760 taken 110 times.
✓ Branch 763 → 764 taken 40 times.
✓ Branch 765 → 762 taken 55 times.
✓ Branch 765 → 766 taken 45 times.
|
564 | for (; x < width; ++x) { |
| 98 | 378 | const uint32_t ms = mask[x]; | |
| 99 | 378 | const uint32_t a = p1[x]; | |
| 100 | 756 | p1[x] = (uint16_t)magic_div_rt<uint16_t>(a * (max_val - ms) + (uint32_t)p2[x] * ms + half, m_div); | |
| 101 | } | ||
| 102 | 186 | } | |
| 103 | |||
| 104 | // --------------------------------------------------------------------------- | ||
| 105 | // float row — mask already has opacity baked in (range 0.0 to 1.0). | ||
| 106 | // Linear interpolation: p1[x] = p1[x] * (1.0f - mask[x]) + p2[x] * mask[x] | ||
| 107 | // 4 pixels per step. | ||
| 108 | // --------------------------------------------------------------------------- | ||
| 109 | #if defined(GCC) || defined(CLANG) | ||
| 110 | __attribute__((__target__("sse4.1"))) | ||
| 111 | #endif | ||
| 112 | 30 | static void blend_masked_float_sse41_row( | |
| 113 | float* p1, const float* p2, const float* mask, int width) | ||
| 114 | { | ||
| 115 | 30 | int x = 0; | |
| 116 | // const __m128 v_one = _mm_set1_ps(1.0f); in case of 1-x implementation | ||
| 117 | |||
| 118 |
2/2✓ Branch 17 → 3 taken 110 times.
✓ Branch 17 → 18 taken 30 times.
|
140 | for (; x <= width - 4; x += 4) { |
| 119 | 110 | __m128 m = _mm_loadu_ps(mask + x); | |
| 120 | 110 | __m128 a = _mm_loadu_ps(p1 + x); | |
| 121 | 220 | __m128 b = _mm_loadu_ps(p2 + x); | |
| 122 | |||
| 123 | // Standard lerp: a + m * (b - a) | ||
| 124 | // This is generally more accurate and faster (1 mul, 2 adds) than | ||
| 125 | // a * (1-m) + b * m (2 muls, 2 adds). | ||
| 126 | 110 | __m128 diff = _mm_sub_ps(b, a); | |
| 127 | 110 | __m128 res = _mm_add_ps(a, _mm_mul_ps(m, diff)); | |
| 128 | |||
| 129 | 110 | _mm_storeu_ps(p1 + x, res); | |
| 130 | } | ||
| 131 | |||
| 132 | // Scalar tail | ||
| 133 |
2/2✓ Branch 20 → 19 taken 30 times.
✓ Branch 20 → 21 taken 30 times.
|
60 | for (; x < width; ++x) { |
| 134 | 30 | const float m = mask[x]; | |
| 135 | 30 | const float a = p1[x]; | |
| 136 | 30 | const float b = p2[x]; | |
| 137 | 30 | p1[x] = a + m * (b - a); | |
| 138 | } | ||
| 139 | 30 | } | |
| 140 | |||
| 141 | // --------------------------------------------------------------------------- | ||
| 142 | // Inner loop — full_opacity known at compile time. | ||
| 143 | // Rowprep bakes opacity when !full_opacity; blend row receives pre-scaled mask. | ||
| 144 | // MASK444 + full_opacity: returns mask ptr directly (no buffer, no copy). | ||
| 145 | // MASK444 + !full_opacity: copies row with opacity scaling into buffer. | ||
| 146 | // --------------------------------------------------------------------------- | ||
| 147 | template<MaskMode maskMode, bool full_opacity> | ||
| 148 | #if defined(GCC) || defined(CLANG) | ||
| 149 | __attribute__((__target__("sse4.1"))) | ||
| 150 | #endif | ||
| 151 | static AVS_FORCEINLINE void masked_merge_sse41_impl_inner( | ||
| 152 | BYTE* p1, const BYTE* p2, const BYTE* mask, | ||
| 153 | int p1_pitch, int p2_pitch, int mask_pitch, | ||
| 154 | int width, int height, int opacity, int bits_per_pixel) | ||
| 155 | { | ||
| 156 | 84 | const MagicDiv mag = get_magic_div(bits_per_pixel); | |
| 157 | 84 | const int max_val = (1 << bits_per_pixel) - 1; | |
| 158 | 84 | const int half = max_val / 2; | |
| 159 | |||
| 160 |
7/7✓ Branch 4 → 5 taken 17 times.
✓ Branch 4 → 54 taken 12 times.
✓ Branch 4 → 55 taken 8 times.
✓ Branch 390 → 391 taken 13 times.
✓ Branch 390 → 441 taken 15 times.
✓ Branch 392 → 393 taken 10 times.
✓ Branch 392 → 443 taken 9 times.
|
84 | if (bits_per_pixel == 8) { |
| 161 | 40 | const uint8_t* maskp = reinterpret_cast<const uint8_t*>(mask); | |
| 162 | 40 | const int mpx = mask_pitch; | |
| 163 | 40 | const int mask_adv = (maskMode == MASK420 || maskMode == MASK420_MPEG2 || maskMode == MASK420_TOPLEFT) ? mpx * 2 : mpx; | |
| 164 | |||
| 165 | 40 | std::vector<uint8_t> eff_buf; | |
| 166 |
3/6✓ Branch 6 → 7 taken 8 times.
✗ Branch 6 → 385 not taken.
✓ Branch 392 → 393 taken 13 times.
✗ Branch 392 → 771 not taken.
✓ Branch 394 → 395 taken 10 times.
✗ Branch 394 → 773 not taken.
|
31 | if constexpr (maskMode != MASK444 || !full_opacity) eff_buf.resize(width); |
| 167 | |||
| 168 |
8/8✓ Branch 51 → 7 taken 31 times.
✓ Branch 51 → 52 taken 9 times.
✓ Branch 52 → 8 taken 40 times.
✓ Branch 52 → 53 taken 8 times.
✓ Branch 438 → 394 taken 43 times.
✓ Branch 438 → 439 taken 13 times.
✓ Branch 440 → 396 taken 52 times.
✓ Branch 440 → 441 taken 10 times.
|
206 | for (int y = 0; y < height; y++) { |
| 169 |
4/8✓ Branch 7 → 8 taken 31 times.
✗ Branch 7 → 383 not taken.
✓ Branch 8 → 9 taken 40 times.
✗ Branch 8 → 385 not taken.
✓ Branch 394 → 395 taken 43 times.
✗ Branch 394 → 771 not taken.
✓ Branch 396 → 397 taken 52 times.
✗ Branch 396 → 773 not taken.
|
166 | const uint8_t* eff = prepare_effective_mask_for_row_sse41<maskMode, uint8_t, full_opacity>( |
| 170 | maskp, mpx, width, eff_buf, opacity, half, mag); | ||
| 171 | blend8_masked_sse41_row( | ||
| 172 | reinterpret_cast<uint8_t*>(p1), reinterpret_cast<const uint8_t*>(p2), eff, width); | ||
| 173 | 166 | p1 += p1_pitch; p2 += p2_pitch; maskp += mask_adv; | |
| 174 | } | ||
| 175 | 40 | return; | |
| 176 | 40 | } | |
| 177 | |||
| 178 | 44 | const uint16_t* maskp = reinterpret_cast<const uint16_t*>(mask); | |
| 179 | 44 | const int mpx = mask_pitch / 2; | |
| 180 | 44 | const int mask_adv = (maskMode == MASK420 || maskMode == MASK420_MPEG2 || maskMode == MASK420_TOPLEFT) ? mpx * 2 : mpx; | |
| 181 | |||
| 182 | 44 | std::vector<uint16_t> eff_buf; | |
| 183 |
3/6✓ Branch 56 → 57 taken 8 times.
✗ Branch 56 → 388 not taken.
✓ Branch 442 → 443 taken 15 times.
✗ Branch 442 → 774 not taken.
✓ Branch 444 → 445 taken 9 times.
✗ Branch 444 → 776 not taken.
|
32 | if constexpr (maskMode != MASK444 || !full_opacity) eff_buf.resize(width); |
| 184 | |||
| 185 | #define BLEND16_LOOP(bpp) \ | ||
| 186 | for (int y = 0; y < height; y++) { \ | ||
| 187 | const uint16_t* eff = prepare_effective_mask_for_row_sse41<maskMode, uint16_t, full_opacity>( \ | ||
| 188 | maskp, mpx, width, eff_buf, opacity, half, mag); \ | ||
| 189 | blend16_masked_sse41_row<bpp>( \ | ||
| 190 | reinterpret_cast<uint16_t*>(p1), reinterpret_cast<const uint16_t*>(p2), eff, width); \ | ||
| 191 | p1 += p1_pitch; p2 += p2_pitch; maskp += mask_adv; \ | ||
| 192 | } break; | ||
| 193 | |||
| 194 |
10/20✓ Branch 55 → 56 taken 1 time.
✓ Branch 55 → 137 taken 1 time.
✓ Branch 55 → 218 taken 1 time.
✓ Branch 55 → 299 taken 9 times.
✗ Branch 55 → 380 not taken.
✗ Branch 57 → 58 not taken.
✗ Branch 57 → 139 not taken.
✗ Branch 57 → 220 not taken.
✓ Branch 57 → 301 taken 8 times.
✗ Branch 57 → 382 not taken.
✓ Branch 443 → 444 taken 1 time.
✓ Branch 443 → 525 taken 1 time.
✓ Branch 443 → 606 taken 1 time.
✓ Branch 443 → 687 taken 12 times.
✗ Branch 443 → 768 not taken.
✗ Branch 445 → 446 not taken.
✗ Branch 445 → 527 not taken.
✗ Branch 445 → 608 not taken.
✓ Branch 445 → 689 taken 9 times.
✗ Branch 445 → 770 not taken.
|
44 | switch (bits_per_pixel) { |
| 195 |
6/16✓ Branch 57 → 58 taken 5 times.
✗ Branch 57 → 386 not taken.
✗ Branch 59 → 60 not taken.
✗ Branch 59 → 388 not taken.
✓ Branch 135 → 57 taken 5 times.
✓ Branch 135 → 136 taken 1 time.
✗ Branch 137 → 59 not taken.
✗ Branch 137 → 138 not taken.
✓ Branch 445 → 446 taken 5 times.
✗ Branch 445 → 774 not taken.
✗ Branch 447 → 448 not taken.
✗ Branch 447 → 776 not taken.
✓ Branch 523 → 445 taken 5 times.
✓ Branch 523 → 524 taken 1 time.
✗ Branch 525 → 447 not taken.
✗ Branch 525 → 526 not taken.
|
12 | case 10: BLEND16_LOOP(10) |
| 196 |
6/16✓ Branch 138 → 139 taken 5 times.
✗ Branch 138 → 386 not taken.
✗ Branch 140 → 141 not taken.
✗ Branch 140 → 388 not taken.
✓ Branch 216 → 138 taken 5 times.
✓ Branch 216 → 217 taken 1 time.
✗ Branch 218 → 140 not taken.
✗ Branch 218 → 219 not taken.
✓ Branch 526 → 527 taken 5 times.
✗ Branch 526 → 774 not taken.
✗ Branch 528 → 529 not taken.
✗ Branch 528 → 776 not taken.
✓ Branch 604 → 526 taken 5 times.
✓ Branch 604 → 605 taken 1 time.
✗ Branch 606 → 528 not taken.
✗ Branch 606 → 607 not taken.
|
12 | case 12: BLEND16_LOOP(12) |
| 197 |
6/16✓ Branch 219 → 220 taken 5 times.
✗ Branch 219 → 386 not taken.
✗ Branch 221 → 222 not taken.
✗ Branch 221 → 388 not taken.
✓ Branch 297 → 219 taken 5 times.
✓ Branch 297 → 298 taken 1 time.
✗ Branch 299 → 221 not taken.
✗ Branch 299 → 300 not taken.
✓ Branch 607 → 608 taken 5 times.
✗ Branch 607 → 774 not taken.
✗ Branch 609 → 610 not taken.
✗ Branch 609 → 776 not taken.
✓ Branch 685 → 607 taken 5 times.
✓ Branch 685 → 686 taken 1 time.
✗ Branch 687 → 609 not taken.
✗ Branch 687 → 688 not taken.
|
12 | case 14: BLEND16_LOOP(14) |
| 198 |
12/16✓ Branch 300 → 301 taken 31 times.
✗ Branch 300 → 386 not taken.
✓ Branch 302 → 303 taken 40 times.
✗ Branch 302 → 388 not taken.
✓ Branch 378 → 300 taken 31 times.
✓ Branch 378 → 379 taken 9 times.
✓ Branch 380 → 302 taken 40 times.
✓ Branch 380 → 381 taken 8 times.
✓ Branch 688 → 689 taken 40 times.
✗ Branch 688 → 774 not taken.
✓ Branch 690 → 691 taken 45 times.
✗ Branch 690 → 776 not taken.
✓ Branch 766 → 688 taken 40 times.
✓ Branch 766 → 767 taken 12 times.
✓ Branch 768 → 690 taken 45 times.
✓ Branch 768 → 769 taken 9 times.
|
194 | case 16: BLEND16_LOOP(16) |
| 199 | } | ||
| 200 | #undef BLEND16_LOOP | ||
| 201 | 44 | } | |
| 202 | |||
| 203 | // --------------------------------------------------------------------------- | ||
| 204 | // Inner loop — full_opacity known at compile time. | ||
| 205 | // Rowprep bakes opacity when !full_opacity; blend row receives pre-scaled mask. | ||
| 206 | // MASK444 + full_opacity: returns mask ptr directly (no buffer, no copy). | ||
| 207 | // MASK444 + !full_opacity: copies row with opacity scaling into buffer. | ||
| 208 | // --------------------------------------------------------------------------- | ||
| 209 | template<MaskMode maskMode, bool full_opacity> | ||
| 210 | #if defined(GCC) || defined(CLANG) | ||
| 211 | __attribute__((__target__("sse4.1"))) | ||
| 212 | #endif | ||
| 213 | 6 | static void masked_merge_float_sse41_impl_inner( | |
| 214 | BYTE* p1, const BYTE* p2, const BYTE* mask, | ||
| 215 | int p1_pitch, int p2_pitch, int mask_pitch, | ||
| 216 | int width, int height, float opacity) | ||
| 217 | { | ||
| 218 | 6 | const float* maskp = reinterpret_cast<const float*>(mask); | |
| 219 | 6 | const int mpx = mask_pitch / sizeof(float); | |
| 220 | 6 | const int mask_adv = (maskMode == MASK420 || maskMode == MASK420_MPEG2 || maskMode == MASK420_TOPLEFT) ? mpx * 2 : mpx; | |
| 221 | |||
| 222 | 6 | std::vector<float> eff_buf; | |
| 223 |
5/30void masked_merge_float_sse41_impl_inner<(MaskMode)0, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, float):
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 11 not taken.
void masked_merge_float_sse41_impl_inner<(MaskMode)0, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, float):
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 11 not taken.
void masked_merge_float_sse41_impl_inner<(MaskMode)1, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, float):
✓ Branch 3 → 4 taken 1 time.
✗ Branch 3 → 11 not taken.
void masked_merge_float_sse41_impl_inner<(MaskMode)1, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, float):
✓ Branch 3 → 4 taken 1 time.
✗ Branch 3 → 11 not taken.
void masked_merge_float_sse41_impl_inner<(MaskMode)2, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, float):
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 11 not taken.
void masked_merge_float_sse41_impl_inner<(MaskMode)2, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, float):
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 11 not taken.
void masked_merge_float_sse41_impl_inner<(MaskMode)3, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, float):
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 11 not taken.
void masked_merge_float_sse41_impl_inner<(MaskMode)3, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, float):
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 11 not taken.
void masked_merge_float_sse41_impl_inner<(MaskMode)4, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, float):
✓ Branch 3 → 4 taken 1 time.
✗ Branch 3 → 11 not taken.
void masked_merge_float_sse41_impl_inner<(MaskMode)4, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, float):
✓ Branch 3 → 4 taken 1 time.
✗ Branch 3 → 11 not taken.
void masked_merge_float_sse41_impl_inner<(MaskMode)5, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, float):
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 11 not taken.
void masked_merge_float_sse41_impl_inner<(MaskMode)5, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, float):
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 11 not taken.
void masked_merge_float_sse41_impl_inner<(MaskMode)6, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, float):
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 11 not taken.
void masked_merge_float_sse41_impl_inner<(MaskMode)6, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, float):
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 11 not taken.
void masked_merge_float_sse41_impl_inner<(MaskMode)7, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, float):
✓ Branch 3 → 4 taken 1 time.
✗ Branch 3 → 11 not taken.
|
5 | if constexpr (maskMode != MASK444 || !full_opacity) eff_buf.resize(width); |
| 224 | |||
| 225 |
12/32void masked_merge_float_sse41_impl_inner<(MaskMode)0, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, float):
✗ Branch 8 → 5 not taken.
✗ Branch 8 → 9 not taken.
void masked_merge_float_sse41_impl_inner<(MaskMode)0, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, float):
✗ Branch 8 → 5 not taken.
✗ Branch 8 → 9 not taken.
void masked_merge_float_sse41_impl_inner<(MaskMode)1, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, float):
✓ Branch 8 → 5 taken 5 times.
✓ Branch 8 → 9 taken 1 time.
void masked_merge_float_sse41_impl_inner<(MaskMode)1, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, float):
✓ Branch 8 → 5 taken 5 times.
✓ Branch 8 → 9 taken 1 time.
void masked_merge_float_sse41_impl_inner<(MaskMode)2, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, float):
✗ Branch 8 → 5 not taken.
✗ Branch 8 → 9 not taken.
void masked_merge_float_sse41_impl_inner<(MaskMode)2, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, float):
✗ Branch 8 → 5 not taken.
✗ Branch 8 → 9 not taken.
void masked_merge_float_sse41_impl_inner<(MaskMode)3, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, float):
✗ Branch 8 → 5 not taken.
✗ Branch 8 → 9 not taken.
void masked_merge_float_sse41_impl_inner<(MaskMode)3, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, float):
✗ Branch 8 → 5 not taken.
✗ Branch 8 → 9 not taken.
void masked_merge_float_sse41_impl_inner<(MaskMode)4, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, float):
✓ Branch 8 → 5 taken 5 times.
✓ Branch 8 → 9 taken 1 time.
void masked_merge_float_sse41_impl_inner<(MaskMode)4, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, float):
✓ Branch 8 → 5 taken 5 times.
✓ Branch 8 → 9 taken 1 time.
void masked_merge_float_sse41_impl_inner<(MaskMode)5, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, float):
✗ Branch 8 → 5 not taken.
✗ Branch 8 → 9 not taken.
void masked_merge_float_sse41_impl_inner<(MaskMode)5, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, float):
✗ Branch 8 → 5 not taken.
✗ Branch 8 → 9 not taken.
void masked_merge_float_sse41_impl_inner<(MaskMode)6, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, float):
✗ Branch 8 → 5 not taken.
✗ Branch 8 → 9 not taken.
void masked_merge_float_sse41_impl_inner<(MaskMode)6, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, float):
✗ Branch 8 → 5 not taken.
✗ Branch 8 → 9 not taken.
void masked_merge_float_sse41_impl_inner<(MaskMode)7, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, float):
✓ Branch 8 → 5 taken 5 times.
✓ Branch 8 → 9 taken 1 time.
void masked_merge_float_sse41_impl_inner<(MaskMode)7, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, float):
✓ Branch 7 → 4 taken 5 times.
✓ Branch 7 → 8 taken 1 time.
|
36 | for (int y = 0; y < height; y++) { |
| 226 |
6/32void masked_merge_float_sse41_impl_inner<(MaskMode)0, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, float):
✗ Branch 5 → 6 not taken.
✗ Branch 5 → 11 not taken.
void masked_merge_float_sse41_impl_inner<(MaskMode)0, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, float):
✗ Branch 5 → 6 not taken.
✗ Branch 5 → 11 not taken.
void masked_merge_float_sse41_impl_inner<(MaskMode)1, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, float):
✓ Branch 5 → 6 taken 5 times.
✗ Branch 5 → 11 not taken.
void masked_merge_float_sse41_impl_inner<(MaskMode)1, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, float):
✓ Branch 5 → 6 taken 5 times.
✗ Branch 5 → 11 not taken.
void masked_merge_float_sse41_impl_inner<(MaskMode)2, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, float):
✗ Branch 5 → 6 not taken.
✗ Branch 5 → 11 not taken.
void masked_merge_float_sse41_impl_inner<(MaskMode)2, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, float):
✗ Branch 5 → 6 not taken.
✗ Branch 5 → 11 not taken.
void masked_merge_float_sse41_impl_inner<(MaskMode)3, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, float):
✗ Branch 5 → 6 not taken.
✗ Branch 5 → 11 not taken.
void masked_merge_float_sse41_impl_inner<(MaskMode)3, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, float):
✗ Branch 5 → 6 not taken.
✗ Branch 5 → 11 not taken.
void masked_merge_float_sse41_impl_inner<(MaskMode)4, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, float):
✓ Branch 5 → 6 taken 5 times.
✗ Branch 5 → 11 not taken.
void masked_merge_float_sse41_impl_inner<(MaskMode)4, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, float):
✓ Branch 5 → 6 taken 5 times.
✗ Branch 5 → 11 not taken.
void masked_merge_float_sse41_impl_inner<(MaskMode)5, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, float):
✗ Branch 5 → 6 not taken.
✗ Branch 5 → 11 not taken.
void masked_merge_float_sse41_impl_inner<(MaskMode)5, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, float):
✗ Branch 5 → 6 not taken.
✗ Branch 5 → 11 not taken.
void masked_merge_float_sse41_impl_inner<(MaskMode)6, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, float):
✗ Branch 5 → 6 not taken.
✗ Branch 5 → 11 not taken.
void masked_merge_float_sse41_impl_inner<(MaskMode)6, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, float):
✗ Branch 5 → 6 not taken.
✗ Branch 5 → 11 not taken.
void masked_merge_float_sse41_impl_inner<(MaskMode)7, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, float):
✓ Branch 5 → 6 taken 5 times.
✗ Branch 5 → 11 not taken.
void masked_merge_float_sse41_impl_inner<(MaskMode)7, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, float):
✓ Branch 4 → 5 taken 5 times.
✗ Branch 4 → 10 not taken.
|
30 | const float* eff = prepare_effective_mask_for_row_float_sse41<maskMode, full_opacity>( |
| 227 | maskp, mpx, width, eff_buf, opacity); | ||
| 228 | 30 | blend_masked_float_sse41_row( | |
| 229 | reinterpret_cast<float*>(p1), reinterpret_cast<const float*>(p2), eff, width); | ||
| 230 | 30 | p1 += p1_pitch; p2 += p2_pitch; maskp += mask_adv; | |
| 231 | } | ||
| 232 | 6 | } | |
| 233 | |||
| 234 | // --------------------------------------------------------------------------- | ||
| 235 | // Outer: dispatch on full_opacity (opacity == max_pixel_value) at the call site. | ||
| 236 | // Public signature unchanged — existing callers and function-pointer tables work. | ||
| 237 | // --------------------------------------------------------------------------- | ||
| 238 | template<MaskMode maskMode> | ||
| 239 | #if defined(GCC) || defined(CLANG) | ||
| 240 | __attribute__((__target__("sse4.1"))) | ||
| 241 | #endif | ||
| 242 | 84 | static void masked_merge_sse41_impl( | |
| 243 | BYTE* p1, const BYTE* p2, const BYTE* mask, | ||
| 244 | int p1_pitch, int p2_pitch, int mask_pitch, | ||
| 245 | int width, int height, int opacity, int bits_per_pixel) | ||
| 246 | { | ||
| 247 | 84 | const int max_val = (1 << bits_per_pixel) - 1; | |
| 248 |
14/16void masked_merge_sse41_impl<(MaskMode)0>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 391 not taken.
void masked_merge_sse41_impl<(MaskMode)1>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 2 → 3 taken 4 times.
✓ Branch 2 → 391 taken 5 times.
void masked_merge_sse41_impl<(MaskMode)2>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 2 → 3 taken 2 times.
✓ Branch 2 → 391 taken 3 times.
void masked_merge_sse41_impl<(MaskMode)3>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 2 → 3 taken 2 times.
✓ Branch 2 → 391 taken 2 times.
void masked_merge_sse41_impl<(MaskMode)4>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 2 → 3 taken 4 times.
✓ Branch 2 → 391 taken 5 times.
void masked_merge_sse41_impl<(MaskMode)5>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 2 → 3 taken 2 times.
✓ Branch 2 → 391 taken 2 times.
void masked_merge_sse41_impl<(MaskMode)6>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 2 → 3 taken 2 times.
✓ Branch 2 → 391 taken 2 times.
void masked_merge_sse41_impl<(MaskMode)7>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 2 → 3 taken 21 times.
✓ Branch 2 → 389 taken 28 times.
|
84 | if (opacity == max_val) |
| 249 | masked_merge_sse41_impl_inner<maskMode, true>( | ||
| 250 | p1, p2, mask, p1_pitch, p2_pitch, mask_pitch, width, height, opacity, bits_per_pixel); | ||
| 251 | else | ||
| 252 | masked_merge_sse41_impl_inner<maskMode, false>( | ||
| 253 | p1, p2, mask, p1_pitch, p2_pitch, mask_pitch, width, height, opacity, bits_per_pixel); | ||
| 254 | 84 | } | |
| 255 | |||
| 256 | template<MaskMode maskMode> | ||
| 257 | #if defined(GCC) || defined(CLANG) | ||
| 258 | __attribute__((__target__("sse4.1"))) | ||
| 259 | #endif | ||
| 260 | 6 | static void masked_merge_float_sse41_impl( | |
| 261 | BYTE* p1, const BYTE* p2, const BYTE* mask, | ||
| 262 | int p1_pitch, int p2_pitch, int mask_pitch, | ||
| 263 | int width, int height, float opacity) | ||
| 264 | { | ||
| 265 |
6/16void masked_merge_float_sse41_impl<(MaskMode)0>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, float):
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 4 not taken.
void masked_merge_float_sse41_impl<(MaskMode)1>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, float):
✓ Branch 2 → 3 taken 1 time.
✓ Branch 2 → 4 taken 1 time.
void masked_merge_float_sse41_impl<(MaskMode)2>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, float):
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 4 not taken.
void masked_merge_float_sse41_impl<(MaskMode)3>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, float):
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 4 not taken.
void masked_merge_float_sse41_impl<(MaskMode)4>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, float):
✓ Branch 2 → 3 taken 1 time.
✓ Branch 2 → 4 taken 1 time.
void masked_merge_float_sse41_impl<(MaskMode)5>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, float):
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 4 not taken.
void masked_merge_float_sse41_impl<(MaskMode)6>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, float):
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 4 not taken.
void masked_merge_float_sse41_impl<(MaskMode)7>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, float):
✓ Branch 2 → 3 taken 1 time.
✓ Branch 2 → 4 taken 1 time.
|
6 | if (opacity >= 1.0f) |
| 266 | 3 | masked_merge_float_sse41_impl_inner<maskMode, true>( | |
| 267 | p1, p2, mask, p1_pitch, p2_pitch, mask_pitch, width, height, opacity); | ||
| 268 | else | ||
| 269 | 3 | masked_merge_float_sse41_impl_inner<maskMode, false>( | |
| 270 | p1, p2, mask, p1_pitch, p2_pitch, mask_pitch, width, height, opacity); | ||
| 271 | 6 | } | |
| 272 |