GCC Code Coverage Report


Directory: avs_core/
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 100.0% 90 / 0 / 90
Functions: 100.0% 3 / 0 / 3
Branches: 95.8% 23 / 0 / 24

filters/overlay/intel/444convert_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 // Overlay (c) 2003, 2004 by Klaus Post
36
37 #include "444convert_avx2.h"
38
39 #include <stdint.h>
40
41 #ifdef _MSC_VER
42 #include <intrin.h>
43 #else
44 #include <x86intrin.h>
45 #endif
46 #include <immintrin.h>
47
48 // YV24->YV12 uint8_t AVX2.
49 // permute4x64(0xD8) fixes packus_epi16 lane interleaving: [lo0,hi0,lo1,hi1] -> [lo0,lo1,hi0,hi1].
50 // Tail: XMM step (maddubs, SSSE3 implied by AVX2) then scalar.
51 10 void convert_yv24_chroma_to_yv12_u8_avx2(BYTE *dstp, const BYTE *srcp, int dst_pitch, int src_pitch, int dst_width, int dst_height)
52 {
53 10 const __m256i ones256 = _mm256_set1_epi8(1);
54 10 const __m256i two256 = _mm256_set1_epi16(2);
55 10 const __m128i ones128 = _mm_set1_epi8(1);
56 10 const __m128i two128 = _mm_set1_epi16(2);
57
58
2/2
✓ Branch 90 → 19 taken 24 times.
✓ Branch 90 → 91 taken 10 times.
34 for (int y = 0; y < dst_height; ++y) {
59 24 int x = 0;
60
61
2/2
✓ Branch 52 → 20 taken 5 times.
✓ Branch 52 → 53 taken 24 times.
29 for (; x + 32 <= dst_width; x += 32) {
62 5 __m256i r0lo = _mm256_loadu_si256(reinterpret_cast<const __m256i*>(srcp + x * 2));
63 5 __m256i r0hi = _mm256_loadu_si256(reinterpret_cast<const __m256i*>(srcp + x * 2 + 32));
64 5 __m256i r1lo = _mm256_loadu_si256(reinterpret_cast<const __m256i*>(srcp + x * 2 + src_pitch));
65 10 __m256i r1hi = _mm256_loadu_si256(reinterpret_cast<const __m256i*>(srcp + x * 2 + src_pitch + 32));
66
67 25 __m256i sum_lo = _mm256_srli_epi16(_mm256_add_epi16(_mm256_add_epi16(_mm256_maddubs_epi16(r0lo, ones256), _mm256_maddubs_epi16(r1lo, ones256)), two256), 2);
68 25 __m256i sum_hi = _mm256_srli_epi16(_mm256_add_epi16(_mm256_add_epi16(_mm256_maddubs_epi16(r0hi, ones256), _mm256_maddubs_epi16(r1hi, ones256)), two256), 2);
69
70 5 _mm256_storeu_si256(reinterpret_cast<__m256i*>(dstp + x),
71 _mm256_permute4x64_epi64(_mm256_packus_epi16(sum_lo, sum_hi), 0xD8));
72 }
73
74 // XMM tail: one 16-byte chunk if enough room
75
2/2
✓ Branch 53 → 54 taken 8 times.
✓ Branch 53 → 86 taken 16 times.
24 if (x + 16 <= dst_width) {
76 8 __m128i r0lo = _mm_loadu_si128(reinterpret_cast<const __m128i*>(srcp + x * 2));
77 8 __m128i r0hi = _mm_loadu_si128(reinterpret_cast<const __m128i*>(srcp + x * 2 + 16));
78 8 __m128i r1lo = _mm_loadu_si128(reinterpret_cast<const __m128i*>(srcp + x * 2 + src_pitch));
79 16 __m128i r1hi = _mm_loadu_si128(reinterpret_cast<const __m128i*>(srcp + x * 2 + src_pitch + 16));
80
81 40 __m128i sum_lo = _mm_srli_epi16(_mm_add_epi16(_mm_add_epi16(_mm_maddubs_epi16(r0lo, ones128), _mm_maddubs_epi16(r1lo, ones128)), two128), 2);
82 40 __m128i sum_hi = _mm_srli_epi16(_mm_add_epi16(_mm_add_epi16(_mm_maddubs_epi16(r0hi, ones128), _mm_maddubs_epi16(r1hi, ones128)), two128), 2);
83
84 8 _mm_storeu_si128(reinterpret_cast<__m128i*>(dstp + x), _mm_packus_epi16(sum_lo, sum_hi));
85 8 x += 16;
86 }
87
88 // scalar tail (0-15 remaining u8 pixels)
89
2/2
✓ Branch 88 → 87 taken 98 times.
✓ Branch 88 → 89 taken 24 times.
122 for (; x < dst_width; ++x)
90 98 dstp[x] = (srcp[x*2] + srcp[x*2+1] + srcp[x*2+src_pitch] + srcp[x*2+src_pitch+1] + 2) >> 2;
91
92 24 dstp += dst_pitch;
93 24 srcp += src_pitch * 2;
94 }
95 10 }
96
97 // YV24->YV12 uint16_t lessthan16bit AVX2.
98 // hadd_epi16 lane interleaving fixed by permute4x64(0xD8).
99 // Tail: XMM hadd step (SSSE3 implied by AVX2) then scalar.
100 1 void convert_yv24_chroma_to_yv12_u16_lessthan16bit_avx2(BYTE *dstp, const BYTE *srcp, int dst_pitch, int src_pitch, int dst_width, int dst_height)
101 {
102 1 const __m256i two256 = _mm256_set1_epi16(2);
103 1 const __m128i two128 = _mm_set1_epi16(2);
104
105
2/2
✓ Branch 58 → 11 taken 5 times.
✓ Branch 58 → 59 taken 1 time.
6 for (int y = 0; y < dst_height; ++y) {
106 5 int x = 0;
107
108
2/2
✓ Branch 32 → 12 taken 5 times.
✓ Branch 32 → 33 taken 5 times.
10 for (; x + 32 <= dst_width; x += 32) {
109 5 __m256i r0lo = _mm256_loadu_si256(reinterpret_cast<const __m256i*>(srcp + x * 2));
110 5 __m256i r0hi = _mm256_loadu_si256(reinterpret_cast<const __m256i*>(srcp + x * 2 + 32));
111 5 __m256i r1lo = _mm256_loadu_si256(reinterpret_cast<const __m256i*>(srcp + x * 2 + src_pitch));
112 10 __m256i r1hi = _mm256_loadu_si256(reinterpret_cast<const __m256i*>(srcp + x * 2 + src_pitch + 32));
113
114 25 __m256i pair_sums = _mm256_permute4x64_epi64(
115 _mm256_hadd_epi16(_mm256_add_epi16(r0lo, r1lo), _mm256_add_epi16(r0hi, r1hi)), 0xD8);
116
117 10 _mm256_storeu_si256(reinterpret_cast<__m256i*>(dstp + x),
118 _mm256_srli_epi16(_mm256_add_epi16(pair_sums, two256), 2));
119 }
120
121 // XMM tail: one 16-byte chunk (8 u16 pixels) if enough room
122
1/2
✓ Branch 33 → 34 taken 5 times.
✗ Branch 33 → 54 not taken.
5 if (x + 16 <= dst_width) {
123 5 __m128i r0lo = _mm_loadu_si128(reinterpret_cast<const __m128i*>(srcp + x * 2));
124 5 __m128i r0hi = _mm_loadu_si128(reinterpret_cast<const __m128i*>(srcp + x * 2 + 16));
125 5 __m128i r1lo = _mm_loadu_si128(reinterpret_cast<const __m128i*>(srcp + x * 2 + src_pitch));
126 10 __m128i r1hi = _mm_loadu_si128(reinterpret_cast<const __m128i*>(srcp + x * 2 + src_pitch + 16));
127
128 25 _mm_storeu_si128(reinterpret_cast<__m128i*>(dstp + x),
129 _mm_srli_epi16(_mm_add_epi16(_mm_hadd_epi16(_mm_add_epi16(r0lo, r1lo), _mm_add_epi16(r0hi, r1hi)), two128), 2));
130 5 x += 16;
131 }
132
133 // scalar tail (0-7 remaining u16 pixels)
134 5 const uint16_t *s0 = reinterpret_cast<const uint16_t*>(srcp);
135 5 const uint16_t *s1 = reinterpret_cast<const uint16_t*>(srcp + src_pitch);
136 5 uint16_t *d = reinterpret_cast<uint16_t*>(dstp);
137
2/2
✓ Branch 56 → 55 taken 15 times.
✓ Branch 56 → 57 taken 5 times.
20 for (int px = x / 2; px < dst_width / 2; ++px)
138 15 d[px] = (uint16_t)((s0[px*2] + s0[px*2+1] + s1[px*2] + s1[px*2+1] + 2) >> 2);
139
140 5 dstp += dst_pitch;
141 5 srcp += src_pitch * 2;
142 }
143 1 }
144
145 // YV24->YV12 uint16_t true 16-bit AVX2.
146 // XOR 0x8000 pivot before madd_epi16 maps u16→i16 [-32768,32767]; srai+packs+XOR restores u16.
147 // packs_epi32 lane interleaving fixed by permute4x64(0xD8).
148 // Tail: XMM step (SSE2; SSE4.1 implied by AVX2) then scalar.
149 2 void convert_yv24_chroma_to_yv12_u16_avx2(BYTE *dstp, const BYTE *srcp, int dst_pitch, int src_pitch, int dst_width, int dst_height)
150 {
151 2 const __m256i xor256 = _mm256_set1_epi16((short)0x8000);
152 2 const __m256i ones256 = _mm256_set1_epi16(1);
153 2 const __m256i two256 = _mm256_set1_epi32(2);
154 2 const __m128i xor128 = _mm_set1_epi16((short)0x8000);
155 2 const __m128i ones128 = _mm_set1_epi16(1);
156 2 const __m128i two128 = _mm_set1_epi32(2);
157
158
2/2
✓ Branch 116 → 25 taken 8 times.
✓ Branch 116 → 117 taken 2 times.
10 for (int y = 0; y < dst_height; ++y) {
159 8 int x = 0;
160
161
2/2
✓ Branch 68 → 26 taken 8 times.
✓ Branch 68 → 69 taken 8 times.
16 for (; x + 32 <= dst_width; x += 32) {
162 16 __m256i r0lo = _mm256_xor_si256(_mm256_loadu_si256(reinterpret_cast<const __m256i*>(srcp + x * 2)), xor256);
163 16 __m256i r0hi = _mm256_xor_si256(_mm256_loadu_si256(reinterpret_cast<const __m256i*>(srcp + x * 2 + 32)), xor256);
164 16 __m256i r1lo = _mm256_xor_si256(_mm256_loadu_si256(reinterpret_cast<const __m256i*>(srcp + x * 2 + src_pitch)), xor256);
165 24 __m256i r1hi = _mm256_xor_si256(_mm256_loadu_si256(reinterpret_cast<const __m256i*>(srcp + x * 2 + src_pitch + 32)), xor256);
166
167 40 __m256i sum_lo = _mm256_srai_epi32(_mm256_add_epi32(_mm256_add_epi32(_mm256_madd_epi16(r0lo, ones256), _mm256_madd_epi16(r1lo, ones256)), two256), 2);
168 40 __m256i sum_hi = _mm256_srai_epi32(_mm256_add_epi32(_mm256_add_epi32(_mm256_madd_epi16(r0hi, ones256), _mm256_madd_epi16(r1hi, ones256)), two256), 2);
169
170 16 _mm256_storeu_si256(reinterpret_cast<__m256i*>(dstp + x),
171 _mm256_xor_si256(_mm256_permute4x64_epi64(_mm256_packs_epi32(sum_lo, sum_hi), 0xD8), xor256));
172 }
173
174 // XMM tail: one 16-byte chunk (8 u16 pixels) if enough room
175
2/2
✓ Branch 69 → 70 taken 5 times.
✓ Branch 69 → 112 taken 3 times.
8 if (x + 16 <= dst_width) {
176 10 __m128i r0lo = _mm_xor_si128(_mm_loadu_si128(reinterpret_cast<const __m128i*>(srcp + x * 2)), xor128);
177 10 __m128i r0hi = _mm_xor_si128(_mm_loadu_si128(reinterpret_cast<const __m128i*>(srcp + x * 2 + 16)), xor128);
178 10 __m128i r1lo = _mm_xor_si128(_mm_loadu_si128(reinterpret_cast<const __m128i*>(srcp + x * 2 + src_pitch)), xor128);
179 15 __m128i r1hi = _mm_xor_si128(_mm_loadu_si128(reinterpret_cast<const __m128i*>(srcp + x * 2 + src_pitch + 16)), xor128);
180
181 25 __m128i sum_lo = _mm_srai_epi32(_mm_add_epi32(_mm_add_epi32(_mm_madd_epi16(r0lo, ones128), _mm_madd_epi16(r1lo, ones128)), two128), 2);
182 25 __m128i sum_hi = _mm_srai_epi32(_mm_add_epi32(_mm_add_epi32(_mm_madd_epi16(r0hi, ones128), _mm_madd_epi16(r1hi, ones128)), two128), 2);
183
184 10 _mm_storeu_si128(reinterpret_cast<__m128i*>(dstp + x),
185 _mm_xor_si128(_mm_packs_epi32(sum_lo, sum_hi), xor128));
186 5 x += 16;
187 }
188
189 // scalar tail (0-7 remaining u16 pixels)
190 8 const uint16_t *s0 = reinterpret_cast<const uint16_t*>(srcp);
191 8 const uint16_t *s1 = reinterpret_cast<const uint16_t*>(srcp + src_pitch);
192 8 uint16_t *d = reinterpret_cast<uint16_t*>(dstp);
193
2/2
✓ Branch 114 → 113 taken 24 times.
✓ Branch 114 → 115 taken 8 times.
32 for (int px = x / 2; px < dst_width / 2; ++px)
194 24 d[px] = (uint16_t)((s0[px*2] + s0[px*2+1] + s1[px*2] + s1[px*2+1] + 2) >> 2);
195
196 8 dstp += dst_pitch;
197 8 srcp += src_pitch * 2;
198 }
199 2 }
200