GCC Code Coverage Report


Directory: avs_core/
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 56.9% 169 / 0 / 297
Functions: 61.5% 8 / 0 / 13
Branches: 47.7% 62 / 0 / 130

filters/overlay/intel/blend_common_avx2.cpp
Line Branch Exec Source
1 // Avisynth+
2 // https://avs-plus.net
3 //
4 // This program is free software; you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation; either version 2 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA, or visit
17 // http://www.gnu.org/copyleft/gpl.html .
18 //
19 // Linking Avisynth statically or dynamically with other modules is making a
20 // combined work based on Avisynth. Thus, the terms and conditions of the GNU
21 // General Public License cover the whole combination.
22 //
23 // As a special exception, the copyright holders of Avisynth give you
24 // permission to link Avisynth with independent modules that communicate with
25 // Avisynth solely through the interfaces defined in avisynth.h, regardless of the license
26 // terms of these independent modules, and to copy and distribute the
27 // resulting combined work under terms of your choice, provided that
28 // every copy of the combined work is accompanied by a complete copy of
29 // the source code of Avisynth (the version of Avisynth used to produce the
30 // combined work), being distributed under the terms of the GNU General
31 // Public License plus this exception. An independent module is a module
32 // which is not derived from or based on Avisynth, such as 3rd-party filters,
33 // import and export plugins, or graphical user interfaces.
34
35 #include "avisynth.h"
36 #include "blend_common_avx2.h"
37 #include "../blend_common.h"
38
39 #include <stdint.h>
40 #include <vector>
41
42 #ifdef _MSC_VER
43 #include <intrin.h>
44 #else
45 #include <x86intrin.h>
46 #endif
47 #include <immintrin.h>
48
49 // simd_magic_div_32_avx2 is in masked_rowprep_avx2_impl.h (included by masked_merge_avx2_impl.hpp).
50 // blend8_masked_avx2_row, blend16_masked_avx2_row, masked_merge_avx2_impl
51 // (implementation-include, no guards — each TU gets its own compiled copy)
52 #include "masked_merge_avx2_impl.hpp"
53
54 // ---------------------------------------------------------------------------
55 // Family 1: weighted_merge — AVX2 (no mask, flat weight, >> 15 shift)
56 // weight + invweight == 32768; boundary values (0, 32768) are caller early-outs.
57 // ---------------------------------------------------------------------------
58 // Important: the two extremes 0 and 32768 (15 bit arith) are handled specially earlier, returning
59 // exactly data from p1 or p2 respectively. (32768 mask value does not fit into signed int16)
60 46 static void weighted_merge_uint8_avx2_impl(
61 BYTE* p1, const BYTE* p2, int p1_pitch, int p2_pitch,
62 int rowsize, int height, int weight_i, int invweight_i)
63 {
64 // interleaved mask: invweight in lo word, weight in hi word → madd gives p1*inv + p2*w
65 92 const auto mask = _mm256_set1_epi32(invweight_i | (weight_i << 16));
66 46 const auto round_mask = _mm256_set1_epi32(0x4000);
67 46 const auto zero = _mm256_setzero_si256();
68
69 92 const auto mask_128 = _mm_set1_epi32(invweight_i | (weight_i << 16));
70 46 const auto round_mask_128 = _mm_set1_epi32(0x4000);
71 46 const auto zero_128 = _mm_setzero_si128();
72
73 46 const int wMod32 = (rowsize / 32) * 32;
74 46 const int wMod16 = (rowsize / 16) * 16;
75
76
2/2
✓ Branch 123 → 19 taken 176 times.
✓ Branch 123 → 124 taken 46 times.
222 for (int y = 0; y < height; y++) {
77
2/2
✓ Branch 68 → 20 taken 189 times.
✓ Branch 68 → 69 taken 176 times.
365 for (int x = 0; x < wMod32; x += 32) {
78 189 auto px1 = _mm256_loadu_si256(reinterpret_cast<const __m256i*>(p1 + x));
79 378 auto px2 = _mm256_loadu_si256(reinterpret_cast<const __m256i*>(p2 + x));
80
81 189 auto p07 = _mm256_unpacklo_epi8(px1, px2); // interleave p1/p2 bytes
82 189 auto p815 = _mm256_unpackhi_epi8(px1, px2);
83
84 189 auto p03 = _mm256_unpacklo_epi8(p07, zero); // zero-extend to 16-bit pairs
85 189 auto p47 = _mm256_unpackhi_epi8(p07, zero);
86 189 auto p811 = _mm256_unpacklo_epi8(p815, zero);
87 189 auto p1215 = _mm256_unpackhi_epi8(p815, zero);
88
89 378 p03 = _mm256_add_epi32(_mm256_madd_epi16(p03, mask), round_mask);
90 378 p47 = _mm256_add_epi32(_mm256_madd_epi16(p47, mask), round_mask);
91 378 p811 = _mm256_add_epi32(_mm256_madd_epi16(p811, mask), round_mask);
92 378 p1215 = _mm256_add_epi32(_mm256_madd_epi16(p1215, mask), round_mask);
93
94 189 p03 = _mm256_srli_epi32(p03, 15);
95 189 p47 = _mm256_srli_epi32(p47, 15);
96 189 p811 = _mm256_srli_epi32(p811, 15);
97 189 p1215 = _mm256_srli_epi32(p1215, 15);
98
99 189 p07 = _mm256_packs_epi32(p03, p47);
100 378 p815 = _mm256_packs_epi32(p811, p1215);
101
102 189 _mm256_storeu_si256(reinterpret_cast<__m256i*>(p1 + x),
103 _mm256_packus_epi16(p07, p815));
104 }
105
106
2/2
✓ Branch 118 → 70 taken 5 times.
✓ Branch 118 → 119 taken 176 times.
181 for (int x = wMod32; x < wMod16; x += 16) {
107 5 auto px1 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(p1 + x));
108 10 auto px2 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(p2 + x));
109
110 5 auto p07 = _mm_unpacklo_epi8(px1, px2);
111 5 auto p815 = _mm_unpackhi_epi8(px1, px2);
112
113 5 auto p03 = _mm_unpacklo_epi8(p07, zero_128);
114 5 auto p47 = _mm_unpackhi_epi8(p07, zero_128);
115 5 auto p811 = _mm_unpacklo_epi8(p815, zero_128);
116 5 auto p1215 = _mm_unpackhi_epi8(p815, zero_128);
117
118 10 p03 = _mm_add_epi32(_mm_madd_epi16(p03, mask_128), round_mask_128);
119 10 p47 = _mm_add_epi32(_mm_madd_epi16(p47, mask_128), round_mask_128);
120 10 p811 = _mm_add_epi32(_mm_madd_epi16(p811, mask_128), round_mask_128);
121 10 p1215 = _mm_add_epi32(_mm_madd_epi16(p1215, mask_128), round_mask_128);
122
123 5 p03 = _mm_srli_epi32(p03, 15);
124 5 p47 = _mm_srli_epi32(p47, 15);
125 5 p811 = _mm_srli_epi32(p811, 15);
126 5 p1215 = _mm_srli_epi32(p1215, 15);
127
128 5 p07 = _mm_packs_epi32(p03, p47);
129 5 p815 = _mm_packs_epi32(p811, p1215);
130
131 5 _mm_storeu_si128(reinterpret_cast<__m128i*>(p1 + x),
132 _mm_packus_epi16(p07, p815));
133 }
134
135 // Scalar tail
136
2/2
✓ Branch 121 → 120 taken 618 times.
✓ Branch 121 → 122 taken 176 times.
794 for (int x = wMod16; x < rowsize; ++x)
137 618 p1[x] = (uint8_t)((p1[x] * invweight_i + p2[x] * weight_i + 16384) >> 15);
138
139 176 p1 += p1_pitch;
140 176 p2 += p2_pitch;
141 }
142 46 }
143
144 // Important: the two extremes 0 and 32768 (15 bit arith) are handled specially earlier, returning
145 // exactly data from p1 or p2 respectively. (32768 mask value does not fit into signed int16)
146 // lessthan16bit=true: 10/12/14-bit — no signed pivot needed (pixel values fit positive int16)
147 // lessthan16bit=false: full 16-bit — signed pivot to avoid unsigned overflow in madd
148 template<bool lessthan16bit>
149 4 static void weighted_merge_uint16_avx2_impl(
150 BYTE* p1, const BYTE* p2, int p1_pitch, int p2_pitch,
151 int rowsize, int height, int weight_i, int invweight_i)
152 {
153 // After unpacklo_epi16(px1,px2): pairs are (px1[i], px2[i]).
154 // mask lo=invweight, hi=weight → madd gives px1*invweight + px2*weight.
155 8 const __m256i mask = _mm256_set1_epi32((weight_i << 16) + invweight_i);
156 4 const __m256i round_mask = _mm256_set1_epi32(0x4000);
157 4 const __m256i signed_shift = _mm256_set1_epi16(-32768); // add to convert u16→s16
158
159 8 const __m128i mask_128 = _mm_set1_epi32((weight_i << 16) + invweight_i);
160 4 const __m128i round_mask_128 = _mm_set1_epi32(0x4000);
161 4 const __m128i signed_shift_128 = _mm_set1_epi16(-32768);
162
163 4 const int wMod32 = (rowsize / 32) * 32;
164 4 const int wMod16 = (rowsize / 16) * 16;
165
166
4/4
void weighted_merge_uint16_avx2_impl<false>(unsigned char*, unsigned char const*, int, int, int, int, int, int):
✓ Branch 91 → 23 taken 13 times.
✓ Branch 91 → 92 taken 1 time.
void weighted_merge_uint16_avx2_impl<true>(unsigned char*, unsigned char const*, int, int, int, int, int, int):
✓ Branch 79 → 23 taken 27 times.
✓ Branch 79 → 80 taken 3 times.
44 for (int y = 0; y < height; y++) {
167 // 32-byte (16 pixels) AVX2 loop
168
3/4
void weighted_merge_uint16_avx2_impl<false>(unsigned char*, unsigned char const*, int, int, int, int, int, int):
✗ Branch 54 → 24 not taken.
✓ Branch 54 → 55 taken 13 times.
void weighted_merge_uint16_avx2_impl<true>(unsigned char*, unsigned char const*, int, int, int, int, int, int):
✓ Branch 48 → 24 taken 27 times.
✓ Branch 48 → 49 taken 27 times.
67 for (int x = 0; x < wMod32; x += 32) {
169 27 __m256i px1 = _mm256_loadu_si256(reinterpret_cast<const __m256i*>(p1 + x));
170 54 __m256i px2 = _mm256_loadu_si256(reinterpret_cast<const __m256i*>(p2 + x));
171
172 if constexpr (!lessthan16bit) {
173 // Shift unsigned 0..65535 → signed -32768..32767 for madd safety
174 px1 = _mm256_add_epi16(px1, signed_shift);
175 px2 = _mm256_add_epi16(px2, signed_shift);
176 }
177
178 27 auto p03 = _mm256_unpacklo_epi16(px1, px2);
179 27 auto p47 = _mm256_unpackhi_epi16(px1, px2);
180
181 54 p03 = _mm256_add_epi32(_mm256_madd_epi16(p03, mask), round_mask);
182 54 p47 = _mm256_add_epi32(_mm256_madd_epi16(p47, mask), round_mask);
183
184 27 p03 = _mm256_srai_epi32(p03, 15);
185 27 p47 = _mm256_srai_epi32(p47, 15);
186
187 27 auto p07 = _mm256_packs_epi32(p03, p47);
188 if constexpr (!lessthan16bit) {
189 // Restore: signed → unsigned by adding 32768 (modular: -32768 + 32768 = 0)
190 p07 = _mm256_add_epi16(p07, signed_shift);
191 }
192
193 27 _mm256_storeu_si256(reinterpret_cast<__m256i*>(p1 + x), p07);
194 }
195
196 // 16-byte (8 pixels) fallback
197
3/4
void weighted_merge_uint16_avx2_impl<false>(unsigned char*, unsigned char const*, int, int, int, int, int, int):
✓ Branch 86 → 56 taken 13 times.
✓ Branch 86 → 87 taken 13 times.
void weighted_merge_uint16_avx2_impl<true>(unsigned char*, unsigned char const*, int, int, int, int, int, int):
✗ Branch 74 → 50 not taken.
✓ Branch 74 → 75 taken 27 times.
53 for (int x = wMod32; x < wMod16; x += 16) {
198 13 __m128i px1 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(p1 + x));
199 26 __m128i px2 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(p2 + x));
200
201 if constexpr (!lessthan16bit) {
202 13 px1 = _mm_add_epi16(px1, signed_shift_128);
203 13 px2 = _mm_add_epi16(px2, signed_shift_128);
204 }
205
206 13 auto p03 = _mm_unpacklo_epi16(px1, px2);
207 13 auto p47 = _mm_unpackhi_epi16(px1, px2);
208
209 26 p03 = _mm_add_epi32(_mm_madd_epi16(p03, mask_128), round_mask_128);
210 26 p47 = _mm_add_epi32(_mm_madd_epi16(p47, mask_128), round_mask_128);
211
212 13 p03 = _mm_srai_epi32(p03, 15);
213 13 p47 = _mm_srai_epi32(p47, 15);
214
215 13 auto p07 = _mm_packs_epi32(p03, p47);
216 if constexpr (!lessthan16bit) {
217 13 p07 = _mm_add_epi16(p07, signed_shift_128);
218 }
219
220 13 _mm_storeu_si128(reinterpret_cast<__m128i*>(p1 + x), p07);
221 }
222
223 // Scalar tail (in pixels)
224
4/4
void weighted_merge_uint16_avx2_impl<false>(unsigned char*, unsigned char const*, int, int, int, int, int, int):
✓ Branch 89 → 88 taken 91 times.
✓ Branch 89 → 90 taken 13 times.
void weighted_merge_uint16_avx2_impl<true>(unsigned char*, unsigned char const*, int, int, int, int, int, int):
✓ Branch 77 → 76 taken 91 times.
✓ Branch 77 → 78 taken 27 times.
222 for (int x = wMod16 / 2; x < rowsize / 2; ++x) {
225 182 reinterpret_cast<uint16_t*>(p1)[x] = (uint16_t)(
226 182 (reinterpret_cast<uint16_t*>(p1)[x] * invweight_i +
227 182 reinterpret_cast<const uint16_t*>(p2)[x] * weight_i + 16384) >> 15);
228 }
229
230 40 p1 += p1_pitch;
231 40 p2 += p2_pitch;
232 }
233 4 }
234
235 50 void weighted_merge_avx2(BYTE* p1, const BYTE* p2, int p1_pitch, int p2_pitch,
236 int width, int height, int weight, int invweight, int bits_per_pixel)
237 {
238
2/2
✓ Branch 2 → 3 taken 46 times.
✓ Branch 2 → 4 taken 4 times.
50 const int pixelsize = bits_per_pixel <= 8 ? 1 : 2;
239 50 const int rowsize = width * pixelsize;
240
241
2/2
✓ Branch 5 → 6 taken 46 times.
✓ Branch 5 → 7 taken 4 times.
50 if (bits_per_pixel == 8)
242 46 weighted_merge_uint8_avx2_impl(p1, p2, p1_pitch, p2_pitch, rowsize, height, weight, invweight);
243
2/2
✓ Branch 7 → 8 taken 1 time.
✓ Branch 7 → 9 taken 3 times.
4 else if (bits_per_pixel == 16)
244 1 weighted_merge_uint16_avx2_impl<false>(p1, p2, p1_pitch, p2_pitch, rowsize, height, weight, invweight);
245 else // 10, 12, 14-bit
246 3 weighted_merge_uint16_avx2_impl<true>(p1, p2, p1_pitch, p2_pitch, rowsize, height, weight, invweight);
247 50 }
248
249 4 void weighted_merge_float_avx2(BYTE* p1, const BYTE* p2, int p1_pitch, int p2_pitch,
250 int width, int height, float weight_f)
251 {
252 4 const float invweight_f = 1.0f - weight_f;
253 4 const auto v_weight = _mm256_set1_ps(weight_f);
254 4 const auto v_invweight = _mm256_set1_ps(invweight_f);
255 4 const int rowsize = width * 4;
256 4 const int wMod32 = (rowsize / 32) * 32;
257
258
2/2
✓ Branch 23 → 7 taken 19 times.
✓ Branch 23 → 24 taken 4 times.
23 for (int y = 0; y < height; y++) {
259
2/2
✓ Branch 18 → 8 taken 30 times.
✓ Branch 18 → 19 taken 19 times.
49 for (int x = 0; x < wMod32; x += 32) {
260 30 auto px1 = _mm256_loadu_ps(reinterpret_cast<const float*>(p1 + x));
261 60 auto px2 = _mm256_loadu_ps(reinterpret_cast<const float*>(p2 + x));
262 // p1 + (p2 - p1) * w == p1*(1-w) + p2*w
263 // choose the latter to match C ref
264 30 auto res = _mm256_fmadd_ps(px1, v_invweight, _mm256_mul_ps(px2, v_weight));
265 // Linear interp: auto res = _mm256_add_ps(px1, _mm256_mul_ps(_mm256_sub_ps(px2, px1), v_weight))
266 30 _mm256_storeu_ps(reinterpret_cast<float*>(p1 + x), res);
267 }
268 // Scalar tail
269
2/2
✓ Branch 21 → 20 taken 83 times.
✓ Branch 21 → 22 taken 19 times.
102 for (int x = wMod32 / 4; x < width; ++x) {
270 83 reinterpret_cast<float*>(p1)[x] =
271 83 reinterpret_cast<float*>(p1)[x] * invweight_f +
272 83 reinterpret_cast<const float*>(p2)[x] * weight_f;
273 }
274 19 p1 += p1_pitch;
275 19 p2 += p2_pitch;
276 }
277 4 }
278
279 // ---------------------------------------------------------------------------
280 // Overlay blend masked getter — returns masked_merge_avx2_impl instantiation.
281 // is_chroma=false -> always MASK444 (luma).
282 // is_chroma=true -> placement-aware maskMode (chroma).
283 // ---------------------------------------------------------------------------
284 8150 masked_merge_fn_t* get_overlay_blend_masked_fn_avx2(bool is_chroma, MaskMode maskMode)
285 {
286 #define DISPATCH_OVERLAY_BLEND_AVX2(MaskType) \
287 return is_chroma ? masked_merge_avx2_impl<MaskType> \
288 : masked_merge_avx2_impl<MASK444>;
289
290
7/9
✓ Branch 2 → 3 taken 2168 times.
✓ Branch 2 → 4 taken 1445 times.
✓ Branch 2 → 8 taken 910 times.
✓ Branch 2 → 12 taken 728 times.
✓ Branch 2 → 16 taken 1443 times.
✓ Branch 2 → 20 taken 728 times.
✓ Branch 2 → 24 taken 728 times.
✗ Branch 2 → 28 not taken.
✗ Branch 2 → 32 not taken.
8150 switch (maskMode) {
291 2168 case MASK444: DISPATCH_OVERLAY_BLEND_AVX2(MASK444)
292
1/2
✓ Branch 4 → 5 taken 1445 times.
✗ Branch 4 → 6 not taken.
1445 case MASK420: DISPATCH_OVERLAY_BLEND_AVX2(MASK420)
293
1/2
✓ Branch 8 → 9 taken 910 times.
✗ Branch 8 → 10 not taken.
910 case MASK420_MPEG2: DISPATCH_OVERLAY_BLEND_AVX2(MASK420_MPEG2)
294
1/2
✓ Branch 12 → 13 taken 728 times.
✗ Branch 12 → 14 not taken.
728 case MASK420_TOPLEFT: DISPATCH_OVERLAY_BLEND_AVX2(MASK420_TOPLEFT)
295
1/2
✓ Branch 16 → 17 taken 1443 times.
✗ Branch 16 → 18 not taken.
1443 case MASK422: DISPATCH_OVERLAY_BLEND_AVX2(MASK422)
296
1/2
✓ Branch 20 → 21 taken 728 times.
✗ Branch 20 → 22 not taken.
728 case MASK422_MPEG2: DISPATCH_OVERLAY_BLEND_AVX2(MASK422_MPEG2)
297
1/2
✓ Branch 24 → 25 taken 728 times.
✗ Branch 24 → 26 not taken.
728 case MASK422_TOPLEFT: DISPATCH_OVERLAY_BLEND_AVX2(MASK422_TOPLEFT)
298 case MASK411: DISPATCH_OVERLAY_BLEND_AVX2(MASK411)
299 }
300 #undef DISPATCH_OVERLAY_BLEND_AVX2
301 return masked_merge_avx2_impl<MASK444>; // unreachable
302 }
303
304 // ---------------------------------------------------------------------------
305 // Per-row chroma mask preparation for the scratch path in OF_blend.cpp.
306 // Defined here so masked_rowprep_avx2_impl.h is only included in this TU.
307 // ---------------------------------------------------------------------------
308 template<typename pixel_t, bool full_opacity>
309 9 void do_fill_chroma_row_avx2(
310 std::vector<pixel_t>& buf, const pixel_t* luma_row,
311 int luma_pitch_pixels, int chroma_w, MaskMode mode,
312 int opacity_i, int half, MagicDiv magic)
313 {
314
2/32
void do_fill_chroma_row_avx2<unsigned char, false>(std::vector<unsigned char, std::allocator<unsigned char> >&, unsigned char const*, int, int, MaskMode, int, int, MagicDiv):
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 4 not taken.
✓ Branch 2 → 5 taken 4 times.
✗ Branch 2 → 6 not taken.
✗ Branch 2 → 7 not taken.
✓ Branch 2 → 8 taken 5 times.
✗ Branch 2 → 9 not taken.
✗ Branch 2 → 10 not taken.
void do_fill_chroma_row_avx2<unsigned char, true>(std::vector<unsigned char, std::allocator<unsigned char> >&, unsigned char const*, int, int, MaskMode, int, int, MagicDiv):
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 4 not taken.
✗ Branch 2 → 5 not taken.
✗ Branch 2 → 6 not taken.
✗ Branch 2 → 7 not taken.
✗ Branch 2 → 8 not taken.
✗ Branch 2 → 9 not taken.
✗ Branch 2 → 10 not taken.
void do_fill_chroma_row_avx2<unsigned short, false>(std::vector<unsigned short, std::allocator<unsigned short> >&, unsigned short const*, int, int, MaskMode, int, int, MagicDiv):
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 4 not taken.
✗ Branch 2 → 5 not taken.
✗ Branch 2 → 6 not taken.
✗ Branch 2 → 7 not taken.
✗ Branch 2 → 8 not taken.
✗ Branch 2 → 9 not taken.
✗ Branch 2 → 10 not taken.
void do_fill_chroma_row_avx2<unsigned short, true>(std::vector<unsigned short, std::allocator<unsigned short> >&, unsigned short const*, int, int, MaskMode, int, int, MagicDiv):
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 4 not taken.
✗ Branch 2 → 5 not taken.
✗ Branch 2 → 6 not taken.
✗ Branch 2 → 7 not taken.
✗ Branch 2 → 8 not taken.
✗ Branch 2 → 9 not taken.
✗ Branch 2 → 10 not taken.
9 switch (mode) {
315 case MASK411:
316 prepare_effective_mask_for_row_avx2<MASK411, pixel_t, full_opacity>(luma_row, luma_pitch_pixels, chroma_w, buf, opacity_i, half, magic); break;
317 case MASK420:
318 prepare_effective_mask_for_row_avx2<MASK420, pixel_t, full_opacity>(luma_row, luma_pitch_pixels, chroma_w, buf, opacity_i, half, magic); break;
319 4 case MASK420_MPEG2:
320 4 prepare_effective_mask_for_row_avx2<MASK420_MPEG2, pixel_t, full_opacity>(luma_row, luma_pitch_pixels, chroma_w, buf, opacity_i, half, magic); break;
321 case MASK420_TOPLEFT:
322 prepare_effective_mask_for_row_avx2<MASK420_TOPLEFT, pixel_t, full_opacity>(luma_row, luma_pitch_pixels, chroma_w, buf, opacity_i, half, magic); break;
323 case MASK422:
324 prepare_effective_mask_for_row_avx2<MASK422, pixel_t, full_opacity>(luma_row, luma_pitch_pixels, chroma_w, buf, opacity_i, half, magic); break;
325 5 case MASK422_MPEG2:
326 5 prepare_effective_mask_for_row_avx2<MASK422_MPEG2, pixel_t, full_opacity>(luma_row, luma_pitch_pixels, chroma_w, buf, opacity_i, half, magic); break;
327 case MASK422_TOPLEFT:
328 prepare_effective_mask_for_row_avx2<MASK422_TOPLEFT, pixel_t, full_opacity>(luma_row, luma_pitch_pixels, chroma_w, buf, opacity_i, half, magic); break;
329 default: break;
330 }
331 9 }
332
333 template void do_fill_chroma_row_avx2<uint8_t, true>(std::vector<uint8_t>&, const uint8_t*, int, int, MaskMode, int, int, MagicDiv);
334 template void do_fill_chroma_row_avx2<uint8_t, false>(std::vector<uint8_t>&, const uint8_t*, int, int, MaskMode, int, int, MagicDiv);
335 template void do_fill_chroma_row_avx2<uint16_t, true>(std::vector<uint16_t>&, const uint16_t*, int, int, MaskMode, int, int, MagicDiv);
336 template void do_fill_chroma_row_avx2<uint16_t, false>(std::vector<uint16_t>&, const uint16_t*, int, int, MaskMode, int, int, MagicDiv);
337
338
339 template<bool full_opacity>
340 void do_fill_chroma_row_float_avx2(
341 std::vector<float>& buf, const float* luma_row,
342 int luma_pitch_pixels, int chroma_w, MaskMode mode,
343 float opacity)
344 {
345 switch (mode) {
346 case MASK411:
347 prepare_effective_mask_for_row_float_avx2<MASK411, full_opacity>(luma_row, luma_pitch_pixels, chroma_w, buf, opacity); break;
348 case MASK420:
349 prepare_effective_mask_for_row_float_avx2<MASK420, full_opacity>(luma_row, luma_pitch_pixels, chroma_w, buf, opacity); break;
350 case MASK420_MPEG2:
351 prepare_effective_mask_for_row_float_avx2<MASK420_MPEG2, full_opacity>(luma_row, luma_pitch_pixels, chroma_w, buf, opacity); break;
352 case MASK420_TOPLEFT:
353 prepare_effective_mask_for_row_float_avx2<MASK420_TOPLEFT, full_opacity>(luma_row, luma_pitch_pixels, chroma_w, buf, opacity); break;
354 case MASK422:
355 prepare_effective_mask_for_row_float_avx2<MASK422, full_opacity>(luma_row, luma_pitch_pixels, chroma_w, buf, opacity); break;
356 case MASK422_MPEG2:
357 prepare_effective_mask_for_row_float_avx2<MASK422_MPEG2, full_opacity>(luma_row, luma_pitch_pixels, chroma_w, buf, opacity); break;
358 case MASK422_TOPLEFT:
359 prepare_effective_mask_for_row_float_avx2<MASK422_TOPLEFT, full_opacity>(luma_row, luma_pitch_pixels, chroma_w, buf, opacity); break;
360 default: break;
361 }
362 }
363
364 template void do_fill_chroma_row_float_avx2<true> (std::vector<float>&, const float*, int, int, MaskMode, float);
365 template void do_fill_chroma_row_float_avx2<false>(std::vector<float>&, const float*, int, int, MaskMode, float);
366
367 // and for float:
368 6139 masked_merge_float_fn_t* get_overlay_blend_masked_float_fn_avx2(bool is_chroma, MaskMode maskMode)
369 {
370 #define DISPATCH_OVERLAY_BLEND_FLOAT_AVX2(MaskType) \
371 return is_chroma ? masked_merge_float_avx2_impl<MaskType> \
372 : masked_merge_float_avx2_impl<MASK444>;
373
374
7/9
✓ Branch 2 → 3 taken 1015 times.
✓ Branch 2 → 4 taken 1016 times.
✓ Branch 2 → 8 taken 910 times.
✓ Branch 2 → 12 taken 728 times.
✓ Branch 2 → 16 taken 1014 times.
✓ Branch 2 → 20 taken 728 times.
✓ Branch 2 → 24 taken 728 times.
✗ Branch 2 → 28 not taken.
✗ Branch 2 → 32 not taken.
6139 switch (maskMode) {
375 1015 case MASK444: DISPATCH_OVERLAY_BLEND_FLOAT_AVX2(MASK444)
376
1/2
✓ Branch 4 → 5 taken 1016 times.
✗ Branch 4 → 6 not taken.
1016 case MASK420: DISPATCH_OVERLAY_BLEND_FLOAT_AVX2(MASK420)
377
1/2
✓ Branch 8 → 9 taken 910 times.
✗ Branch 8 → 10 not taken.
910 case MASK420_MPEG2: DISPATCH_OVERLAY_BLEND_FLOAT_AVX2(MASK420_MPEG2)
378
1/2
✓ Branch 12 → 13 taken 728 times.
✗ Branch 12 → 14 not taken.
728 case MASK420_TOPLEFT: DISPATCH_OVERLAY_BLEND_FLOAT_AVX2(MASK420_TOPLEFT)
379
1/2
✓ Branch 16 → 17 taken 1014 times.
✗ Branch 16 → 18 not taken.
1014 case MASK422: DISPATCH_OVERLAY_BLEND_FLOAT_AVX2(MASK422)
380
1/2
✓ Branch 20 → 21 taken 728 times.
✗ Branch 20 → 22 not taken.
728 case MASK422_MPEG2: DISPATCH_OVERLAY_BLEND_FLOAT_AVX2(MASK422_MPEG2)
381
1/2
✓ Branch 24 → 25 taken 728 times.
✗ Branch 24 → 26 not taken.
728 case MASK422_TOPLEFT: DISPATCH_OVERLAY_BLEND_FLOAT_AVX2(MASK422_TOPLEFT)
382 case MASK411: DISPATCH_OVERLAY_BLEND_FLOAT_AVX2(MASK411)
383 }
384 #undef DISPATCH_OVERLAY_BLEND_FLOAT_AVX2
385 return masked_merge_float_avx2_impl<MASK444>; // unreachable
386 }
387
388