GCC Code Coverage Report


Directory: avs_core/
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 85.9% 407 / 0 / 474
Functions: 90.5% 19 / 0 / 21
Branches: 82.1% 87 / 0 / 106

filters/intel/layer_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
37 // Avisynth filter: Layer
38 // by "poptones" (poptones@myrealbox.com)
39
40 #include "layer_sse.h"
41 #include "../layer.h"
42
43 #ifdef AVS_WINDOWS
44 #include <avs/win.h>
45 #else
46 #include <avs/posix.h>
47 #endif
48
49 #include <avs/minmax.h>
50 #include <avs/alignment.h>
51 #include "../core/internal.h"
52
53 // Intrinsics base header + really required extension headers
54 #if defined(_MSC_VER)
55 #include <intrin.h> // MSVC
56 #else
57 #include <x86intrin.h> // GCC/MinGW/Clang/LLVM
58 #endif
59
60 #include "../convert/convert_planar.h"
61 #include <algorithm>
62
63
64 static AVS_FORCEINLINE __m128i mask_core_sse2(__m128i& src, __m128i& alpha, __m128i& not_alpha_mask, __m128i& zero, __m128i& matrix, __m128i& round_mask) {
65 18 __m128i not_alpha = _mm_and_si128(src, not_alpha_mask);
66
67 9 __m128i pixel0 = _mm_unpacklo_epi8(alpha, zero);
68 9 __m128i pixel1 = _mm_unpackhi_epi8(alpha, zero);
69
70 9 pixel0 = _mm_madd_epi16(pixel0, matrix);
71 18 pixel1 = _mm_madd_epi16(pixel1, matrix);
72
73 27 __m128i tmp = _mm_castps_si128(_mm_shuffle_ps(_mm_castsi128_ps(pixel0), _mm_castsi128_ps(pixel1), _MM_SHUFFLE(3, 1, 3, 1)));
74 27 __m128i tmp2 = _mm_castps_si128(_mm_shuffle_ps(_mm_castsi128_ps(pixel0), _mm_castsi128_ps(pixel1), _MM_SHUFFLE(2, 0, 2, 0)));
75
76 9 tmp = _mm_add_epi32(tmp, tmp2);
77 18 tmp = _mm_add_epi32(tmp, round_mask);
78 9 tmp = _mm_srli_epi32(tmp, 15);
79 9 __m128i result_alpha = _mm_slli_epi32(tmp, 24);
80
81 9 return _mm_or_si128(result_alpha, not_alpha);
82 }
83
84 1 void mask_sse2(BYTE* srcp, const BYTE* alphap, int src_pitch, int alpha_pitch, size_t width, size_t height) {
85 1 __m128i matrix = _mm_set_epi16(0, cyr, cyg, cyb, 0, cyr, cyg, cyb);
86 1 __m128i zero = _mm_setzero_si128();
87 1 __m128i round_mask = _mm_set1_epi32(16384);
88 1 __m128i not_alpha_mask = _mm_set1_epi32(0x00FFFFFF);
89
90 1 size_t width_bytes = width * 4;
91 1 size_t width_mod16 = width_bytes / 16 * 16;
92
93
2/2
✓ Branch 99 → 15 taken 3 times.
✓ Branch 99 → 100 taken 1 time.
4 for (size_t y = 0; y < height; ++y) {
94
2/2
✓ Branch 56 → 16 taken 6 times.
✓ Branch 56 → 57 taken 3 times.
9 for (size_t x = 0; x < width_mod16; x += 16) {
95 6 __m128i src = _mm_load_si128(reinterpret_cast<const __m128i*>(srcp + x));
96 12 __m128i alpha = _mm_load_si128(reinterpret_cast<const __m128i*>(alphap + x));
97 6 __m128i result = mask_core_sse2(src, alpha, not_alpha_mask, zero, matrix, round_mask);
98
99 6 _mm_store_si128(reinterpret_cast<__m128i*>(srcp + x), result);
100 }
101
102
1/2
✓ Branch 57 → 58 taken 3 times.
✗ Branch 57 → 98 not taken.
3 if (width_mod16 < width_bytes) {
103 3 __m128i src = _mm_loadu_si128(reinterpret_cast<const __m128i*>(srcp + width_bytes - 16));
104 6 __m128i alpha = _mm_loadu_si128(reinterpret_cast<const __m128i*>(alphap + width_bytes - 16));
105 3 __m128i result = mask_core_sse2(src, alpha, not_alpha_mask, zero, matrix, round_mask);
106
107 3 _mm_storeu_si128(reinterpret_cast<__m128i*>(srcp + width_bytes - 16), result);
108 }
109
110 3 srcp += src_pitch;
111 3 alphap += alpha_pitch;
112 }
113 1 }
114
115 1 void colorkeymask_sse2(BYTE* pf, int pitch, int color, int height, int width, int tolB, int tolG, int tolR) {
116 1 unsigned int t = 0xFF000000 | (tolR << 16) | (tolG << 8) | tolB;
117 2 __m128i tolerance = _mm_set1_epi32(t);
118 1 __m128i colorv = _mm_set1_epi32(color);
119 1 __m128i zero = _mm_setzero_si128();
120
121 1 BYTE* endp = pf + pitch * height;
122
123
2/2
✓ Branch 31 → 13 taken 12 times.
✓ Branch 31 → 32 taken 1 time.
13 while (pf < endp)
124 {
125 12 __m128i src = _mm_load_si128(reinterpret_cast<const __m128i*>(pf));
126 12 __m128i gt = _mm_subs_epu8(colorv, src);
127 12 __m128i lt = _mm_subs_epu8(src, colorv);
128 12 __m128i absdiff = _mm_or_si128(gt, lt); //abs(color - src)
129
130 12 __m128i not_passed = _mm_subs_epu8(absdiff, tolerance);
131 12 __m128i passed = _mm_cmpeq_epi32(not_passed, zero);
132 12 passed = _mm_slli_epi32(passed, 24);
133 12 __m128i result = _mm_andnot_si128(passed, src);
134
135 _mm_store_si128(reinterpret_cast<__m128i*>(pf), result);
136
137 12 pf += 16;
138 }
139 1 }
140
141
142 2 void invert_frame_inplace_sse2(BYTE* frame, int pitch, int width, int height, int mask) {
143 2 __m128i maskv = _mm_set1_epi32(mask);
144
145 2 BYTE* endp = frame + pitch * height;
146
147
2/2
✓ Branch 13 → 7 taken 58 times.
✓ Branch 13 → 14 taken 2 times.
60 while (frame < endp) {
148 58 __m128i src = _mm_load_si128(reinterpret_cast<const __m128i*>(frame));
149 58 __m128i inv = _mm_xor_si128(src, maskv);
150 _mm_store_si128(reinterpret_cast<__m128i*>(frame), inv);
151 58 frame += 16;
152 }
153 2 }
154
155 2 void invert_frame_uint16_inplace_sse2(BYTE* frame, int pitch, int width, int height, uint64_t mask64) {
156 2 __m128i maskv = _mm_set_epi32((uint32_t)(mask64 >> 32), (uint32_t)mask64, (uint32_t)(mask64 >> 32), (uint32_t)mask64);
157
158 2 BYTE* endp = frame + pitch * height;
159
160
2/2
✓ Branch 11 → 5 taken 58 times.
✓ Branch 11 → 12 taken 2 times.
60 while (frame < endp) {
161 58 __m128i src = _mm_load_si128(reinterpret_cast<const __m128i*>(frame));
162 58 __m128i inv = _mm_xor_si128(src, maskv);
163 _mm_store_si128(reinterpret_cast<__m128i*>(frame), inv);
164 58 frame += 16;
165 }
166 2 }
167
168 template<bool chroma>
169 2 void invert_plane_sse2_u8(uint8_t* dstp, const uint8_t* srcp, int src_pitch, int dst_pitch, int width, int height, int /*bits_per_pixel*/)
170 {
171 2 const __m128i v_ff = _mm_set1_epi8((char)0xFF);
172 2 const __m128i v_one = _mm_set1_epi8(1);
173
4/4
void invert_plane_sse2_u8<false>(unsigned char*, unsigned char const*, int, int, int, int, int):
✓ Branch 20 → 11 taken 3 times.
✓ Branch 20 → 21 taken 1 time.
void invert_plane_sse2_u8<true>(unsigned char*, unsigned char const*, int, int, int, int, int):
✓ Branch 22 → 11 taken 3 times.
✓ Branch 22 → 23 taken 1 time.
8 for (int y = 0; y < height; ++y) {
174
175
4/4
void invert_plane_sse2_u8<false>(unsigned char*, unsigned char const*, int, int, int, int, int):
✓ Branch 18 → 12 taken 12 times.
✓ Branch 18 → 19 taken 3 times.
void invert_plane_sse2_u8<true>(unsigned char*, unsigned char const*, int, int, int, int, int):
✓ Branch 20 → 12 taken 12 times.
✓ Branch 20 → 21 taken 3 times.
30 for (int x = 0; x < width; x += 16) {
176 48 __m128i s = _mm_load_si128(reinterpret_cast<const __m128i*>(srcp + x));
177 __m128i r;
178 if constexpr (chroma)
179 12 r = _mm_xor_si128(_mm_subs_epu8(s, v_one), v_ff);
180 else
181 12 r = _mm_xor_si128(s, v_ff);
182 24 _mm_store_si128(reinterpret_cast<__m128i*>(dstp + x), r);
183 }
184 6 srcp += src_pitch;
185 6 dstp += dst_pitch;
186 }
187 2 }
188
189 template<bool chroma>
190 10 void invert_plane_sse2_u16(uint8_t* dstp, const uint8_t* srcp, int src_pitch, int dst_pitch, int width, int height, int bits_per_pixel)
191 {
192 10 const int max_pixel_value = (1 << bits_per_pixel) - 1;
193 20 const __m128i v_max = _mm_set1_epi16((short)max_pixel_value);
194 10 const __m128i v_one = _mm_set1_epi16(1);
195
4/4
void invert_plane_sse2_u16<false>(unsigned char*, unsigned char const*, int, int, int, int, int):
✓ Branch 20 → 11 taken 17 times.
✓ Branch 20 → 21 taken 5 times.
void invert_plane_sse2_u16<true>(unsigned char*, unsigned char const*, int, int, int, int, int):
✓ Branch 22 → 11 taken 17 times.
✓ Branch 22 → 23 taken 5 times.
44 for (int y = 0; y < height; ++y) {
196 34 const uint16_t* s16 = reinterpret_cast<const uint16_t*>(srcp);
197 34 uint16_t* d16 = reinterpret_cast<uint16_t*>(dstp);
198
4/4
void invert_plane_sse2_u16<false>(unsigned char*, unsigned char const*, int, int, int, int, int):
✓ Branch 18 → 12 taken 68 times.
✓ Branch 18 → 19 taken 17 times.
void invert_plane_sse2_u16<true>(unsigned char*, unsigned char const*, int, int, int, int, int):
✓ Branch 20 → 12 taken 68 times.
✓ Branch 20 → 21 taken 17 times.
170 for (int x = 0; x < width; x += 8) {
199 272 __m128i s = _mm_load_si128(reinterpret_cast<const __m128i*>(s16 + x));
200 __m128i r;
201 if constexpr (chroma)
202 68 r = _mm_xor_si128(_mm_subs_epu16(s, v_one), v_max);
203 else
204 68 r = _mm_xor_si128(s, v_max);
205 136 _mm_store_si128(reinterpret_cast<__m128i*>(d16 + x), r);
206 }
207 34 srcp += src_pitch;
208 34 dstp += dst_pitch;
209 }
210 10 }
211
212 template<bool chroma>
213 4 void invert_plane_sse2_f32(uint8_t* dstp, const uint8_t* srcp, int src_pitch, int dst_pitch, int width, int height, int /*bits_per_pixel*/)
214 {
215 4 const __m128 v_one = _mm_set1_ps(1.0f);
216 4 const __m128 v_sign = _mm_set1_ps(-0.0f);
217
4/4
void invert_plane_sse2_f32<false>(unsigned char*, unsigned char const*, int, int, int, int, int):
✓ Branch 16 → 7 taken 8 times.
✓ Branch 16 → 17 taken 2 times.
void invert_plane_sse2_f32<true>(unsigned char*, unsigned char const*, int, int, int, int, int):
✓ Branch 16 → 7 taken 8 times.
✓ Branch 16 → 17 taken 2 times.
20 for (int y = 0; y < height; ++y) {
218 16 const float* sf = reinterpret_cast<const float*>(srcp);
219 16 float* df = reinterpret_cast<float*>(dstp);
220
4/4
void invert_plane_sse2_f32<false>(unsigned char*, unsigned char const*, int, int, int, int, int):
✓ Branch 14 → 8 taken 32 times.
✓ Branch 14 → 15 taken 8 times.
void invert_plane_sse2_f32<true>(unsigned char*, unsigned char const*, int, int, int, int, int):
✓ Branch 14 → 8 taken 32 times.
✓ Branch 14 → 15 taken 8 times.
80 for (int x = 0; x < width; x += 4) {
221 128 __m128 s = _mm_load_ps(sf + x);
222 64 __m128 r = chroma ? _mm_xor_ps(s, v_sign) : _mm_sub_ps(v_one, s);
223 64 _mm_store_ps(df + x, r);
224 }
225 16 srcp += src_pitch; dstp += dst_pitch;
226 }
227 4 }
228
229 template void invert_plane_sse2_u8<false>(uint8_t*, const uint8_t*, int, int, int, int, int);
230 template void invert_plane_sse2_u8<true>(uint8_t*, const uint8_t*, int, int, int, int, int);
231 template void invert_plane_sse2_u16<false>(uint8_t*, const uint8_t*, int, int, int, int, int);
232 template void invert_plane_sse2_u16<true>(uint8_t*, const uint8_t*, int, int, int, int, int);
233 template void invert_plane_sse2_f32<false>(uint8_t*, const uint8_t*, int, int, int, int, int);
234 template void invert_plane_sse2_f32<true>(uint8_t*, const uint8_t*, int, int, int, int, int);
235
236 /*******************************
237 ******* Layer Filter ******
238 *******************************/
239
240 1 void layer_rgb32_fast_sse2(BYTE* dstp, const BYTE* ovrp, int dst_pitch, int overlay_pitch, int width, int height, int level) {
241 AVS_UNUSED(level);
242 1 int width_bytes = width * 4;
243 1 int width_mod16 = width_bytes / 16 * 16;
244
245
2/2
✓ Branch 17 → 3 taken 3 times.
✓ Branch 17 → 18 taken 1 time.
4 for (int y = 0; y < height; ++y) {
246
2/2
✓ Branch 12 → 4 taken 6 times.
✓ Branch 12 → 13 taken 3 times.
9 for (int x = 0; x < width_mod16; x += 16) {
247 6 __m128i src = _mm_load_si128(reinterpret_cast<const __m128i*>(dstp + x));
248 12 __m128i ovr = _mm_load_si128(reinterpret_cast<const __m128i*>(ovrp + x));
249
250 6 _mm_store_si128(reinterpret_cast<__m128i*>(dstp + x), _mm_avg_epu8(src, ovr));
251 }
252
253
2/2
✓ Branch 15 → 14 taken 36 times.
✓ Branch 15 → 16 taken 3 times.
39 for (int x = width_mod16; x < width_bytes; ++x) {
254 36 dstp[x] = (dstp[x] + ovrp[x] + 1) / 2;
255 }
256
257 3 dstp += dst_pitch;
258 3 ovrp += overlay_pitch;
259 }
260 1 }
261
262
263 template<typename pixel_t>
264 4 void layer_genericplane_fast_sse2(BYTE* dstp, const BYTE* ovrp, int dst_pitch, int overlay_pitch, int width, int height, int level) {
265 AVS_UNUSED(level);
266 4 int width_bytes = width * sizeof(pixel_t);
267 4 int width_mod16 = width_bytes / 16 * 16;
268
269
4/4
void layer_genericplane_fast_sse2<unsigned char>(unsigned char*, unsigned char const*, int, int, int, int, int):
✓ Branch 17 → 3 taken 10 times.
✓ Branch 17 → 18 taken 2 times.
void layer_genericplane_fast_sse2<unsigned short>(unsigned char*, unsigned char const*, int, int, int, int, int):
✓ Branch 17 → 3 taken 10 times.
✓ Branch 17 → 18 taken 2 times.
24 for (int y = 0; y < height; ++y) {
270
4/4
void layer_genericplane_fast_sse2<unsigned char>(unsigned char*, unsigned char const*, int, int, int, int, int):
✓ Branch 12 → 4 taken 20 times.
✓ Branch 12 → 13 taken 10 times.
void layer_genericplane_fast_sse2<unsigned short>(unsigned char*, unsigned char const*, int, int, int, int, int):
✓ Branch 12 → 4 taken 20 times.
✓ Branch 12 → 13 taken 10 times.
60 for (int x = 0; x < width_mod16; x += 16) {
271 40 __m128i src = _mm_loadu_si128(reinterpret_cast<const __m128i*>(dstp + x));
272 80 __m128i ovr = _mm_loadu_si128(reinterpret_cast<const __m128i*>(ovrp + x));
273 if constexpr (sizeof(pixel_t) == 1)
274 20 _mm_storeu_si128(reinterpret_cast<__m128i*>(dstp + x), _mm_avg_epu8(src, ovr));
275 else
276 20 _mm_storeu_si128(reinterpret_cast<__m128i*>(dstp + x), _mm_avg_epu16(src, ovr));
277 }
278
279
4/4
void layer_genericplane_fast_sse2<unsigned char>(unsigned char*, unsigned char const*, int, int, int, int, int):
✓ Branch 15 → 14 taken 114 times.
✓ Branch 15 → 16 taken 10 times.
void layer_genericplane_fast_sse2<unsigned short>(unsigned char*, unsigned char const*, int, int, int, int, int):
✓ Branch 15 → 14 taken 52 times.
✓ Branch 15 → 16 taken 10 times.
186 for (int x = width_mod16 / sizeof(pixel_t); x < width; ++x) {
280 166 reinterpret_cast<pixel_t*>(dstp)[x] = (reinterpret_cast<pixel_t*>(dstp)[x] + reinterpret_cast<const pixel_t*>(ovrp)[x] + 1) / 2;
281 }
282
283 20 dstp += dst_pitch;
284 20 ovrp += overlay_pitch;
285 }
286 4 }
287
288 // instantiate
289 template void layer_genericplane_fast_sse2<uint8_t>(BYTE* dstp, const BYTE* ovrp, int dst_pitch, int overlay_pitch, int width, int height, int level);
290 template void layer_genericplane_fast_sse2<uint16_t>(BYTE* dstp, const BYTE* ovrp, int dst_pitch, int overlay_pitch, int width, int height, int level);
291
292 /* RGB32 */
293
294 //src format: xx xx xx xx | xx xx xx xx | a1 xx xx xx | a0 xx xx xx
295 //level_vector and one should be vectors of 32bit packed integers
296 static AVS_FORCEINLINE __m128i calculate_monochrome_alpha_sse2(const __m128i& src, const __m128i& level_vector, const __m128i& one) {
297 576 __m128i alpha = _mm_srli_epi32(src, 24);
298 288 alpha = _mm_mullo_epi16(alpha, level_vector);
299 576 alpha = _mm_add_epi32(alpha, one);
300 288 alpha = _mm_srli_epi32(alpha, 8);
301 288 alpha = _mm_shufflelo_epi16(alpha, _MM_SHUFFLE(2, 2, 0, 0));
302 288 return _mm_shuffle_epi32(alpha, _MM_SHUFFLE(1, 1, 0, 0));
303 }
304
305 static AVS_FORCEINLINE __m128i calculate_luma_sse2(const __m128i& src, const __m128i& rgb_coeffs, const __m128i& zero) {
306 AVS_UNUSED(zero);
307 96 __m128i temp = _mm_madd_epi16(src, rgb_coeffs);
308 336 __m128i low = _mm_shuffle_epi32(temp, _MM_SHUFFLE(3, 3, 1, 1));
309 336 temp = _mm_add_epi32(low, temp);
310 336 temp = _mm_srli_epi32(temp, 15);
311 336 __m128i result = _mm_shufflelo_epi16(temp, _MM_SHUFFLE(0, 0, 0, 0));
312 336 return _mm_shufflehi_epi16(result, _MM_SHUFFLE(0, 0, 0, 0));
313 }
314
315 // must be unaligned load/store
316 template<bool use_chroma>
317 6 void layer_rgb32_mul_sse2(BYTE* dstp, const BYTE* ovrp, int dst_pitch, int overlay_pitch, int width, int height, int level) {
318 6 int mod2_width = width / 2 * 2;
319
320 6 __m128i zero = _mm_setzero_si128();
321 6 __m128i level_vector = _mm_set1_epi32(level);
322 6 __m128i one = _mm_set1_epi32(1);
323 6 __m128i rgb_coeffs = _mm_set_epi16(0, cyr, cyg, cyb, 0, cyr, cyg, cyb);
324
325
4/4
void layer_rgb32_mul_sse2<false>(unsigned char*, unsigned char const*, int, int, int, int, int):
✓ Branch 72 → 15 taken 11 times.
✓ Branch 72 → 73 taken 3 times.
void layer_rgb32_mul_sse2<true>(unsigned char*, unsigned char const*, int, int, int, int, int):
✓ Branch 65 → 15 taken 11 times.
✓ Branch 65 → 66 taken 3 times.
28 for (int y = 0; y < height; ++y) {
326
4/4
void layer_rgb32_mul_sse2<false>(unsigned char*, unsigned char const*, int, int, int, int, int):
✓ Branch 67 → 16 taken 48 times.
✓ Branch 67 → 68 taken 11 times.
void layer_rgb32_mul_sse2<true>(unsigned char*, unsigned char const*, int, int, int, int, int):
✓ Branch 60 → 16 taken 48 times.
✓ Branch 60 → 61 taken 11 times.
118 for (int x = 0; x < mod2_width; x += 2) {
327 96 __m128i src = _mm_loadl_epi64(reinterpret_cast<const __m128i*>(dstp + x * 4));
328 192 __m128i ovr = _mm_loadl_epi64(reinterpret_cast<const __m128i*>(ovrp + x * 4));
329
330 96 __m128i alpha = calculate_monochrome_alpha_sse2(ovr, level_vector, one);
331
332 96 src = _mm_unpacklo_epi8(src, zero);
333 192 ovr = _mm_unpacklo_epi8(ovr, zero);
334
335 __m128i luma;
336 if (use_chroma) {
337 48 luma = ovr;
338 }
339 else {
340 48 luma = calculate_luma_sse2(ovr, rgb_coeffs, zero);
341 }
342
343 96 __m128i dst = _mm_mullo_epi16(luma, src);
344 96 dst = _mm_srli_epi16(dst, 8);
345 96 dst = _mm_subs_epi16(dst, src);
346 96 dst = _mm_mullo_epi16(dst, alpha);
347 96 dst = _mm_srli_epi16(dst, 8);
348 96 dst = _mm_add_epi8(src, dst);
349
350 96 dst = _mm_packus_epi16(dst, zero);
351
352 96 _mm_storel_epi64(reinterpret_cast<__m128i*>(dstp + x * 4), dst);
353 }
354
355
2/4
void layer_rgb32_mul_sse2<false>(unsigned char*, unsigned char const*, int, int, int, int, int):
✓ Branch 68 → 69 taken 11 times.
✗ Branch 68 → 71 not taken.
void layer_rgb32_mul_sse2<true>(unsigned char*, unsigned char const*, int, int, int, int, int):
✓ Branch 61 → 62 taken 11 times.
✗ Branch 61 → 64 not taken.
22 if (width != mod2_width) {
356 22 int x = mod2_width;
357 22 int alpha = (ovrp[x * 4 + 3] * level + 1) >> 8;
358
359 if (use_chroma) {
360 11 dstp[x * 4] = dstp[x * 4] + (((((ovrp[x * 4] * dstp[x * 4]) >> 8) - dstp[x * 4]) * alpha) >> 8);
361 11 dstp[x * 4 + 1] = dstp[x * 4 + 1] + (((((ovrp[x * 4 + 1] * dstp[x * 4 + 1]) >> 8) - dstp[x * 4 + 1]) * alpha) >> 8);
362 11 dstp[x * 4 + 2] = dstp[x * 4 + 2] + (((((ovrp[x * 4 + 2] * dstp[x * 4 + 2]) >> 8) - dstp[x * 4 + 2]) * alpha) >> 8);
363 11 dstp[x * 4 + 3] = dstp[x * 4 + 3] + (((((ovrp[x * 4 + 3] * dstp[x * 4 + 3]) >> 8) - dstp[x * 4 + 3]) * alpha) >> 8);
364 }
365 else {
366 11 int luma = (cyb * ovrp[x * 4] + cyg * ovrp[x * 4 + 1] + cyr * ovrp[x * 4 + 2]) >> 15;
367
368 11 dstp[x * 4] = dstp[x * 4] + (((((luma * dstp[x * 4]) >> 8) - dstp[x * 4]) * alpha) >> 8);
369 11 dstp[x * 4 + 1] = dstp[x * 4 + 1] + (((((luma * dstp[x * 4 + 1]) >> 8) - dstp[x * 4 + 1]) * alpha) >> 8);
370 11 dstp[x * 4 + 2] = dstp[x * 4 + 2] + (((((luma * dstp[x * 4 + 2]) >> 8) - dstp[x * 4 + 2]) * alpha) >> 8);
371 11 dstp[x * 4 + 3] = dstp[x * 4 + 3] + (((((luma * dstp[x * 4 + 3]) >> 8) - dstp[x * 4 + 3]) * alpha) >> 8);
372 }
373 }
374
375 22 dstp += dst_pitch;
376 22 ovrp += overlay_pitch;
377 }
378 6 }
379
380 // instantiate
381 template void layer_rgb32_mul_sse2<false>(BYTE* dstp, const BYTE* ovrp, int dst_pitch, int overlay_pitch, int width, int height, int level);
382 template void layer_rgb32_mul_sse2<true>(BYTE* dstp, const BYTE* ovrp, int dst_pitch, int overlay_pitch, int width, int height, int level);
383
384
385 // must be unaligned load/store
386 template<bool use_chroma>
387 3 void layer_rgb32_add_sse2(BYTE* dstp, const BYTE* ovrp, int dst_pitch, int overlay_pitch, int width, int height, int level) {
388 3 int mod2_width = width / 2 * 2;
389
390 3 __m128i zero = _mm_setzero_si128();
391 3 __m128i level_vector = _mm_set1_epi32(level);
392 3 __m128i one = _mm_set1_epi32(1);
393 3 __m128i rgb_coeffs = _mm_set_epi16(0, cyr, cyg, cyb, 0, cyr, cyg, cyb);
394
395 3 constexpr int rounder = 128;
396 3 const __m128i rounder_simd = _mm_set1_epi16(rounder);
397
398
2/4
void layer_rgb32_add_sse2<false>(unsigned char*, unsigned char const*, int, int, int, int, int):
✓ Branch 74 → 19 taken 11 times.
✓ Branch 74 → 75 taken 3 times.
void layer_rgb32_add_sse2<true>(unsigned char*, unsigned char const*, int, int, int, int, int):
✗ Branch 67 → 19 not taken.
✗ Branch 67 → 68 not taken.
14 for (int y = 0; y < height; ++y) {
399
2/4
void layer_rgb32_add_sse2<false>(unsigned char*, unsigned char const*, int, int, int, int, int):
✓ Branch 69 → 20 taken 48 times.
✓ Branch 69 → 70 taken 11 times.
void layer_rgb32_add_sse2<true>(unsigned char*, unsigned char const*, int, int, int, int, int):
✗ Branch 62 → 20 not taken.
✗ Branch 62 → 63 not taken.
59 for (int x = 0; x < mod2_width; x += 2) {
400 48 __m128i src = _mm_loadl_epi64(reinterpret_cast<const __m128i*>(dstp + x * 4));
401 96 __m128i ovr = _mm_loadl_epi64(reinterpret_cast<const __m128i*>(ovrp + x * 4));
402
403 48 __m128i alpha = calculate_monochrome_alpha_sse2(ovr, level_vector, one);
404
405 48 src = _mm_unpacklo_epi8(src, zero);
406 96 ovr = _mm_unpacklo_epi8(ovr, zero);
407
408 __m128i luma;
409 if (use_chroma) {
410 luma = ovr;
411 }
412 else {
413 48 luma = calculate_luma_sse2(ovr, rgb_coeffs, zero);
414 }
415
416 48 __m128i dst = _mm_subs_epi16(luma, src);
417 48 dst = _mm_mullo_epi16(dst, alpha);
418 48 dst = _mm_add_epi16(dst, rounder_simd);
419 48 dst = _mm_srli_epi16(dst, 8);
420 48 dst = _mm_add_epi8(src, dst);
421
422 48 dst = _mm_packus_epi16(dst, zero);
423
424 48 _mm_storel_epi64(reinterpret_cast<__m128i*>(dstp + x * 4), dst);
425 }
426
427
1/4
void layer_rgb32_add_sse2<false>(unsigned char*, unsigned char const*, int, int, int, int, int):
✓ Branch 70 → 71 taken 11 times.
✗ Branch 70 → 73 not taken.
void layer_rgb32_add_sse2<true>(unsigned char*, unsigned char const*, int, int, int, int, int):
✗ Branch 63 → 64 not taken.
✗ Branch 63 → 66 not taken.
11 if (width != mod2_width) {
428 11 int x = mod2_width;
429 11 int alpha = (ovrp[x * 4 + 3] * level + 1) >> 8;
430
431 if (use_chroma) {
432 dstp[x * 4] = dstp[x * 4] + (((ovrp[x * 4] - dstp[x * 4]) * alpha + rounder) >> 8);
433 dstp[x * 4 + 1] = dstp[x * 4 + 1] + (((ovrp[x * 4 + 1] - dstp[x * 4 + 1]) * alpha + rounder) >> 8);
434 dstp[x * 4 + 2] = dstp[x * 4 + 2] + (((ovrp[x * 4 + 2] - dstp[x * 4 + 2]) * alpha + rounder) >> 8);
435 dstp[x * 4 + 3] = dstp[x * 4 + 3] + (((ovrp[x * 4 + 3] - dstp[x * 4 + 3]) * alpha + rounder) >> 8);
436 }
437 else {
438 11 int luma = (cyb * ovrp[x * 4] + cyg * ovrp[x * 4 + 1] + cyr * ovrp[x * 4 + 2]) >> 15;
439
440 11 dstp[x * 4] = dstp[x * 4] + (((luma - dstp[x * 4]) * alpha + rounder) >> 8);
441 11 dstp[x * 4 + 1] = dstp[x * 4 + 1] + (((luma - dstp[x * 4 + 1]) * alpha + rounder) >> 8);
442 11 dstp[x * 4 + 2] = dstp[x * 4 + 2] + (((luma - dstp[x * 4 + 2]) * alpha + rounder) >> 8);
443 11 dstp[x * 4 + 3] = dstp[x * 4 + 3] + (((luma - dstp[x * 4 + 3]) * alpha + rounder) >> 8);
444 }
445 }
446
447 11 dstp += dst_pitch;
448 11 ovrp += overlay_pitch;
449 }
450 3 }
451
452 // instantiate
453 template void layer_rgb32_add_sse2<false>(BYTE* dstp, const BYTE* ovrp, int dst_pitch, int overlay_pitch, int width, int height, int level);
454 template void layer_rgb32_add_sse2<true>(BYTE* dstp, const BYTE* ovrp, int dst_pitch, int overlay_pitch, int width, int height, int level);
455
456
457
458 template<bool use_chroma>
459 3 void layer_rgb32_subtract_sse2(BYTE* dstp, const BYTE* ovrp, int dst_pitch, int overlay_pitch, int width, int height, int level) {
460 3 int mod2_width = width / 2 * 2;
461
462 3 __m128i zero = _mm_setzero_si128();
463 3 __m128i level_vector = _mm_set1_epi32(level);
464 3 __m128i one = _mm_set1_epi32(1);
465 3 __m128i rgb_coeffs = _mm_set_epi16(0, cyr, cyg, cyb, 0, cyr, cyg, cyb);
466 3 __m128i ff = _mm_set1_epi16(0x00FF);
467
468 3 constexpr int rounder = 128;
469 3 const __m128i rounder_simd = _mm_set1_epi16(rounder);
470
471
2/4
void layer_rgb32_subtract_sse2<false>(unsigned char*, unsigned char const*, int, int, int, int, int):
✓ Branch 80 → 23 taken 11 times.
✓ Branch 80 → 81 taken 3 times.
void layer_rgb32_subtract_sse2<true>(unsigned char*, unsigned char const*, int, int, int, int, int):
✗ Branch 73 → 23 not taken.
✗ Branch 73 → 74 not taken.
14 for (int y = 0; y < height; ++y) {
472
2/4
void layer_rgb32_subtract_sse2<false>(unsigned char*, unsigned char const*, int, int, int, int, int):
✓ Branch 75 → 24 taken 48 times.
✓ Branch 75 → 76 taken 11 times.
void layer_rgb32_subtract_sse2<true>(unsigned char*, unsigned char const*, int, int, int, int, int):
✗ Branch 68 → 24 not taken.
✗ Branch 68 → 69 not taken.
59 for (int x = 0; x < mod2_width; x += 2) {
473 48 __m128i src = _mm_loadl_epi64(reinterpret_cast<const __m128i*>(dstp + x * 4));
474 96 __m128i ovr = _mm_loadl_epi64(reinterpret_cast<const __m128i*>(ovrp + x * 4));
475
476 48 __m128i alpha = calculate_monochrome_alpha_sse2(ovr, level_vector, one);
477
478 48 src = _mm_unpacklo_epi8(src, zero);
479 96 ovr = _mm_unpacklo_epi8(ovr, zero);
480
481 __m128i luma;
482 if (use_chroma) {
483 luma = _mm_subs_epi16(ff, ovr);
484 }
485 else {
486 144 luma = calculate_luma_sse2(_mm_andnot_si128(ovr, ff), rgb_coeffs, zero);
487 }
488
489 48 __m128i dst = _mm_subs_epi16(luma, src);
490 48 dst = _mm_mullo_epi16(dst, alpha);
491 48 dst = _mm_add_epi16(dst, rounder_simd);
492 48 dst = _mm_srli_epi16(dst, 8);
493 48 dst = _mm_add_epi8(src, dst);
494
495 48 dst = _mm_packus_epi16(dst, zero);
496
497 48 _mm_storel_epi64(reinterpret_cast<__m128i*>(dstp + x * 4), dst);
498 }
499
500
1/4
void layer_rgb32_subtract_sse2<false>(unsigned char*, unsigned char const*, int, int, int, int, int):
✓ Branch 76 → 77 taken 11 times.
✗ Branch 76 → 79 not taken.
void layer_rgb32_subtract_sse2<true>(unsigned char*, unsigned char const*, int, int, int, int, int):
✗ Branch 69 → 70 not taken.
✗ Branch 69 → 72 not taken.
11 if (width != mod2_width) {
501 11 int x = mod2_width;
502 11 int alpha = (ovrp[x * 4 + 3] * level + 1) >> 8;
503
504 if (use_chroma) {
505 dstp[x * 4] = dstp[x * 4] + (((255 - ovrp[x * 4] - dstp[x * 4]) * alpha + rounder) >> 8);
506 dstp[x * 4 + 1] = dstp[x * 4 + 1] + (((255 - ovrp[x * 4 + 1] - dstp[x * 4 + 1]) * alpha + rounder) >> 8);
507 dstp[x * 4 + 2] = dstp[x * 4 + 2] + (((255 - ovrp[x * 4 + 2] - dstp[x * 4 + 2]) * alpha + rounder) >> 8);
508 dstp[x * 4 + 3] = dstp[x * 4 + 3] + (((255 - ovrp[x * 4 + 3] - dstp[x * 4 + 3]) * alpha + rounder) >> 8);
509 }
510 else {
511 11 int luma = (cyb * (255 - ovrp[x * 4]) + cyg * (255 - ovrp[x * 4 + 1]) + cyr * (255 - ovrp[x * 4 + 2])) >> 15;
512
513 11 dstp[x * 4] = dstp[x * 4] + (((luma - dstp[x * 4]) * alpha + rounder) >> 8);
514 11 dstp[x * 4 + 1] = dstp[x * 4 + 1] + (((luma - dstp[x * 4 + 1]) * alpha + rounder) >> 8);
515 11 dstp[x * 4 + 2] = dstp[x * 4 + 2] + (((luma - dstp[x * 4 + 2]) * alpha + rounder) >> 8);
516 11 dstp[x * 4 + 3] = dstp[x * 4 + 3] + (((luma - dstp[x * 4 + 3]) * alpha + rounder) >> 8);
517 }
518 }
519
520 11 dstp += dst_pitch;
521 11 ovrp += overlay_pitch;
522 }
523 3 }
524
525 // instantiate
526 template void layer_rgb32_subtract_sse2<false>(BYTE* dstp, const BYTE* ovrp, int dst_pitch, int overlay_pitch, int width, int height, int level);
527 template void layer_rgb32_subtract_sse2<true>(BYTE* dstp, const BYTE* ovrp, int dst_pitch, int overlay_pitch, int width, int height, int level);
528
529
530 template<int mode>
531 6 void layer_rgb32_lighten_darken_sse2(BYTE* dstp, const BYTE* ovrp, int dst_pitch, int overlay_pitch, int width, int height, int level, int thresh) {
532 6 int mod2_width = width / 2 * 2;
533
534 6 __m128i zero = _mm_setzero_si128();
535 6 __m128i level_vector = _mm_set1_epi32(level);
536 6 __m128i one = _mm_set1_epi32(1);
537 6 __m128i rgb_coeffs = _mm_set_epi16(0, cyr, cyg, cyb, 0, cyr, cyg, cyb);
538 6 __m128i threshold = _mm_set1_epi16(thresh);
539
540 6 constexpr int rounder = 128;
541 6 const __m128i rounder_simd = _mm_set1_epi16(rounder);
542
543
4/4
void layer_rgb32_lighten_darken_sse2<0>(unsigned char*, unsigned char const*, int, int, int, int, int, int):
✓ Branch 93 → 23 taken 11 times.
✓ Branch 93 → 94 taken 3 times.
void layer_rgb32_lighten_darken_sse2<1>(unsigned char*, unsigned char const*, int, int, int, int, int, int):
✓ Branch 93 → 23 taken 11 times.
✓ Branch 93 → 94 taken 3 times.
28 for (int y = 0; y < height; ++y) {
544
4/4
void layer_rgb32_lighten_darken_sse2<0>(unsigned char*, unsigned char const*, int, int, int, int, int, int):
✓ Branch 86 → 24 taken 48 times.
✓ Branch 86 → 87 taken 11 times.
void layer_rgb32_lighten_darken_sse2<1>(unsigned char*, unsigned char const*, int, int, int, int, int, int):
✓ Branch 86 → 24 taken 48 times.
✓ Branch 86 → 87 taken 11 times.
118 for (int x = 0; x < mod2_width; x += 2) {
545 96 __m128i src = _mm_loadl_epi64(reinterpret_cast<const __m128i*>(dstp + x * 4));
546 192 __m128i ovr = _mm_loadl_epi64(reinterpret_cast<const __m128i*>(ovrp + x * 4));
547
548 96 __m128i alpha = calculate_monochrome_alpha_sse2(ovr, level_vector, one);
549
550 96 src = _mm_unpacklo_epi8(src, zero);
551 192 ovr = _mm_unpacklo_epi8(ovr, zero);
552
553 96 __m128i luma_ovr = calculate_luma_sse2(ovr, rgb_coeffs, zero);
554 96 __m128i luma_src = calculate_luma_sse2(src, rgb_coeffs, zero);
555
556 __m128i mask;
557 if constexpr (mode == LIGHTEN) {
558 48 __m128i tmp = _mm_add_epi16(luma_src, threshold);
559 48 mask = _mm_cmpgt_epi16(luma_ovr, tmp);
560 }
561 else {
562 48 __m128i tmp = _mm_sub_epi16(luma_src, threshold);
563 48 mask = _mm_cmpgt_epi16(tmp, luma_ovr);
564 }
565
566 96 alpha = _mm_and_si128(alpha, mask);
567
568 192 __m128i dst = _mm_subs_epi16(ovr, src);
569 96 dst = _mm_mullo_epi16(dst, alpha);
570 96 dst = _mm_add_epi16(dst, rounder_simd);
571 96 dst = _mm_srli_epi16(dst, 8);
572 96 dst = _mm_add_epi8(src, dst);
573
574 96 dst = _mm_packus_epi16(dst, zero);
575
576 96 _mm_storel_epi64(reinterpret_cast<__m128i*>(dstp + x * 4), dst);
577 }
578
579
2/4
void layer_rgb32_lighten_darken_sse2<0>(unsigned char*, unsigned char const*, int, int, int, int, int, int):
✓ Branch 87 → 88 taken 11 times.
✗ Branch 87 → 92 not taken.
void layer_rgb32_lighten_darken_sse2<1>(unsigned char*, unsigned char const*, int, int, int, int, int, int):
✓ Branch 87 → 88 taken 11 times.
✗ Branch 87 → 92 not taken.
22 if (width != mod2_width) {
580 22 int x = mod2_width;
581 22 int alpha = (ovrp[x * 4 + 3] * level + 1) >> 8;
582 22 int luma_ovr = (cyb * ovrp[x * 4] + cyg * ovrp[x * 4 + 1] + cyr * ovrp[x * 4 + 2]) >> 15;
583 22 int luma_src = (cyb * dstp[x * 4] + cyg * dstp[x * 4 + 1] + cyr * dstp[x * 4 + 2]) >> 15;
584
585 if constexpr (mode == LIGHTEN)
586
2/2
✓ Branch 88 → 89 taken 1 time.
✓ Branch 88 → 90 taken 10 times.
11 alpha = luma_ovr > luma_src + thresh ? alpha : 0;
587 else // DARKEN
588
2/2
✓ Branch 88 → 89 taken 5 times.
✓ Branch 88 → 90 taken 6 times.
11 alpha = luma_ovr < luma_src - thresh ? alpha : 0;
589
590 22 dstp[x * 4] = dstp[x * 4] + (((ovrp[x * 4] - dstp[x * 4]) * alpha + rounder) >> 8);
591 22 dstp[x * 4 + 1] = dstp[x * 4 + 1] + (((ovrp[x * 4 + 1] - dstp[x * 4 + 1]) * alpha + rounder) >> 8);
592 22 dstp[x * 4 + 2] = dstp[x * 4 + 2] + (((ovrp[x * 4 + 2] - dstp[x * 4 + 2]) * alpha + rounder) >> 8);
593 22 dstp[x * 4 + 3] = dstp[x * 4 + 3] + (((ovrp[x * 4 + 3] - dstp[x * 4 + 3]) * alpha + rounder) >> 8);
594 }
595
596 22 dstp += dst_pitch;
597 22 ovrp += overlay_pitch;
598 }
599 6 }
600
601 // instantiate
602 template void layer_rgb32_lighten_darken_sse2<LIGHTEN>(BYTE* dstp, const BYTE* ovrp, int dst_pitch, int overlay_pitch, int width, int height, int level, int thresh);
603 template void layer_rgb32_lighten_darken_sse2<DARKEN>(BYTE* dstp, const BYTE* ovrp, int dst_pitch, int overlay_pitch, int width, int height, int level, int thresh);
604
605