GCC Code Coverage Report


Directory: avs_core/
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 93.8% 61 / 0 / 65
Functions: 100.0% 3 / 0 / 3
Branches: 96.4% 27 / 0 / 28

filters/intel/merge_avx2.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 // Intrinsics base header + really required extension headers
43 #if defined(_MSC_VER)
44 #include <intrin.h> // MSVC
45 #else
46 #include <x86intrin.h> // GCC/MinGW/Clang/LLVM
47 #endif
48 #include <immintrin.h>
49
50
51 #if !defined(__FMA__)
52 // Assume that all processors that have AVX2 also have FMA3
53 #if defined(__GNUC__) && !defined(__INTEL_COMPILER) && !defined(__clang__)
54 // Prevent error message in g++ when using FMA intrinsics with avx2:
55 #pragma message "It is recommended to specify also option -mfma when using -mavx2 or higher"
56 #else
57 #define __FMA__ 1
58 #endif
59 #endif
60 // FMA3 instruction set
61 #if defined(__FMA__) && (defined(__GNUC__) || defined(__clang__)) && !defined(__INTEL_COMPILER)
62 #include <fmaintrin.h>
63 #endif // __FMA__
64
65 #include "merge_avx2.h"
66 #include <avisynth.h>
67 #include <avs/types.h>
68 #include <cstdint>
69
70 #ifndef _mm256_set_m128i
71 #define _mm256_set_m128i(v0, v1) _mm256_insertf128_si256(_mm256_castsi128_si256(v1), (v0), 1)
72 #endif
73
74 #ifndef _mm256_set_m128
75 #define _mm256_set_m128(v0, v1) _mm256_insertf128_ps(_mm256_castps128_ps256(v1), (v0), 1)
76 #endif
77
78 /* -----------------------------------
79 * average_plane
80 * -----------------------------------
81 */
82 // VS2017 15.5.1..2 optimizer generates illegal instructions for _mm_stream_load_si128 (vmovntdqa)
83 // just a note, don't use that.
84 // Can be called from Layer or Overlay, so no aligned loads/stores here and prepare for exact width
85 template<typename pixel_t>
86 15 void average_plane_avx2(BYTE *p1, const BYTE *p2, int p1_pitch, int p2_pitch, int rowsize, int height) {
87 // width is RowSize here
88 15 int mod32_width = rowsize / 32 * 32;
89 15 int mod16_width = rowsize / 16 * 16;
90
91
4/4
void average_plane_avx2<unsigned char>(unsigned char*, unsigned char const*, int, int, int, int):
✓ Branch 28 → 3 taken 47 times.
✓ Branch 28 → 29 taken 12 times.
void average_plane_avx2<unsigned short>(unsigned char*, unsigned char const*, int, int, int, int):
✓ Branch 28 → 3 taken 15 times.
✓ Branch 28 → 29 taken 3 times.
77 for(int y = 0; y < height; y++) {
92
4/4
void average_plane_avx2<unsigned char>(unsigned char*, unsigned char const*, int, int, int, int):
✓ Branch 12 → 4 taken 15 times.
✓ Branch 12 → 13 taken 47 times.
void average_plane_avx2<unsigned short>(unsigned char*, unsigned char const*, int, int, int, int):
✓ Branch 12 → 4 taken 15 times.
✓ Branch 12 → 13 taken 15 times.
92 for(int x = 0; x < mod32_width; x+=32) {
93 30 __m256i src1 = _mm256_loadu_si256(reinterpret_cast<__m256i*>(p1 + x));
94 60 __m256i src2 = _mm256_loadu_si256(const_cast<__m256i*>(reinterpret_cast<const __m256i*>(p2+x)));
95 __m256i dst;
96 if constexpr(sizeof(pixel_t) == 1)
97 15 dst = _mm256_avg_epu8(src1, src2); // 16 pixels
98 else // pixel_size == 2
99 15 dst = _mm256_avg_epu16(src1, src2); // 8 pixels
100
101 30 _mm256_storeu_si256(reinterpret_cast<__m256i*>(p1+x), dst);
102 }
103
104
4/4
void average_plane_avx2<unsigned char>(unsigned char*, unsigned char const*, int, int, int, int):
✓ Branch 22 → 14 taken 7 times.
✓ Branch 22 → 23 taken 47 times.
void average_plane_avx2<unsigned short>(unsigned char*, unsigned char const*, int, int, int, int):
✓ Branch 22 → 14 taken 7 times.
✓ Branch 22 → 23 taken 15 times.
76 for(int x = mod32_width; x < mod16_width; x+=16) {
105 14 __m128i src1 = _mm_loadu_si128(reinterpret_cast<__m128i*>(p1 + x));
106 28 __m128i src2 = _mm_loadu_si128(const_cast<__m128i*>(reinterpret_cast<const __m128i*>(p2 + x)));
107 __m128i dst;
108 if constexpr(sizeof(pixel_t) == 1)
109 7 dst = _mm_avg_epu8(src1, src2); // 8 pixels
110 else // pixel_size == 2
111 7 dst = _mm_avg_epu16(src1, src2); // 4 pixels
112
113 14 _mm_storeu_si128(reinterpret_cast<__m128i*>(p1+x), dst);
114 }
115
116
4/4
void average_plane_avx2<unsigned char>(unsigned char*, unsigned char const*, int, int, int, int):
✓ Branch 23 → 24 taken 44 times.
✓ Branch 23 → 27 taken 3 times.
void average_plane_avx2<unsigned short>(unsigned char*, unsigned char const*, int, int, int, int):
✓ Branch 23 → 24 taken 12 times.
✓ Branch 23 → 27 taken 3 times.
62 if (mod16_width != rowsize) {
117
4/4
void average_plane_avx2<unsigned char>(unsigned char*, unsigned char const*, int, int, int, int):
✓ Branch 26 → 25 taken 301 times.
✓ Branch 26 → 27 taken 44 times.
void average_plane_avx2<unsigned short>(unsigned char*, unsigned char const*, int, int, int, int):
✓ Branch 26 → 25 taken 56 times.
✓ Branch 26 → 27 taken 12 times.
413 for (size_t x = mod16_width / sizeof(pixel_t); x < rowsize/sizeof(pixel_t); ++x) {
118 357 reinterpret_cast<pixel_t *>(p1)[x] = (int(reinterpret_cast<pixel_t *>(p1)[x]) + reinterpret_cast<const pixel_t *>(p2)[x] + 1) >> 1;
119 }
120 }
121 62 p1 += p1_pitch;
122 62 p2 += p2_pitch;
123 }
124 15 }
125
126 // instantiate to let them access from other modules
127 template void average_plane_avx2<uint8_t>(BYTE *p1, const BYTE *p2, int p1_pitch, int p2_pitch, int rowsize, int height);
128 template void average_plane_avx2<uint16_t>(BYTE *p1, const BYTE *p2, int p1_pitch, int p2_pitch, int rowsize, int height);
129
130 // weighted_merge_planar AVX2 implementations moved to overlay/intel/blend_common_avx2.cpp
131 // (see weighted_merge_avx2 / weighted_merge_float_avx2)
132
133 3 void average_plane_avx2_float(BYTE* p1, const BYTE* p2, int p1_pitch, int p2_pitch, int rowsize, int height) {
134 3 const auto v_half = _mm256_set1_ps(0.5f);
135
136 // Process 64 bytes (16 floats) per iteration
137 3 const int wMod64 = (rowsize / 64) * 64;
138 // Process 32 bytes (8 floats) per iteration (for the remainder)
139 3 const int wMod32 = (rowsize / 32) * 32;
140
141
2/2
✓ Branch 42 → 5 taken 15 times.
✓ Branch 42 → 43 taken 3 times.
18 for (int y = 0; y < height; y++) {
142 15 int x = 0;
143
144 // 16 floats at a time
145
2/2
✓ Branch 25 → 6 taken 15 times.
✓ Branch 25 → 26 taken 15 times.
30 for (; x < wMod64; x += 64) {
146 // Load 16 floats from p1 and 16 from p2
147 15 auto p1_a = _mm256_loadu_ps(reinterpret_cast<const float*>(p1 + x));
148 15 auto p1_b = _mm256_loadu_ps(reinterpret_cast<const float*>(p1 + x + 32));
149 15 auto p2_a = _mm256_loadu_ps(reinterpret_cast<const float*>(p2 + x));
150 30 auto p2_b = _mm256_loadu_ps(reinterpret_cast<const float*>(p2 + x + 32));
151
152 // result = (p1 + p2) * 0.5
153 30 auto res_a = _mm256_mul_ps(_mm256_add_ps(p1_a, p2_a), v_half);
154 15 auto res_b = _mm256_mul_ps(_mm256_add_ps(p1_b, p2_b), v_half);
155
156 15 _mm256_storeu_ps(reinterpret_cast<float*>(p1 + x), res_a);
157 15 _mm256_storeu_ps(reinterpret_cast<float*>(p1 + x + 32), res_b);
158 }
159
160 // 8 floats at a time
161
1/2
✗ Branch 37 → 27 not taken.
✓ Branch 37 → 38 taken 15 times.
15 for (; x < wMod32; x += 32) {
162 auto px1 = _mm256_loadu_ps(reinterpret_cast<const float*>(p1 + x));
163 auto px2 = _mm256_loadu_ps(reinterpret_cast<const float*>(p2 + x));
164 auto res = _mm256_mul_ps(_mm256_add_ps(px1, px2), v_half);
165 _mm256_storeu_ps(reinterpret_cast<float*>(p1 + x), res);
166 }
167
168 // Scalar tail widths
169
2/2
✓ Branch 40 → 39 taken 40 times.
✓ Branch 40 → 41 taken 15 times.
55 for (int i = x / 4; i < rowsize / 4; i++) {
170 40 reinterpret_cast<float*>(p1)[i] = (reinterpret_cast<float*>(p1)[i] + reinterpret_cast<const float*>(p2)[i]) * 0.5f;
171 }
172
173 15 p1 += p1_pitch;
174 15 p2 += p2_pitch;
175 }
176 3 }
177
178