GCC Code Coverage Report


Directory: avs_core/
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 58.3% 194 / 0 / 333
Functions: 54.3% 19 / 0 / 35
Branches: 51.1% 168 / 0 / 329

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/30
void 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/32
void 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/32
void 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/16
void 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/16
void 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