GCC Code Coverage Report


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

filters/intel/resize_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 #include <avisynth.h>
36
37 // Intrinsics base header + really required extension headers
38 #if defined(_MSC_VER)
39 #include <intrin.h> // MSVC
40 #else
41 #include <x86intrin.h> // GCC/MinGW/Clang/LLVM
42 #endif
43
44
45
46 //todo: think of a way to do this with pavgb
47 static AVS_FORCEINLINE __m128i vertical_reduce_sse2_blend(__m128i& src, __m128i& src_next, __m128i& src_next2, __m128i& zero, __m128i& two) {
48 34 __m128i src_unpck_lo = _mm_unpacklo_epi8(src, zero);
49 17 __m128i src_unpck_hi = _mm_unpackhi_epi8(src, zero);
50
51 17 __m128i src_next_unpck_lo = _mm_unpacklo_epi8(src_next, zero);
52 17 __m128i src_next_unpck_hi = _mm_unpackhi_epi8(src_next, zero);
53
54 17 __m128i src_next2_unpck_lo = _mm_unpacklo_epi8(src_next2, zero);
55 34 __m128i src_next2_unpck_hi = _mm_unpackhi_epi8(src_next2, zero);
56
57 17 __m128i acc_lo = _mm_adds_epu16(src_next_unpck_lo, src_next_unpck_lo);
58 17 acc_lo = _mm_adds_epu16(acc_lo, src_unpck_lo);
59 17 acc_lo = _mm_adds_epu16(acc_lo, src_next2_unpck_lo);
60
61 17 __m128i acc_hi = _mm_adds_epu16(src_next_unpck_hi, src_next_unpck_hi);
62 17 acc_hi = _mm_adds_epu16(acc_hi, src_unpck_hi);
63 17 acc_hi = _mm_adds_epu16(acc_hi, src_next2_unpck_hi);
64
65 17 acc_lo = _mm_adds_epu16(acc_lo, two);
66 34 acc_hi = _mm_adds_epu16(acc_hi, two);
67
68 17 acc_lo = _mm_srai_epi16(acc_lo, 2);
69 17 acc_hi = _mm_srai_epi16(acc_hi, 2);
70
71 17 return _mm_packus_epi16(acc_lo, acc_hi);
72 }
73
74 2 void vertical_reduce_sse2(BYTE* dstp, const BYTE* srcp, int dst_pitch, int src_pitch, size_t width, size_t height) {
75 2 const BYTE* srcp_next = srcp + src_pitch;
76 2 const BYTE* srcp_next2 = srcp + src_pitch * 2;
77 2 __m128i zero = _mm_setzero_si128();
78 2 __m128i two = _mm_set1_epi16(2);
79
80
2/2
✓ Branch 56 → 9 taken 5 times.
✓ Branch 56 → 57 taken 2 times.
7 for (size_t y = 0; y < height - 1; ++y) {
81
2/2
✓ Branch 54 → 10 taken 13 times.
✓ Branch 54 → 55 taken 5 times.
18 for (size_t x = 0; x < width; x += 16) {
82 13 __m128i src = _mm_load_si128(reinterpret_cast<const __m128i*>(srcp + x));
83 13 __m128i src_next = _mm_load_si128(reinterpret_cast<const __m128i*>(srcp_next + x));
84 26 __m128i src_next2 = _mm_load_si128(reinterpret_cast<const __m128i*>(srcp_next2 + x));
85
86 13 __m128i avg = vertical_reduce_sse2_blend(src, src_next, src_next2, zero, two);
87
88 13 _mm_store_si128(reinterpret_cast<__m128i*>(dstp + x), avg);
89 }
90
91 5 dstp += dst_pitch;
92 5 srcp += src_pitch * 2;
93 5 srcp_next += src_pitch * 2;
94 5 srcp_next2 += src_pitch * 2;
95 }
96 //last line
97
2/2
✓ Branch 100 → 58 taken 4 times.
✓ Branch 100 → 101 taken 2 times.
6 for (size_t x = 0; x < width; x += 16) {
98 4 __m128i src = _mm_load_si128(reinterpret_cast<const __m128i*>(srcp + x));
99 8 __m128i src_next = _mm_load_si128(reinterpret_cast<const __m128i*>(srcp_next + x));
100
101 4 __m128i avg = vertical_reduce_sse2_blend(src, src_next, src_next, zero, two);
102
103 4 _mm_store_si128(reinterpret_cast<__m128i*>(dstp + x), avg);
104 }
105 2 }
106
107 #ifdef X86_32
108
109 //todo: think of a way to do this with pavgb
110 static AVS_FORCEINLINE __m64 vertical_reduce_mmx_blend(__m64& src, __m64& src_next, __m64& src_next2, __m64& zero, __m64& two) {
111 __m64 src_unpck_lo = _mm_unpacklo_pi8(src, zero);
112 __m64 src_unpck_hi = _mm_unpackhi_pi8(src, zero);
113
114 __m64 src_next_unpck_lo = _mm_unpacklo_pi8(src_next, zero);
115 __m64 src_next_unpck_hi = _mm_unpackhi_pi8(src_next, zero);
116
117 __m64 src_next2_unpck_lo = _mm_unpacklo_pi8(src_next2, zero);
118 __m64 src_next2_unpck_hi = _mm_unpackhi_pi8(src_next2, zero);
119
120 __m64 acc_lo = _mm_adds_pu16(src_next_unpck_lo, src_next_unpck_lo);
121 acc_lo = _mm_adds_pu16(acc_lo, src_unpck_lo);
122 acc_lo = _mm_adds_pu16(acc_lo, src_next2_unpck_lo);
123
124 __m64 acc_hi = _mm_adds_pu16(src_next_unpck_hi, src_next_unpck_hi);
125 acc_hi = _mm_adds_pu16(acc_hi, src_unpck_hi);
126 acc_hi = _mm_adds_pu16(acc_hi, src_next2_unpck_hi);
127
128 acc_lo = _mm_adds_pu16(acc_lo, two);
129 acc_hi = _mm_adds_pu16(acc_hi, two);
130
131 acc_lo = _mm_srai_pi16(acc_lo, 2);
132 acc_hi = _mm_srai_pi16(acc_hi, 2);
133
134 return _mm_packs_pu16(acc_lo, acc_hi);
135 }
136
137 void vertical_reduce_mmx(BYTE* dstp, const BYTE* srcp, int dst_pitch, int src_pitch, size_t width, size_t height) {
138 const BYTE* srcp_next = srcp + src_pitch;
139 const BYTE* srcp_next2 = srcp + src_pitch * 2;
140 __m64 zero = _mm_setzero_si64();
141 __m64 two = _mm_set1_pi16(2);
142
143 size_t mod8_width = width / 8 * 8;
144
145 for (size_t y = 0; y < height - 1; ++y) {
146 for (size_t x = 0; x < mod8_width; x += 8) {
147 __m64 src = *reinterpret_cast<const __m64*>(srcp + x);
148 __m64 src_next = *reinterpret_cast<const __m64*>(srcp_next + x);
149 __m64 src_next2 = *reinterpret_cast<const __m64*>(srcp_next2 + x);
150
151 __m64 avg = vertical_reduce_mmx_blend(src, src_next, src_next2, zero, two);
152
153 *reinterpret_cast<__m64*>(dstp + x) = avg;
154 }
155
156 if (mod8_width != width) {
157 size_t x = width - 8;
158 __m64 src = *reinterpret_cast<const __m64*>(srcp + x);
159 __m64 src_next = *reinterpret_cast<const __m64*>(srcp_next + x);
160 __m64 src_next2 = *reinterpret_cast<const __m64*>(srcp_next2 + x);
161
162 __m64 avg = vertical_reduce_mmx_blend(src, src_next, src_next2, zero, two);
163
164 *reinterpret_cast<__m64*>(dstp + x) = avg;
165 }
166
167 dstp += dst_pitch;
168 srcp += src_pitch * 2;
169 srcp_next += src_pitch * 2;
170 srcp_next2 += src_pitch * 2;
171 }
172 //last line
173 for (size_t x = 0; x < mod8_width; x += 8) {
174 __m64 src = *reinterpret_cast<const __m64*>(srcp + x);
175 __m64 src_next = *reinterpret_cast<const __m64*>(srcp_next + x);
176
177 __m64 avg = vertical_reduce_mmx_blend(src, src_next, src_next, zero, two);
178
179 *reinterpret_cast<__m64*>(dstp + x) = avg;
180 }
181
182 if (mod8_width != width) {
183 size_t x = width - 8;
184 __m64 src = *reinterpret_cast<const __m64*>(srcp + x);
185 __m64 src_next = *reinterpret_cast<const __m64*>(srcp_next + x);
186
187 __m64 avg = vertical_reduce_mmx_blend(src, src_next, src_next, zero, two);
188
189 *reinterpret_cast<__m64*>(dstp + x) = avg;
190 }
191
192 _mm_empty();
193 }
194 #endif
195
196
197
198