GCC Code Coverage Report


Directory: avs_core/
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 100.0% 117 / 0 / 117
Functions: 100.0% 6 / 0 / 6
Branches: 100.0% 40 / 0 / 40

filters/intel/merge_sse.cpp
Line Branch Exec Source
1 // Avisynth v2.5. Copyright 2002 Ben Rudiak-Gould et al.
2 // http://avisynth.nl
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
36 // Avisynth filter: YUV merge / Swap planes
37 // by Klaus Post (kp@interact.dk)
38 // adapted by Richard Berg (avisynth-dev@richardberg.net)
39 // iSSE code by Ian Brabham
40
41
42 #include "../merge.h"
43 #include "merge_sse.h"
44 #include "merge_avx2.h"
45 #include "../core/internal.h"
46
47 // Intrinsics base header + really required extension headers
48 #if defined(_MSC_VER)
49 #include <intrin.h> // MSVC
50 #else
51 #include <x86intrin.h> // GCC/MinGW/Clang/LLVM
52 #endif
53
54 #include "avs/alignment.h"
55 #include <stdint.h>
56
57
58 /* -----------------------------------
59 * weighted_merge_chroma_yuy2
60 * -----------------------------------
61 */
62 2 void weighted_merge_chroma_yuy2_sse2(BYTE *src, const BYTE *chroma, int pitch, int chroma_pitch,int width, int height, int weight, int invweight )
63 {
64 2 __m128i round_mask = _mm_set1_epi32(0x4000);
65 4 __m128i mask = _mm_set_epi16(weight, invweight, weight, invweight, weight, invweight, weight, invweight);
66 2 __m128i luma_mask = _mm_set1_epi16(0x00FF);
67
68 2 int wMod16 = (width/16) * 16;
69
70
2/2
✓ Branch 53 → 13 taken 18 times.
✓ Branch 53 → 54 taken 2 times.
20 for (int y = 0; y < height; y++) {
71
2/2
✓ Branch 48 → 14 taken 47 times.
✓ Branch 48 → 49 taken 18 times.
65 for (int x = 0; x < wMod16; x += 16) {
72 47 __m128i px1 = _mm_load_si128(reinterpret_cast<const __m128i*>(src+x));
73 94 __m128i px2 = _mm_load_si128(reinterpret_cast<const __m128i*>(chroma+x));
74
75 47 __m128i src_lo = _mm_unpacklo_epi16(px1, px2);
76 47 __m128i src_hi = _mm_unpackhi_epi16(px1, px2);
77
78 47 src_lo = _mm_srli_epi16(src_lo, 8);
79 47 src_hi = _mm_srli_epi16(src_hi, 8);
80
81 47 src_lo = _mm_madd_epi16(src_lo, mask);
82 47 src_hi = _mm_madd_epi16(src_hi, mask);
83
84 47 src_lo = _mm_add_epi32(src_lo, round_mask);
85 47 src_hi = _mm_add_epi32(src_hi, round_mask);
86
87 47 src_lo = _mm_srli_epi32(src_lo, 15);
88 47 src_hi = _mm_srli_epi32(src_hi, 15);
89
90 47 __m128i result_chroma = _mm_packs_epi32(src_lo, src_hi);
91 47 result_chroma = _mm_slli_epi16(result_chroma, 8);
92
93 47 __m128i result_luma = _mm_and_si128(px1, luma_mask);
94 47 __m128i result = _mm_or_si128(result_chroma, result_luma);
95
96 47 _mm_store_si128(reinterpret_cast<__m128i*>(src+x), result);
97 }
98
99
2/2
✓ Branch 51 → 50 taken 98 times.
✓ Branch 51 → 52 taken 18 times.
116 for (int x = wMod16; x < width; x+=2) {
100 98 src[x+1] = (chroma[x+1] * weight + src[x+1] * invweight + 16384) >> 15;
101 }
102
103 18 src += pitch;
104 18 chroma += chroma_pitch;
105 }
106 2 }
107
108 #ifdef X86_32
109 void weighted_merge_chroma_yuy2_mmx(BYTE *src, const BYTE *chroma, int pitch, int chroma_pitch,int width, int height, int weight, int invweight )
110 {
111 __m64 round_mask = _mm_set1_pi32(0x4000);
112 __m64 mask = _mm_set_pi16(weight, invweight, weight, invweight);
113 __m64 luma_mask = _mm_set1_pi16(0x00FF);
114
115 int wMod8 = (width/8) * 8;
116
117 for (int y = 0; y < height; y++) {
118 for (int x = 0; x < wMod8; x += 8) {
119 __m64 px1 = *reinterpret_cast<const __m64*>(src+x); //V1 Y3 U1 Y2 V0 Y1 U0 Y0
120 __m64 px2 = *reinterpret_cast<const __m64*>(chroma+x); //v1 y3 u1 y2 v0 y1 u0 y0
121
122 __m64 src_lo = _mm_unpacklo_pi16(px1, px2); //v0 y1 V0 Y1 u0 y0 U0 Y0
123 __m64 src_hi = _mm_unpackhi_pi16(px1, px2);
124
125 src_lo = _mm_srli_pi16(src_lo, 8); //00 v0 00 V0 00 u0 00 U0
126 src_hi = _mm_srli_pi16(src_hi, 8);
127
128 src_lo = _mm_madd_pi16(src_lo, mask);
129 src_hi = _mm_madd_pi16(src_hi, mask);
130
131 src_lo = _mm_add_pi32(src_lo, round_mask);
132 src_hi = _mm_add_pi32(src_hi, round_mask);
133
134 src_lo = _mm_srli_pi32(src_lo, 15);
135 src_hi = _mm_srli_pi32(src_hi, 15);
136
137 __m64 result_chroma = _mm_packs_pi32(src_lo, src_hi);
138 result_chroma = _mm_slli_pi16(result_chroma, 8);
139
140 __m64 result_luma = _mm_and_si64(px1, luma_mask);
141 __m64 result = _mm_or_si64(result_chroma, result_luma);
142
143 *reinterpret_cast<__m64*>(src+x) = result;
144 }
145
146 for (int x = wMod8; x < width; x+=2) {
147 src[x+1] = (chroma[x+1] * weight + src[x+1] * invweight + 16384) >> 15;
148 }
149
150 src += pitch;
151 chroma += chroma_pitch;
152 }
153 _mm_empty();
154 }
155 #endif
156
157
158
159 /* -----------------------------------
160 * weighted_merge_luma_yuy2
161 * -----------------------------------
162 */
163 2 void weighted_merge_luma_yuy2_sse2(BYTE *src, const BYTE *luma, int pitch, int luma_pitch,int width, int height, int weight, int invweight)
164 {
165 2 __m128i round_mask = _mm_set1_epi32(0x4000);
166 4 __m128i mask = _mm_set_epi16(weight, invweight, weight, invweight, weight, invweight, weight, invweight);
167 2 __m128i luma_mask = _mm_set1_epi16(0x00FF);
168 2 __m128i chroma_mask = _mm_set1_epi16((short)0xFF00);
169
170 2 int wMod16 = (width/16) * 16;
171
172
2/2
✓ Branch 55 → 17 taken 18 times.
✓ Branch 55 → 56 taken 2 times.
20 for (int y = 0; y < height; y++) {
173
2/2
✓ Branch 50 → 18 taken 47 times.
✓ Branch 50 → 51 taken 18 times.
65 for (int x = 0; x < wMod16; x += 16) {
174 47 __m128i px1 = _mm_load_si128(reinterpret_cast<const __m128i*>(src+x)); //V1 Y3 U1 Y2 V0 Y1 U0 Y0
175 94 __m128i px2 = _mm_load_si128(reinterpret_cast<const __m128i*>(luma+x)); //v1 y3 u1 y2 v0 y1 u0 y0
176
177 47 __m128i src_lo = _mm_unpacklo_epi16(px1, px2); //v0 y1 V0 Y1 u0 y0 U0 Y0
178 47 __m128i src_hi = _mm_unpackhi_epi16(px1, px2);
179
180 47 src_lo = _mm_and_si128(src_lo, luma_mask); //00 v0 00 V0 00 u0 00 U0
181 47 src_hi = _mm_and_si128(src_hi, luma_mask);
182
183 47 src_lo = _mm_madd_epi16(src_lo, mask);
184 47 src_hi = _mm_madd_epi16(src_hi, mask);
185
186 47 src_lo = _mm_add_epi32(src_lo, round_mask);
187 47 src_hi = _mm_add_epi32(src_hi, round_mask);
188
189 47 src_lo = _mm_srli_epi32(src_lo, 15);
190 47 src_hi = _mm_srli_epi32(src_hi, 15);
191
192 47 __m128i result_luma = _mm_packs_epi32(src_lo, src_hi);
193
194 47 __m128i result_chroma = _mm_and_si128(px1, chroma_mask);
195 47 __m128i result = _mm_or_si128(result_chroma, result_luma);
196
197 47 _mm_store_si128(reinterpret_cast<__m128i*>(src+x), result);
198 }
199
200
2/2
✓ Branch 53 → 52 taken 98 times.
✓ Branch 53 → 54 taken 18 times.
116 for (int x = wMod16; x < width; x+=2) {
201 98 src[x] = (luma[x] * weight + src[x] * invweight + 16384) >> 15;
202 }
203
204 18 src += pitch;
205 18 luma += luma_pitch;
206 }
207 2 }
208
209 #ifdef X86_32
210 void weighted_merge_luma_yuy2_mmx(BYTE *src, const BYTE *luma, int pitch, int luma_pitch,int width, int height, int weight, int invweight)
211 {
212 __m64 round_mask = _mm_set1_pi32(0x4000);
213 __m64 mask = _mm_set_pi16(weight, invweight, weight, invweight);
214 __m64 luma_mask = _mm_set1_pi16(0x00FF);
215 __m64 chroma_mask = _mm_set1_pi16((short)0xFF00);
216
217 int wMod8 = (width/8) * 8;
218
219 for (int y = 0; y < height; y++) {
220 for (int x = 0; x < wMod8; x += 8) {
221 __m64 px1 = *reinterpret_cast<const __m64*>(src+x); //V1 Y3 U1 Y2 V0 Y1 U0 Y0
222 __m64 px2 = *reinterpret_cast<const __m64*>(luma+x); //v1 y3 u1 y2 v0 y1 u0 y0
223
224 __m64 src_lo = _mm_unpacklo_pi16(px1, px2); //v0 y1 V0 Y1 u0 y0 U0 Y0
225 __m64 src_hi = _mm_unpackhi_pi16(px1, px2);
226
227 src_lo = _mm_and_si64(src_lo, luma_mask); //00 v0 00 V0 00 u0 00 U0
228 src_hi = _mm_and_si64(src_hi, luma_mask);
229
230 src_lo = _mm_madd_pi16(src_lo, mask);
231 src_hi = _mm_madd_pi16(src_hi, mask);
232
233 src_lo = _mm_add_pi32(src_lo, round_mask);
234 src_hi = _mm_add_pi32(src_hi, round_mask);
235
236 src_lo = _mm_srli_pi32(src_lo, 15);
237 src_hi = _mm_srli_pi32(src_hi, 15);
238
239 __m64 result_luma = _mm_packs_pi32(src_lo, src_hi);
240
241 __m64 result_chroma = _mm_and_si64(px1, chroma_mask);
242 __m64 result = _mm_or_si64(result_chroma, result_luma);
243
244 *reinterpret_cast<__m64*>(src+x) = result;
245 }
246
247 for (int x = wMod8; x < width; x+=2) {
248 src[x] = (luma[x] * weight + src[x] * invweight + 16384) >> 15;
249 }
250
251 src += pitch;
252 luma += luma_pitch;
253 }
254 _mm_empty();
255 }
256 #endif
257
258
259 /* -----------------------------------
260 * replace_luma_yuy2
261 * -----------------------------------
262 */
263 2 void replace_luma_yuy2_sse2(BYTE *src, const BYTE *luma, int pitch, int luma_pitch,int width, int height)
264 {
265 2 int mod16_width = width / 16 * 16;
266 2 __m128i luma_mask = _mm_set1_epi16(0x00FF);
267 2 __m128i chroma_mask = _mm_set1_epi16((short)0xFF00);
268
269
2/2
✓ Branch 29 → 11 taken 18 times.
✓ Branch 29 → 30 taken 2 times.
20 for(int y = 0; y < height; y++) {
270
2/2
✓ Branch 24 → 12 taken 47 times.
✓ Branch 24 → 25 taken 18 times.
65 for(int x = 0; x < mod16_width; x+=16) {
271 47 __m128i s = _mm_load_si128(reinterpret_cast<const __m128i*>(src+x));
272 94 __m128i l = _mm_load_si128(reinterpret_cast<const __m128i*>(luma+x));
273
274 47 __m128i s_chroma = _mm_and_si128(s, chroma_mask);
275 47 __m128i l_luma = _mm_and_si128(l, luma_mask);
276
277 47 __m128i result = _mm_or_si128(s_chroma, l_luma);
278
279 47 _mm_store_si128(reinterpret_cast<__m128i*>(src+x), result);
280 }
281
282
2/2
✓ Branch 27 → 26 taken 98 times.
✓ Branch 27 → 28 taken 18 times.
116 for (int x = mod16_width; x < width; x+=2) {
283 98 src[x] = luma[x];
284 }
285 18 src += pitch;
286 18 luma += luma_pitch;
287 }
288 2 }
289
290 #ifdef X86_32
291 void replace_luma_yuy2_mmx(BYTE *src, const BYTE *luma, int pitch, int luma_pitch,int width, int height)
292 {
293 int mod8_width = width / 8 * 8;
294 __m64 luma_mask = _mm_set1_pi16(0x00FF);
295 __m64 chroma_mask = _mm_set1_pi16((short)0xFF00);
296
297 for(int y = 0; y < height; y++) {
298 for(int x = 0; x < mod8_width; x+=8) {
299 __m64 s = *reinterpret_cast<const __m64*>(src+x);
300 __m64 l = *reinterpret_cast<const __m64*>(luma+x);
301
302 __m64 s_chroma = _mm_and_si64(s, chroma_mask);
303 __m64 l_luma = _mm_and_si64(l, luma_mask);
304
305 __m64 result = _mm_or_si64(s_chroma, l_luma);
306
307 *reinterpret_cast<__m64*>(src+x) = result;
308 }
309
310 for (int x = mod8_width; x < width; x+=2) {
311 src[x] = luma[x];
312 }
313 src += pitch;
314 luma += luma_pitch;
315 }
316 _mm_empty();
317 }
318 #endif
319
320
321
322 /* -----------------------------------
323 * average_plane
324 * -----------------------------------
325 */
326 // Can be called from Layer or Overlay, so no aligned loads/stores here and prepare for exact width
327 template<typename pixel_t>
328 6 void average_plane_sse2(BYTE *p1, const BYTE *p2, int p1_pitch, int p2_pitch, int rowsize, int height) {
329 // width is RowSize here
330 6 int mod16_width = rowsize / 16 * 16;
331
332
4/4
void average_plane_sse2<unsigned char>(unsigned char*, unsigned char const*, int, int, int, int):
✓ Branch 18 → 3 taken 15 times.
✓ Branch 18 → 19 taken 3 times.
void average_plane_sse2<unsigned short>(unsigned char*, unsigned char const*, int, int, int, int):
✓ Branch 18 → 3 taken 15 times.
✓ Branch 18 → 19 taken 3 times.
36 for(int y = 0; y < height; y++) {
333
4/4
void average_plane_sse2<unsigned char>(unsigned char*, unsigned char const*, int, int, int, int):
✓ Branch 12 → 4 taken 37 times.
✓ Branch 12 → 13 taken 15 times.
void average_plane_sse2<unsigned short>(unsigned char*, unsigned char const*, int, int, int, int):
✓ Branch 12 → 4 taken 37 times.
✓ Branch 12 → 13 taken 15 times.
104 for(int x = 0; x < mod16_width; x+=16) {
334 74 __m128i src1 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(p1+x));
335 148 __m128i src2 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(p2+x));
336 __m128i dst;
337 if constexpr(sizeof(pixel_t) == 1)
338 37 dst = _mm_avg_epu8(src1, src2); // 8 pixels
339 else // pixel_size == 2
340 37 dst = _mm_avg_epu16(src1, src2); // 4 pixels
341
342 74 _mm_storeu_si128(reinterpret_cast<__m128i*>(p1+x), dst);
343 }
344
345
4/4
void average_plane_sse2<unsigned char>(unsigned char*, unsigned char const*, int, int, int, int):
✓ Branch 13 → 14 taken 12 times.
✓ Branch 13 → 17 taken 3 times.
void average_plane_sse2<unsigned short>(unsigned char*, unsigned char const*, int, int, int, int):
✓ Branch 13 → 14 taken 12 times.
✓ Branch 13 → 17 taken 3 times.
30 if (mod16_width != rowsize) {
346
4/4
void average_plane_sse2<unsigned char>(unsigned char*, unsigned char const*, int, int, int, int):
✓ Branch 16 → 15 taken 110 times.
✓ Branch 16 → 17 taken 12 times.
void average_plane_sse2<unsigned short>(unsigned char*, unsigned char const*, int, int, int, int):
✓ Branch 16 → 15 taken 56 times.
✓ Branch 16 → 17 taken 12 times.
190 for (size_t x = mod16_width / sizeof(pixel_t); x < rowsize/sizeof(pixel_t); ++x) {
347 166 reinterpret_cast<pixel_t *>(p1)[x] = (int(reinterpret_cast<pixel_t *>(p1)[x]) + reinterpret_cast<const pixel_t *>(p2)[x] + 1) >> 1;
348 }
349 }
350 30 p1 += p1_pitch;
351 30 p2 += p2_pitch;
352 }
353 6 }
354
355 // instantiate
356 template void average_plane_sse2<uint8_t>(BYTE* p1, const BYTE* p2, int p1_pitch, int p2_pitch, int rowsize, int height);
357 template void average_plane_sse2<uint16_t>(BYTE* p1, const BYTE* p2, int p1_pitch, int p2_pitch, int rowsize, int height);
358
359 // weighted_merge_planar SSE2 implementations moved to overlay/intel/blend_common_sse.cpp
360 // (see weighted_merge_sse2 / weighted_merge_float_sse2)
361
362 3 void average_plane_sse2_float(BYTE *p1, const BYTE *p2, int p1_pitch, int p2_pitch, int rowsize, int height) {
363 3 auto OneHalf = _mm_set1_ps(0.5f);
364
365 3 int wMod16 = (rowsize / 16) * 16;
366
367
2/2
✓ Branch 21 → 5 taken 15 times.
✓ Branch 21 → 22 taken 3 times.
18 for (int y = 0; y < height; y++) {
368
2/2
✓ Branch 16 → 6 taken 67 times.
✓ Branch 16 → 17 taken 15 times.
82 for (int x = 0; x < wMod16; x += 16) {
369 67 auto px1 = _mm_loadu_ps(reinterpret_cast<const float*>(p1 + x));
370 134 auto px2 = _mm_loadu_ps(reinterpret_cast<const float*>(p2 + x));
371
372 67 auto result = _mm_mul_ps(_mm_add_ps(px1, px2), OneHalf);
373
374 67 _mm_storeu_ps(reinterpret_cast<float *>(p1 + x), result);
375 }
376
377
2/2
✓ Branch 19 → 18 taken 12 times.
✓ Branch 19 → 20 taken 15 times.
27 for (size_t x = wMod16 / sizeof(float); x < rowsize / sizeof(float); x++) {
378 12 reinterpret_cast<float *>(p1)[x] = (reinterpret_cast<float *>(p1)[x] + reinterpret_cast<const float *>(p2)[x]) * 0.5f;
379 }
380
381 15 p1 += p1_pitch;
382 15 p2 += p2_pitch;
383 }
384 3 }
385
386