convert/intel/convert_rgb_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 | #include "../convert_rgb.h" | ||
| 37 | |||
| 38 | // Intrinsics base header + really required extension headers | ||
| 39 | #if defined(_MSC_VER) | ||
| 40 | #include <intrin.h> // MSVC | ||
| 41 | #else | ||
| 42 | #include <x86intrin.h> // GCC/MinGW/Clang/LLVM | ||
| 43 | #endif | ||
| 44 | #include <tmmintrin.h> // SSSE3 | ||
| 45 | |||
| 46 | #include <avs/alignment.h> | ||
| 47 | |||
| 48 | |||
| 49 | |||
| 50 | |||
| 51 | #if defined(GCC) || defined(CLANG) | ||
| 52 | __attribute__((__target__("ssse3"))) | ||
| 53 | #endif | ||
| 54 | 2 | void convert_rgb48_to_rgb64_ssse3(const BYTE *srcp, BYTE *dstp, size_t src_pitch, size_t dst_pitch, size_t width, size_t height) | |
| 55 | { | ||
| 56 | 2 | size_t mod16_width = sizeof(uint16_t)*(width & (~size_t(7))); | |
| 57 | 2 | __m128i mask0 = _mm_set_epi8((char)0x80, (char)0x80, 11, 10, 9, 8, 7, 6, (char)0x80, (char)0x80, 5, 4, 3, 2, 1, 0); | |
| 58 | 2 | __m128i mask1 = _mm_set_epi8((char)0x80, (char)0x80, 15, 14, 13, 12, 11, 10, (char)0x80, (char)0x80, 9, 8, 7, 6, 5, 4); | |
| 59 | 2 | __m128i alpha = _mm_set_epi32(0xFFFF0000,0x00000000,0xFFFF0000,0x00000000); | |
| 60 | |||
| 61 |
2/2✓ Branch 42 → 9 taken 8 times.
✓ Branch 42 → 43 taken 2 times.
|
10 | for (size_t y = 0; y < height; ++y) { |
| 62 |
2/2✓ Branch 37 → 10 taken 5 times.
✓ Branch 37 → 38 taken 8 times.
|
13 | for (size_t x = 0; x < mod16_width; x+= 16) { |
| 63 | 10 | __m128i src0 = _mm_load_si128(reinterpret_cast<const __m128i*>(srcp+x*3)); | |
| 64 | // 7... ...0 | ||
| 65 | // B G|R B G R B G #0 #1 (#2) x*3+0 | ||
| 66 | // G R B G|R B G R (#2) #3 #4 (#5) x*3+16 | ||
| 67 | // R B G R B G|R B (#5) #6 #7 x*3+32 | ||
| 68 | 5 | __m128i dst = _mm_or_si128(alpha, _mm_shuffle_epi8(src0, mask0)); | |
| 69 | 5 | _mm_stream_si128(reinterpret_cast<__m128i*>(dstp+4*x), dst); | |
| 70 | |||
| 71 | 5 | __m128i src1 = _mm_load_si128(reinterpret_cast<const __m128i*>(srcp+x*3+16)); | |
| 72 | 5 | __m128i tmp = _mm_alignr_epi8(src1, src0, 12); | |
| 73 | 5 | dst = _mm_or_si128(alpha, _mm_shuffle_epi8(tmp, mask0)); | |
| 74 | 5 | _mm_stream_si128(reinterpret_cast<__m128i*>(dstp+x*4+16), dst); | |
| 75 | |||
| 76 | 5 | __m128i src2 = _mm_load_si128(reinterpret_cast<const __m128i*>(srcp+x*3+32)); | |
| 77 | 5 | tmp = _mm_alignr_epi8(src2, src1, 8); | |
| 78 | 5 | dst = _mm_or_si128(alpha, _mm_shuffle_epi8(tmp, mask0)); | |
| 79 | 5 | _mm_stream_si128(reinterpret_cast<__m128i*>(dstp+x*4+32), dst); | |
| 80 | |||
| 81 | 5 | dst = _mm_or_si128(alpha, _mm_shuffle_epi8(src2, mask1)); | |
| 82 | 5 | _mm_stream_si128(reinterpret_cast<__m128i*>(dstp+x*4+48), dst); | |
| 83 | } | ||
| 84 | |||
| 85 |
2/2✓ Branch 40 → 39 taken 30 times.
✓ Branch 40 → 41 taken 8 times.
|
38 | for (size_t x = mod16_width/sizeof(uint16_t); x < width; ++x) { |
| 86 | 30 | reinterpret_cast<uint16_t *>(dstp)[x*4+0] = reinterpret_cast<const uint16_t *>(srcp)[x*3+0]; | |
| 87 | 30 | reinterpret_cast<uint16_t *>(dstp)[x*4+1] = reinterpret_cast<const uint16_t *>(srcp)[x*3+1]; | |
| 88 | 30 | reinterpret_cast<uint16_t *>(dstp)[x*4+2] = reinterpret_cast<const uint16_t *>(srcp)[x*3+2]; | |
| 89 | 30 | reinterpret_cast<uint16_t *>(dstp)[x*4+3] = 65535; | |
| 90 | } | ||
| 91 | |||
| 92 | 8 | srcp += src_pitch; | |
| 93 | 8 | dstp += dst_pitch; | |
| 94 | } | ||
| 95 | 2 | } | |
| 96 | |||
| 97 | #if defined(GCC) || defined(CLANG) | ||
| 98 | __attribute__((__target__("ssse3"))) | ||
| 99 | #endif | ||
| 100 | 2 | void convert_rgb24_to_rgb32_ssse3(const BYTE *srcp, BYTE *dstp, size_t src_pitch, size_t dst_pitch, size_t width, size_t height) | |
| 101 | { | ||
| 102 | 2 | size_t mod16_width = (width + 3) & (~size_t(15)); //when the modulo is more than 13, a problem does not happen | |
| 103 | 2 | __m128i mask0 = _mm_set_epi8((char)0x80, 11, 10, 9, (char)0x80, 8, 7, 6, (char)0x80, 5, 4, 3, (char)0x80, 2, 1, 0); | |
| 104 | 2 | __m128i mask1 = _mm_set_epi8((char)0x80, 15, 14, 13, (char)0x80, 12, 11, 10, (char)0x80, 9, 8, 7, (char)0x80, 6, 5, 4); | |
| 105 | 2 | __m128i alpha = _mm_set1_epi32(0xFF000000); | |
| 106 | |||
| 107 |
2/2✓ Branch 44 → 11 taken 8 times.
✓ Branch 44 → 45 taken 2 times.
|
10 | for (size_t y = 0; y < height; ++y) { |
| 108 |
2/2✓ Branch 39 → 12 taken 10 times.
✓ Branch 39 → 40 taken 8 times.
|
18 | for (size_t x = 0; x < mod16_width; x+= 16) { |
| 109 | 20 | __m128i src0 = _mm_load_si128(reinterpret_cast<const __m128i*>(srcp+x*3)); | |
| 110 | 10 | __m128i dst = _mm_or_si128(alpha, _mm_shuffle_epi8(src0, mask0)); | |
| 111 | 10 | _mm_stream_si128(reinterpret_cast<__m128i*>(dstp+4*x), dst); | |
| 112 | |||
| 113 | 10 | __m128i src1 = _mm_load_si128(reinterpret_cast<const __m128i*>(srcp+x*3+16)); | |
| 114 | 10 | __m128i tmp = _mm_alignr_epi8(src1, src0, 12); | |
| 115 | 10 | dst = _mm_or_si128(alpha, _mm_shuffle_epi8(tmp, mask0)); | |
| 116 | 10 | _mm_stream_si128(reinterpret_cast<__m128i*>(dstp+x*4+16), dst); | |
| 117 | |||
| 118 | 10 | __m128i src2 = _mm_load_si128(reinterpret_cast<const __m128i*>(srcp+x*3+32)); | |
| 119 | 10 | tmp = _mm_alignr_epi8(src2, src1, 8); | |
| 120 | 10 | dst = _mm_or_si128(alpha, _mm_shuffle_epi8(tmp, mask0)); | |
| 121 | 10 | _mm_stream_si128(reinterpret_cast<__m128i*>(dstp+x*4+32), dst); | |
| 122 | |||
| 123 | 10 | dst = _mm_or_si128(alpha, _mm_shuffle_epi8(src2, mask1)); | |
| 124 | 10 | _mm_stream_si128(reinterpret_cast<__m128i*>(dstp+x*4+48), dst); | |
| 125 | } | ||
| 126 | |||
| 127 |
2/2✓ Branch 42 → 41 taken 15 times.
✓ Branch 42 → 43 taken 8 times.
|
23 | for (size_t x = mod16_width; x < width; ++x) { |
| 128 | 15 | dstp[x*4+0] = srcp[x*3+0]; | |
| 129 | 15 | dstp[x*4+1] = srcp[x*3+1]; | |
| 130 | 15 | dstp[x*4+2] = srcp[x*3+2]; | |
| 131 | 15 | dstp[x*4+3] = 255; | |
| 132 | } | ||
| 133 | |||
| 134 | 8 | srcp += src_pitch; | |
| 135 | 8 | dstp += dst_pitch; | |
| 136 | } | ||
| 137 | 2 | } | |
| 138 | |||
| 139 | |||
| 140 | #if defined(GCC) || defined(CLANG) | ||
| 141 | __attribute__((__target__("ssse3"))) | ||
| 142 | #endif | ||
| 143 | 2 | void convert_rgb64_to_rgb48_ssse3(const BYTE *srcp, BYTE *dstp, size_t src_pitch, size_t dst_pitch, size_t width, size_t height) | |
| 144 | { | ||
| 145 | 2 | size_t mod16_width = sizeof(uint16_t) * ((width) & (~size_t(7))); // perhaps width+2 is still o.k | |
| 146 | 2 | __m128i mask0 = _mm_set_epi8(13, 12, 11, 10, 9, 8, 5, 4, 3, 2, 1, 0, 15, 14, 7, 6); // BBGGRRBBGGRRAAAA | |
| 147 | 2 | __m128i mask1 = _mm_set_epi8(15, 14, 7, 6, 13, 12, 11, 10, 9, 8, 5, 4, 3, 2, 1, 0); // AAAABBGGRRBBGGRR | |
| 148 | |||
| 149 |
2/2✓ Branch 33 → 7 taken 8 times.
✓ Branch 33 → 34 taken 2 times.
|
10 | for (size_t y = 0; y < height; ++y) { |
| 150 |
2/2✓ Branch 28 → 8 taken 5 times.
✓ Branch 28 → 29 taken 8 times.
|
13 | for (size_t x = 0; x < mod16_width; x+= 16) { |
| 151 | 5 | __m128i src0 = _mm_load_si128(reinterpret_cast<const __m128i*>(srcp+x*4)); //a1b1 g1r1 a0b0 g0r0 | |
| 152 | 10 | __m128i src1 = _mm_load_si128(reinterpret_cast<const __m128i*>(srcp+x*4+16)); //a3b3 g3r3 a2b2 g2r2 | |
| 153 | 5 | src0 = _mm_shuffle_epi8(src0, mask0); //b1g1 r1b0 g0r0 a1a0 | |
| 154 | 5 | src1 = _mm_shuffle_epi8(src1, mask1); //a3a2 b3g3 r3b2 g2r2 | |
| 155 | 5 | __m128i dst = _mm_alignr_epi8(src1, src0, 4); //g2r2 b1g1 r1b0 g0r0 | |
| 156 | 5 | _mm_stream_si128(reinterpret_cast<__m128i*>(dstp+x*3), dst); | |
| 157 | |||
| 158 | 5 | src0 = _mm_slli_si128(src1, 4); // b3g3 r3b2 g2r2 XXXX | |
| 159 | 10 | src1 = _mm_load_si128(reinterpret_cast<const __m128i*>(srcp + x * 4 + 32)); // a5b5 g5r5 a4b4 g4r4 | |
| 160 | 5 | src1 = _mm_shuffle_epi8(src1, mask1); // a5a4 b5g5 r5b4 g4r4 | |
| 161 | 5 | dst = _mm_alignr_epi8(src1, src0, 8); // r5b4 g4r4 b3g3 r3b2 | |
| 162 | 5 | _mm_stream_si128(reinterpret_cast<__m128i*>(dstp+x*3+16), dst); | |
| 163 | |||
| 164 | 5 | src0 = _mm_slli_si128(src1, 4); // b5g5 r5b4 g4r4 XXXX | |
| 165 | 10 | src1 = _mm_load_si128(reinterpret_cast<const __m128i*>(srcp+x*4+48)); // a7b7 g7r7 a6b6 g6r6 | |
| 166 | 5 | src1 = _mm_shuffle_epi8(src1, mask1); // a7a6 b7g7 r7b6 g6r6 | |
| 167 | 5 | dst = _mm_alignr_epi8(src1, src0, 12); // b7g7 r7b6 g6r6 b5g5 | |
| 168 | 5 | _mm_stream_si128(reinterpret_cast<__m128i*>(dstp+x*3+32), dst); | |
| 169 | } | ||
| 170 | |||
| 171 |
2/2✓ Branch 31 → 30 taken 30 times.
✓ Branch 31 → 32 taken 8 times.
|
38 | for (size_t x = mod16_width/sizeof(uint16_t); x < width; ++x) { |
| 172 | 30 | reinterpret_cast<uint16_t *>(dstp)[x*3+0] = reinterpret_cast<const uint16_t *>(srcp)[x*4+0]; | |
| 173 | 30 | reinterpret_cast<uint16_t *>(dstp)[x*3+1] = reinterpret_cast<const uint16_t *>(srcp)[x*4+1]; | |
| 174 | 30 | reinterpret_cast<uint16_t *>(dstp)[x*3+2] = reinterpret_cast<const uint16_t *>(srcp)[x*4+2]; | |
| 175 | } | ||
| 176 | |||
| 177 | 8 | srcp += src_pitch; | |
| 178 | 8 | dstp += dst_pitch; | |
| 179 | } | ||
| 180 | 2 | } | |
| 181 | |||
| 182 | //todo: think how to port to sse2 without tons of shuffles or (un)packs | ||
| 183 | #if defined(GCC) || defined(CLANG) | ||
| 184 | __attribute__((__target__("ssse3"))) | ||
| 185 | #endif | ||
| 186 | 2 | void convert_rgb32_to_rgb24_ssse3(const BYTE *srcp, BYTE *dstp, size_t src_pitch, size_t dst_pitch, size_t width, size_t height) | |
| 187 | { | ||
| 188 | 2 | size_t mod16_width = (width + 3) & (~size_t(15)); //when the modulo is more than 13, a problem does not happen | |
| 189 | 2 | __m128i mask0 = _mm_set_epi8(14, 13, 12, 10, 9, 8, 6, 5, 4, 2, 1, 0, 15, 11, 7, 3); | |
| 190 | 2 | __m128i mask1 = _mm_set_epi8(15, 11, 7, 3, 14, 13, 12, 10, 9, 8, 6, 5, 4, 2, 1, 0); | |
| 191 | |||
| 192 |
2/2✓ Branch 33 → 7 taken 8 times.
✓ Branch 33 → 34 taken 2 times.
|
10 | for (size_t y = 0; y < height; ++y) { |
| 193 |
2/2✓ Branch 28 → 8 taken 10 times.
✓ Branch 28 → 29 taken 8 times.
|
18 | for (size_t x = 0; x < mod16_width; x+= 16) { |
| 194 | 10 | __m128i src0 = _mm_load_si128(reinterpret_cast<const __m128i*>(srcp+x*4)); //a3b3 g3r3 a2b2 g2r2 a1b1 g1r1 a0b0 g0r0 | |
| 195 | 20 | __m128i src1 = _mm_load_si128(reinterpret_cast<const __m128i*>(srcp+x*4+16)); //a7b7 g7r7 a6b6 g6r6 a5b5 g5r5 a4b4 g4r4 | |
| 196 | 10 | src0 = _mm_shuffle_epi8(src0, mask0); //b3g3 r3b2 g2r2 b1g1 r1b0 g0r0 a3a2 a1a0 | |
| 197 | 10 | src1 = _mm_shuffle_epi8(src1, mask1); //a7a6 a5a4 b7g7 r7b6 g6r6 b5g5 r5b4 g4r4 | |
| 198 | 10 | __m128i dst = _mm_alignr_epi8(src1, src0, 4); //r5b4 g4r4 b3g3 r3b2 g2r2 b1g1 r1b0 g0r0 | |
| 199 | 10 | _mm_stream_si128(reinterpret_cast<__m128i*>(dstp+x*3), dst); | |
| 200 | |||
| 201 | 10 | src0 = _mm_slli_si128(src1, 4); //b7g7 r7b6 g6r6 b5g5 r5b4 g4r4 XXXX XXXX | |
| 202 | 20 | src1 = _mm_load_si128(reinterpret_cast<const __m128i*>(srcp + x * 4 + 32)); //aBbB gBrB aAbA gArA a9b9 g9r9 a8b8 g8r8 | |
| 203 | 10 | src1 = _mm_shuffle_epi8(src1, mask1); //aBaA a9a8 bBgB rBbA gArA b9g9 r9b8 g8r8 | |
| 204 | 10 | dst = _mm_alignr_epi8(src1, src0, 8); //gArA b9g9 r9b8 g8r8 b7g7 r7b6 g6r6 b5g5 | |
| 205 | 10 | _mm_stream_si128(reinterpret_cast<__m128i*>(dstp+x*3+16), dst); | |
| 206 | |||
| 207 | 10 | src0 = _mm_slli_si128(src1, 4); //bBgB rBbA gArA b9g9 r9b8 g8r8 XXXX XXXX | |
| 208 | 20 | src1 = _mm_load_si128(reinterpret_cast<const __m128i*>(srcp+x*4+48)); //aFbF gFrF aEbE gErE aDbD gDrD aCbC gCrC | |
| 209 | 10 | src1 = _mm_shuffle_epi8(src1, mask1); //aFaE aDaC bFgF rFbE gErE bDgD rDbC gCrC | |
| 210 | 10 | dst = _mm_alignr_epi8(src1, src0, 12); //bFgF rFbE gErE bDgD rDbC gCrC bBgB rBbA | |
| 211 | 10 | _mm_stream_si128(reinterpret_cast<__m128i*>(dstp+x*3+32), dst); | |
| 212 | } | ||
| 213 | |||
| 214 |
2/2✓ Branch 31 → 30 taken 15 times.
✓ Branch 31 → 32 taken 8 times.
|
23 | for (size_t x = mod16_width; x < width; ++x) { |
| 215 | 15 | dstp[x*3+0] = srcp[x*4+0]; | |
| 216 | 15 | dstp[x*3+1] = srcp[x*4+1]; | |
| 217 | 15 | dstp[x*3+2] = srcp[x*4+2]; | |
| 218 | } | ||
| 219 | |||
| 220 | 8 | srcp += src_pitch; | |
| 221 | 8 | dstp += dst_pitch; | |
| 222 | } | ||
| 223 | 2 | } | |
| 224 | |||
| 225 | 1 | void convert_rgb32_to_rgb24_sse2(const BYTE* srcp, BYTE* dstp, size_t src_pitch, size_t dst_pitch, size_t width, size_t height) { | |
| 226 | 1 | size_t mod4_width = width & (~size_t(3)); | |
| 227 | |||
| 228 |
2/2✓ Branch 37 → 3 taken 5 times.
✓ Branch 37 → 38 taken 1 time.
|
6 | for (size_t y = 0; y < height; ++y) { |
| 229 |
2/2✓ Branch 32 → 4 taken 35 times.
✓ Branch 32 → 33 taken 5 times.
|
40 | for (size_t x = 0; x < mod4_width; x += 4) { |
| 230 | // Load 4 pixels (16 bytes) | ||
| 231 | 70 | __m128i src = _mm_loadu_si128(reinterpret_cast<const __m128i*>(srcp + x * 4)); | |
| 232 | |||
| 233 | // Pixel 0 (bytes 0,1,2) and Pixel 1 (bytes 4,5,6) | ||
| 234 | // Goal: [ 00 00 r1 g1 b1 r0 g0 b0 ] in the low 64 bits | ||
| 235 | 70 | __m128i p0 = _mm_and_si128(src, _mm_set_epi32(0, 0, 0, 0x00FFFFFF)); | |
| 236 | 35 | __m128i p1 = _mm_and_si128(src, _mm_set_epi32(0, 0, 0x00FFFFFF, 0)); | |
| 237 | 70 | __m128i dst01 = _mm_or_si128(p0, _mm_srli_si128(p1, 1)); | |
| 238 | |||
| 239 | // Pixel 2 (bytes 8,9,10) and Pixel 3 (bytes 12,13,14) | ||
| 240 | 70 | __m128i p2 = _mm_and_si128(src, _mm_set_epi32(0, 0x00FFFFFF, 0, 0)); | |
| 241 | 35 | __m128i p3 = _mm_and_si128(src, _mm_set_epi32(0x00FFFFFF, 0, 0, 0)); | |
| 242 | |||
| 243 | // Shift p2 down to byte 6 and p3 down to byte 9 | ||
| 244 | 70 | __m128i dst23 = _mm_or_si128(_mm_srli_si128(p2, 2), _mm_srli_si128(p3, 3)); | |
| 245 | |||
| 246 | // Combine them | ||
| 247 | 35 | __m128i final = _mm_or_si128(dst01, dst23); | |
| 248 | |||
| 249 | // final now contains: [ B3 G3 R3 | B2 G2 R2 | B1 G1 R1 | B0 G0 R0 ] | ||
| 250 | // In the first 12 bytes. | ||
| 251 | // We store 8 bytes (64-bit) then 4 bytes (32-bit) | ||
| 252 | 35 | _mm_storel_epi64(reinterpret_cast<__m128i*>(dstp + x * 3), final); | |
| 253 | 70 | *reinterpret_cast<int*>(dstp + x * 3 + 8) = _mm_cvtsi128_si32(_mm_srli_si128(final, 8)); | |
| 254 | } | ||
| 255 | |||
| 256 | // Standard remainder loop | ||
| 257 |
2/2✓ Branch 35 → 34 taken 5 times.
✓ Branch 35 → 36 taken 5 times.
|
10 | for (size_t x = mod4_width; x < width; ++x) { |
| 258 | 5 | dstp[x * 3 + 0] = srcp[x * 4 + 0]; | |
| 259 | 5 | dstp[x * 3 + 1] = srcp[x * 4 + 1]; | |
| 260 | 5 | dstp[x * 3 + 2] = srcp[x * 4 + 2]; | |
| 261 | } | ||
| 262 | |||
| 263 | 5 | srcp += src_pitch; | |
| 264 | 5 | dstp += dst_pitch; | |
| 265 | } | ||
| 266 | 1 | } | |
| 267 | |||
| 268 | |||
| 269 | // ============================================================ | ||
| 270 | // SSE2 emulation of _mm_alignr_epi8(hi, lo, N) | ||
| 271 | // Concatenates [hi:lo] as 32 bytes, returns bytes [N..N+15] | ||
| 272 | // ============================================================ | ||
| 273 | template<int N> | ||
| 274 | static AVS_FORCEINLINE __m128i sse2_alignr(__m128i hi, __m128i lo) { | ||
| 275 | 120 | return _mm_or_si128(_mm_srli_si128(lo, N), _mm_slli_si128(hi, 16 - N)); | |
| 276 | } | ||
| 277 | |||
| 278 | // ============================================================ | ||
| 279 | // 8-bit helper: gather B, G, R from 4 BGR8 pixels | ||
| 280 | // | ||
| 281 | // Input 'grp': low 12 bytes hold 4 BGR8 pixels | ||
| 282 | // byte: 0 1 2 3 4 5 6 7 8 9 10 11 | ||
| 283 | // data: B0 G0 R0 B1 G1 R1 B2 G2 R2 B3 G3 R3 | ||
| 284 | // | ||
| 285 | // Output bOut, gOut, rOut: valid bytes in positions 0..3 only | ||
| 286 | // bOut[0..3] = B0 B1 B2 B3 | ||
| 287 | // gOut[0..3] = G0 G1 G2 G3 | ||
| 288 | // rOut[0..3] = R0 R1 R2 R3 | ||
| 289 | // ============================================================ | ||
| 290 | static AVS_FORCEINLINE void gather_bgr8_4px(__m128i grp, | ||
| 291 | __m128i& bOut, __m128i& gOut, __m128i& rOut) | ||
| 292 | { | ||
| 293 | // B is at bytes 0, 3, 6, 9. We shift them to 0, 1, 2, 3. | ||
| 294 | 240 | __m128i b = _mm_and_si128(grp, _mm_set_epi32(0, 0, 0, 0x000000FF)); // B0 | |
| 295 | 360 | b = _mm_or_si128(b, _mm_and_si128(_mm_srli_si128(grp, 2), _mm_set_epi32(0, 0, 0, 0x0000FF00))); // B1 | |
| 296 | 360 | b = _mm_or_si128(b, _mm_and_si128(_mm_srli_si128(grp, 4), _mm_set_epi32(0, 0, 0, 0x00FF0000))); // B2 | |
| 297 | 240 | b = _mm_or_si128(b, _mm_and_si128(_mm_srli_si128(grp, 6), _mm_set_epi32(0, 0, 0, 0xFF000000))); // B3 | |
| 298 | 120 | bOut = b; | |
| 299 | |||
| 300 | // G is at bytes 1, 4, 7, 10. | ||
| 301 | 240 | __m128i g = _mm_and_si128(_mm_srli_si128(grp, 1), _mm_set_epi32(0, 0, 0, 0x000000FF)); // G0 | |
| 302 | 360 | g = _mm_or_si128(g, _mm_and_si128(_mm_srli_si128(grp, 3), _mm_set_epi32(0, 0, 0, 0x0000FF00))); // G1 | |
| 303 | 360 | g = _mm_or_si128(g, _mm_and_si128(_mm_srli_si128(grp, 5), _mm_set_epi32(0, 0, 0, 0x00FF0000))); // G2 | |
| 304 | 240 | g = _mm_or_si128(g, _mm_and_si128(_mm_srli_si128(grp, 7), _mm_set_epi32(0, 0, 0, 0xFF000000))); // G3 | |
| 305 | 120 | gOut = g; | |
| 306 | |||
| 307 | // R is at bytes 2, 5, 8, 11. | ||
| 308 | 240 | __m128i r = _mm_and_si128(_mm_srli_si128(grp, 2), _mm_set_epi32(0, 0, 0, 0x000000FF)); // R0 | |
| 309 | 360 | r = _mm_or_si128(r, _mm_and_si128(_mm_srli_si128(grp, 4), _mm_set_epi32(0, 0, 0, 0x0000FF00))); // R1 | |
| 310 | 360 | r = _mm_or_si128(r, _mm_and_si128(_mm_srli_si128(grp, 6), _mm_set_epi32(0, 0, 0, 0x00FF0000))); // R2 | |
| 311 | 240 | r = _mm_or_si128(r, _mm_and_si128(_mm_srli_si128(grp, 8), _mm_set_epi32(0, 0, 0, 0xFF000000))); // R3 | |
| 312 | 120 | rOut = r; | |
| 313 | 120 | } | |
| 314 | |||
| 315 | // ============================================================ | ||
| 316 | // 8-bit: deinterleave 16 BGR8 pixels from 3 × 16-byte registers | ||
| 317 | // into full 16-byte B, G, R output registers | ||
| 318 | // ============================================================ | ||
| 319 | static AVS_FORCEINLINE void deinterleave_bgr8_16px( | ||
| 320 | __m128i r0, __m128i r1, __m128i r2, | ||
| 321 | __m128i& B, __m128i& G, __m128i& R) | ||
| 322 | { | ||
| 323 | // Split 48-byte stream into 4 groups of 12 bytes (4 pixels each), | ||
| 324 | // each aligned to byte 0 of a 128-bit register: | ||
| 325 | // group0: r0[0..11] | ||
| 326 | // group1: r0[12..15] ++ r1[0..7] = alignr(r1, r0, 12) | ||
| 327 | // group2: r1[8..15] ++ r2[0..3] = alignr(r2, r1, 8) | ||
| 328 | // group3: r2[4..15] = srli(r2, 4) | ||
| 329 | 30 | __m128i g0 = r0; | |
| 330 | 30 | __m128i g1 = sse2_alignr<12>(r1, r0); | |
| 331 | 30 | __m128i g2 = sse2_alignr<8>(r2, r1); | |
| 332 | 30 | __m128i g3 = _mm_srli_si128(r2, 4); | |
| 333 | |||
| 334 | // Extract channels from each group (4 valid bytes each in positions 0..3) | ||
| 335 | __m128i B0, G0, R0, B1, G1, R1, B2, G2, R2, B3, G3, R3; | ||
| 336 | gather_bgr8_4px(g0, B0, G0, R0); | ||
| 337 | gather_bgr8_4px(g1, B1, G1, R1); | ||
| 338 | gather_bgr8_4px(g2, B2, G2, R2); | ||
| 339 | gather_bgr8_4px(g3, B3, G3, R3); | ||
| 340 | |||
| 341 | // Combine 4 groups × 4 bytes into one 16-byte register per channel. | ||
| 342 | // Each Bx/Gx/Rx has its 4 bytes in the low dword (bytes 0..3). | ||
| 343 | // unpacklo_epi32 interleaves low dwords of two registers: | ||
| 344 | // unpacklo_epi32(A, B) = [A.dw0, B.dw0, A.dw1, B.dw1] | ||
| 345 | // unpacklo_epi64 combines low qwords: | ||
| 346 | // unpacklo_epi64(A, B) = [A.qw0, B.qw0] | ||
| 347 | 30 | __m128i B01 = _mm_unpacklo_epi32(B0, B1); // [B_g0(4B), B_g1(4B), ...] | |
| 348 | 60 | __m128i B23 = _mm_unpacklo_epi32(B2, B3); | |
| 349 | 30 | B = _mm_unpacklo_epi64(B01, B23); // all 16 B bytes | |
| 350 | |||
| 351 | 30 | __m128i G01 = _mm_unpacklo_epi32(G0, G1); | |
| 352 | 60 | __m128i G23 = _mm_unpacklo_epi32(G2, G3); | |
| 353 | 30 | G = _mm_unpacklo_epi64(G01, G23); | |
| 354 | |||
| 355 | 30 | __m128i R01 = _mm_unpacklo_epi32(R0, R1); | |
| 356 | 60 | __m128i R23 = _mm_unpacklo_epi32(R2, R3); | |
| 357 | 30 | R = _mm_unpacklo_epi64(R01, R23); | |
| 358 | 30 | } | |
| 359 | |||
| 360 | // ============================================================ | ||
| 361 | // 16-bit helper: gather B, G, R from 2 BGR16 pixels | ||
| 362 | // | ||
| 363 | // Input 'grp': low 12 bytes hold 2 BGR16 pixels | ||
| 364 | // word: 0 1 2 3 4 5 | ||
| 365 | // data: B0 G0 R0 B1 G1 R1 | ||
| 366 | // | ||
| 367 | // Output bOut, gOut, rOut: valid words in positions 0..1 only | ||
| 368 | // bOut[0..1] = B0 B1 | ||
| 369 | // gOut[0..1] = G0 G1 | ||
| 370 | // rOut[0..1] = R0 R1 | ||
| 371 | // ============================================================ | ||
| 372 | static AVS_FORCEINLINE void gather_bgr16_2px(__m128i grp, | ||
| 373 | __m128i& bOut, __m128i& gOut, __m128i& rOut) | ||
| 374 | { | ||
| 375 | // Words in grp: B0 G0 R0 B1 G1 R1 x x | ||
| 376 | // Blue: w0, w3. Use shuffle to bring them to low dword. | ||
| 377 | 120 | bOut = _mm_shufflelo_epi16(grp, _MM_SHUFFLE(3, 3, 3, 0)); | |
| 378 | // Green: w1, w4. | ||
| 379 | 120 | gOut = _mm_shufflelo_epi16(_mm_srli_si128(grp, 2), _MM_SHUFFLE(3, 3, 3, 0)); | |
| 380 | // Red: w2, w5. | ||
| 381 | 90 | rOut = _mm_shufflelo_epi16(_mm_srli_si128(grp, 4), _MM_SHUFFLE(3, 3, 3, 0)); | |
| 382 | |||
| 383 | // Mask out the upper 3 dwords if necessary (though unpacklo handles it) | ||
| 384 | 120 | __m128i mask = _mm_set_epi32(0, 0, 0, 0xFFFFFFFF); | |
| 385 | 120 | bOut = _mm_and_si128(bOut, mask); | |
| 386 | 120 | gOut = _mm_and_si128(gOut, mask); | |
| 387 | 120 | rOut = _mm_and_si128(rOut, mask); | |
| 388 | 120 | } | |
| 389 | |||
| 390 | // ============================================================ | ||
| 391 | // 16-bit: deinterleave 8 BGR16 pixels from 3 × 16-byte registers | ||
| 392 | // into full 16-byte B, G, R output registers | ||
| 393 | // ============================================================ | ||
| 394 | static AVS_FORCEINLINE void deinterleave_bgr16_8px( | ||
| 395 | __m128i r0, __m128i r1, __m128i r2, | ||
| 396 | __m128i& B, __m128i& G, __m128i& R) | ||
| 397 | { | ||
| 398 | // Same group extraction as 8-bit case (48 bytes, same offsets) | ||
| 399 | 30 | __m128i g0 = r0; | |
| 400 | 30 | __m128i g1 = sse2_alignr<12>(r1, r0); | |
| 401 | 30 | __m128i g2 = sse2_alignr<8>(r2, r1); | |
| 402 | 30 | __m128i g3 = _mm_srli_si128(r2, 4); | |
| 403 | |||
| 404 | // Each group: 12 bytes = 6 words = 2 BGR16 pixels | ||
| 405 | // Each output xB/xG/xR has 2 valid words (4 bytes) in dword 0 | ||
| 406 | __m128i B0, G0, R0, B1, G1, R1, B2, G2, R2, B3, G3, R3; | ||
| 407 | gather_bgr16_2px(g0, B0, G0, R0); | ||
| 408 | gather_bgr16_2px(g1, B1, G1, R1); | ||
| 409 | gather_bgr16_2px(g2, B2, G2, R2); | ||
| 410 | gather_bgr16_2px(g3, B3, G3, R3); | ||
| 411 | |||
| 412 | // Combine: 4 groups × 2 words = 8 words = 16 bytes per channel | ||
| 413 | 30 | __m128i B01 = _mm_unpacklo_epi32(B0, B1); | |
| 414 | 60 | __m128i B23 = _mm_unpacklo_epi32(B2, B3); | |
| 415 | 30 | B = _mm_unpacklo_epi64(B01, B23); | |
| 416 | |||
| 417 | 30 | __m128i G01 = _mm_unpacklo_epi32(G0, G1); | |
| 418 | 60 | __m128i G23 = _mm_unpacklo_epi32(G2, G3); | |
| 419 | 30 | G = _mm_unpacklo_epi64(G01, G23); | |
| 420 | |||
| 421 | 30 | __m128i R01 = _mm_unpacklo_epi32(R0, R1); | |
| 422 | 60 | __m128i R23 = _mm_unpacklo_epi32(R2, R3); | |
| 423 | 30 | R = _mm_unpacklo_epi64(R01, R23); | |
| 424 | 30 | } | |
| 425 | |||
| 426 | // ============================================================ | ||
| 427 | // Main conversion function | ||
| 428 | // ============================================================ | ||
| 429 | // RGB24/48 -> RGBP(A)8/16 SSE2 implementation. Ugly and not very quick. | ||
| 430 | template<typename pixel_t, bool targetHasAlpha> | ||
| 431 | 4 | void convert_rgb_to_rgbp_sse2(const BYTE* srcp, BYTE* (&dstp)[4], | |
| 432 | int src_pitch, int(&dst_pitch)[4], | ||
| 433 | int width, int height) | ||
| 434 | { | ||
| 435 | 4 | const int pixels_at_a_time = (sizeof(pixel_t) == 1) ? 16 : 8; | |
| 436 | 4 | const int wmod = (width / pixels_at_a_time) * pixels_at_a_time; | |
| 437 | |||
| 438 | __m128i max_pixel_value; | ||
| 439 | if constexpr (sizeof(pixel_t) == 1) | ||
| 440 | 2 | max_pixel_value = _mm_set1_epi8((char)0xFF); | |
| 441 | else | ||
| 442 | 2 | max_pixel_value = _mm_set1_epi16((short)0xFFFF); | |
| 443 | |||
| 444 |
8/8void convert_rgb_to_rgbp_sse2<unsigned char, false>(unsigned char const*, unsigned char* (&) [4], int, int (&) [4], int, int):
✓ Branch 621 → 7 taken 5 times.
✓ Branch 621 → 622 taken 1 time.
void convert_rgb_to_rgbp_sse2<unsigned char, true>(unsigned char const*, unsigned char* (&) [4], int, int (&) [4], int, int):
✓ Branch 623 → 7 taken 5 times.
✓ Branch 623 → 624 taken 1 time.
void convert_rgb_to_rgbp_sse2<unsigned short, false>(unsigned char const*, unsigned char* (&) [4], int, int (&) [4], int, int):
✓ Branch 157 → 7 taken 5 times.
✓ Branch 157 → 158 taken 1 time.
void convert_rgb_to_rgbp_sse2<unsigned short, true>(unsigned char const*, unsigned char* (&) [4], int, int (&) [4], int, int):
✓ Branch 159 → 7 taken 5 times.
✓ Branch 159 → 160 taken 1 time.
|
24 | for (int y = height; y > 0; --y) { |
| 445 | |||
| 446 |
8/8void convert_rgb_to_rgbp_sse2<unsigned char, false>(unsigned char const*, unsigned char* (&) [4], int, int (&) [4], int, int):
✓ Branch 313 → 8 taken 10 times.
✓ Branch 313 → 314 taken 5 times.
void convert_rgb_to_rgbp_sse2<unsigned char, true>(unsigned char const*, unsigned char* (&) [4], int, int (&) [4], int, int):
✓ Branch 314 → 8 taken 10 times.
✓ Branch 314 → 315 taken 5 times.
void convert_rgb_to_rgbp_sse2<unsigned short, false>(unsigned char const*, unsigned char* (&) [4], int, int (&) [4], int, int):
✓ Branch 81 → 8 taken 10 times.
✓ Branch 81 → 82 taken 5 times.
void convert_rgb_to_rgbp_sse2<unsigned short, true>(unsigned char const*, unsigned char* (&) [4], int, int (&) [4], int, int):
✓ Branch 82 → 8 taken 10 times.
✓ Branch 82 → 83 taken 5 times.
|
60 | for (int x = 0; x < wmod; x += pixels_at_a_time) { |
| 447 | 40 | const BYTE* src = srcp + x * 3 * sizeof(pixel_t); | |
| 448 | 40 | __m128i r0 = _mm_load_si128(reinterpret_cast<const __m128i*>(src)); | |
| 449 | 40 | __m128i r1 = _mm_load_si128(reinterpret_cast<const __m128i*>(src + 16)); | |
| 450 | 80 | __m128i r2 = _mm_load_si128(reinterpret_cast<const __m128i*>(src + 32)); | |
| 451 | |||
| 452 | __m128i B, G, R; | ||
| 453 | if constexpr (sizeof(pixel_t) == 1) | ||
| 454 | deinterleave_bgr8_16px(r0, r1, r2, B, G, R); | ||
| 455 | else | ||
| 456 | deinterleave_bgr16_8px(r0, r1, r2, B, G, R); | ||
| 457 | |||
| 458 | 40 | _mm_store_si128(reinterpret_cast<__m128i*>(dstp[1] + x * sizeof(pixel_t)), B); | |
| 459 | 40 | _mm_store_si128(reinterpret_cast<__m128i*>(dstp[0] + x * sizeof(pixel_t)), G); | |
| 460 | 40 | _mm_store_si128(reinterpret_cast<__m128i*>(dstp[2] + x * sizeof(pixel_t)), R); | |
| 461 | if constexpr (targetHasAlpha) | ||
| 462 | 20 | _mm_store_si128(reinterpret_cast<__m128i*>(dstp[3] + x * sizeof(pixel_t)), max_pixel_value); | |
| 463 | } | ||
| 464 | |||
| 465 |
4/8void convert_rgb_to_rgbp_sse2<unsigned char, false>(unsigned char const*, unsigned char* (&) [4], int, int (&) [4], int, int):
✓ Branch 314 → 315 taken 5 times.
✗ Branch 314 → 620 not taken.
void convert_rgb_to_rgbp_sse2<unsigned char, true>(unsigned char const*, unsigned char* (&) [4], int, int (&) [4], int, int):
✓ Branch 315 → 316 taken 5 times.
✗ Branch 315 → 622 not taken.
void convert_rgb_to_rgbp_sse2<unsigned short, false>(unsigned char const*, unsigned char* (&) [4], int, int (&) [4], int, int):
✓ Branch 82 → 83 taken 5 times.
✗ Branch 82 → 156 not taken.
void convert_rgb_to_rgbp_sse2<unsigned short, true>(unsigned char const*, unsigned char* (&) [4], int, int (&) [4], int, int):
✓ Branch 83 → 84 taken 5 times.
✗ Branch 83 → 158 not taken.
|
20 | if (wmod != width) { |
| 466 | 20 | size_t x = width - pixels_at_a_time; | |
| 467 | 20 | const BYTE* src = srcp + x * 3 * sizeof(pixel_t); | |
| 468 | 20 | __m128i r0 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(src)); | |
| 469 | 20 | __m128i r1 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(src + 16)); | |
| 470 | 40 | __m128i r2 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(src + 32)); | |
| 471 | |||
| 472 | __m128i B, G, R; | ||
| 473 | if constexpr (sizeof(pixel_t) == 1) | ||
| 474 | deinterleave_bgr8_16px(r0, r1, r2, B, G, R); | ||
| 475 | else | ||
| 476 | deinterleave_bgr16_8px(r0, r1, r2, B, G, R); | ||
| 477 | |||
| 478 | 20 | _mm_storeu_si128(reinterpret_cast<__m128i*>(dstp[1] + x * sizeof(pixel_t)), B); | |
| 479 | 20 | _mm_storeu_si128(reinterpret_cast<__m128i*>(dstp[0] + x * sizeof(pixel_t)), G); | |
| 480 | 20 | _mm_storeu_si128(reinterpret_cast<__m128i*>(dstp[2] + x * sizeof(pixel_t)), R); | |
| 481 | if constexpr (targetHasAlpha) | ||
| 482 | 10 | _mm_storeu_si128(reinterpret_cast<__m128i*>(dstp[3] + x * sizeof(pixel_t)), max_pixel_value); | |
| 483 | } | ||
| 484 | |||
| 485 | 20 | srcp -= src_pitch; | |
| 486 | 20 | dstp[0] += dst_pitch[0]; | |
| 487 | 20 | dstp[1] += dst_pitch[1]; | |
| 488 | 20 | dstp[2] += dst_pitch[2]; | |
| 489 | if constexpr (targetHasAlpha) | ||
| 490 | 10 | dstp[3] += dst_pitch[3]; | |
| 491 | } | ||
| 492 | 4 | } | |
| 493 | |||
| 494 | // Instantiations | ||
| 495 | template void convert_rgb_to_rgbp_sse2<uint8_t, false>(const BYTE*, BYTE* (&)[4], int, int(&)[4], int, int); | ||
| 496 | template void convert_rgb_to_rgbp_sse2<uint8_t, true>(const BYTE*, BYTE* (&)[4], int, int(&)[4], int, int); | ||
| 497 | template void convert_rgb_to_rgbp_sse2<uint16_t, false>(const BYTE*, BYTE* (&)[4], int, int(&)[4], int, int); | ||
| 498 | template void convert_rgb_to_rgbp_sse2<uint16_t, true>(const BYTE*, BYTE* (&)[4], int, int(&)[4], int, int); | ||
| 499 | |||
| 500 | // minimum width: 48 bytes | ||
| 501 | template<typename pixel_t, bool targetHasAlpha> | ||
| 502 | #if defined(GCC) || defined(CLANG) | ||
| 503 | __attribute__((__target__("ssse3"))) | ||
| 504 | #endif | ||
| 505 | 4 | void convert_rgb_to_rgbp_ssse3(const BYTE *srcp, BYTE * (&dstp)[4], int src_pitch, int(&dst_pitch)[4], int width, int height) | |
| 506 | { | ||
| 507 | // RGB24: 3x16 bytes cycle, 16*(RGB) 8bit pixels | ||
| 508 | // RGB48: 3x16 bytes cycle, 8*(RGB) 16bit pixels | ||
| 509 | // 0123456789ABCDEF 0123456789ABCDEF 0123456789ABCDEF | ||
| 510 | // BGRBGRBGRBGRBGRB GRBGRBGRBGRBGRBG RBGRBGRBGRBGRBGR // 8 bit | ||
| 511 | // B G R B G R B G R B G R B G R B G R B G R B G R // 16 bit | ||
| 512 | // 1111111111112222 2222222233333333 3333444444444444 | ||
| 513 | |||
| 514 | 4 | const int pixels_at_a_time = (sizeof(pixel_t) == 1) ? 16 : 8; | |
| 515 | 4 | const int wmod = (width / pixels_at_a_time) * pixels_at_a_time; // 8 pixels for 8 bit, 4 pixels for 16 bit | |
| 516 | __m128i mask; | ||
| 517 | if constexpr(sizeof(pixel_t) == 1) | ||
| 518 | 2 | mask = _mm_set_epi8(15, 14, 13, 12, 11, 8, 5, 2, 10, 7, 4, 1, 9, 6, 3, 0); | |
| 519 | else | ||
| 520 | 2 | mask = _mm_set_epi8(15, 14, 13, 12, 11, 10, 5, 4, 9, 8, 3, 2, 7, 6, 1, 0); | |
| 521 | |||
| 522 | __m128i max_pixel_value; | ||
| 523 | if constexpr(sizeof(pixel_t) == 1) | ||
| 524 | 2 | max_pixel_value = _mm_set1_epi8((char)0xFF); | |
| 525 | else | ||
| 526 | 2 | max_pixel_value = _mm_set1_epi16((short)0xFFFF); // bits_per_pixel is 16 | |
| 527 | |||
| 528 |
8/8void convert_rgb_to_rgbp_ssse3<unsigned char, false>(unsigned char const*, unsigned char* (&) [4], int, int (&) [4], int, int):
✓ Branch 79 → 9 taken 5 times.
✓ Branch 79 → 80 taken 1 time.
void convert_rgb_to_rgbp_ssse3<unsigned char, true>(unsigned char const*, unsigned char* (&) [4], int, int (&) [4], int, int):
✓ Branch 79 → 9 taken 5 times.
✓ Branch 79 → 80 taken 1 time.
void convert_rgb_to_rgbp_ssse3<unsigned short, false>(unsigned char const*, unsigned char* (&) [4], int, int (&) [4], int, int):
✓ Branch 79 → 9 taken 5 times.
✓ Branch 79 → 80 taken 1 time.
void convert_rgb_to_rgbp_ssse3<unsigned short, true>(unsigned char const*, unsigned char* (&) [4], int, int (&) [4], int, int):
✓ Branch 79 → 9 taken 5 times.
✓ Branch 79 → 80 taken 1 time.
|
24 | for (int y = height; y > 0; --y) { |
| 529 | __m128i BGRA_1, BGRA_2, BGRA_3; | ||
| 530 |
8/8void convert_rgb_to_rgbp_ssse3<unsigned char, false>(unsigned char const*, unsigned char* (&) [4], int, int (&) [4], int, int):
✓ Branch 43 → 10 taken 10 times.
✓ Branch 43 → 44 taken 5 times.
void convert_rgb_to_rgbp_ssse3<unsigned char, true>(unsigned char const*, unsigned char* (&) [4], int, int (&) [4], int, int):
✓ Branch 43 → 10 taken 10 times.
✓ Branch 43 → 44 taken 5 times.
void convert_rgb_to_rgbp_ssse3<unsigned short, false>(unsigned char const*, unsigned char* (&) [4], int, int (&) [4], int, int):
✓ Branch 43 → 10 taken 10 times.
✓ Branch 43 → 44 taken 5 times.
void convert_rgb_to_rgbp_ssse3<unsigned short, true>(unsigned char const*, unsigned char* (&) [4], int, int (&) [4], int, int):
✓ Branch 43 → 10 taken 10 times.
✓ Branch 43 → 44 taken 5 times.
|
60 | for (int x = 0; x < wmod; x += pixels_at_a_time) { |
| 531 | 40 | BGRA_1 = _mm_load_si128(reinterpret_cast<const __m128i *>(srcp + x * 48 / pixels_at_a_time)); | |
| 532 | 40 | BGRA_2 = _mm_load_si128(reinterpret_cast<const __m128i *>(srcp + x * 48 / pixels_at_a_time + 16)); | |
| 533 | 80 | BGRA_3 = _mm_load_si128(reinterpret_cast<const __m128i *>(srcp + x * 48 / pixels_at_a_time + 32)); | |
| 534 | |||
| 535 | 40 | auto pack_lo = _mm_shuffle_epi8(BGRA_1, mask); // 111111111111: BBBBGGGGRRRR and rest: BGRB | BBGGRR and rest: BBGG | |
| 536 | 40 | BGRA_1 = _mm_alignr_epi8(BGRA_2, BGRA_1, 12); | |
| 537 | 40 | auto pack_hi = _mm_shuffle_epi8(BGRA_1, mask); // 222222222222: BBBBGGGGRRRR | BBGGRR | |
| 538 | 40 | BGRA_2 = _mm_alignr_epi8(BGRA_3, BGRA_2, 8); | |
| 539 | 40 | auto pack_lo2 = _mm_shuffle_epi8(BGRA_2, mask); // 333333333333: BBBBGGGGRRRR | BBGGRR | |
| 540 | 40 | BGRA_3 = _mm_srli_si128(BGRA_3, 4); // to use the same mask | |
| 541 | 40 | auto pack_hi2 = _mm_shuffle_epi8(BGRA_3, mask); // 444444444444: BBBBGGGGRRRR | BBGGRR | |
| 542 | |||
| 543 | 40 | __m128i BG1 = _mm_unpacklo_epi32(pack_lo, pack_hi); // BBBB_lo BBBB_hi GGGG_lo GGGG_hi | |
| 544 | 40 | __m128i BG2 = _mm_unpacklo_epi32(pack_lo2, pack_hi2); // BBBB_lo BBBB_hi GGGG_lo GGGG_hi | |
| 545 | 40 | __m128i RA1 = _mm_unpackhi_epi32(pack_lo, pack_hi); // RRRR_lo RRRR_hi AAAA_lo AAAA_hi | |
| 546 | 40 | __m128i RA2 = _mm_unpackhi_epi32(pack_lo2, pack_hi2); // RRRR_lo RRRR_hi AAAA_lo AAAA_hi | |
| 547 | 40 | __m128i B = _mm_unpacklo_epi64(BG1, BG2); | |
| 548 | 40 | _mm_store_si128(reinterpret_cast<__m128i *>(dstp[1] + x * sizeof(pixel_t)), B); // B | |
| 549 | 40 | __m128i G = _mm_unpackhi_epi64(BG1, BG2); | |
| 550 | 40 | _mm_store_si128(reinterpret_cast<__m128i *>(dstp[0] + x * sizeof(pixel_t)), G); // G | |
| 551 | 40 | __m128i R = _mm_unpacklo_epi64(RA1, RA2); | |
| 552 | 40 | _mm_store_si128(reinterpret_cast<__m128i *>(dstp[2] + x * sizeof(pixel_t)), R); // R | |
| 553 | if (targetHasAlpha) | ||
| 554 | 20 | _mm_store_si128(reinterpret_cast<__m128i *>(dstp[3] + x * sizeof(pixel_t)), max_pixel_value); // A | |
| 555 | } | ||
| 556 | // rest, unaligned but simd | ||
| 557 | // RGB24/48 source is 3 bytes/pixel: no power-of-2 stride, 64-byte alignment does not guarantee width is a multiple of 16/8 | ||
| 558 | // So we cannot spare the last chunk | ||
| 559 |
4/8void convert_rgb_to_rgbp_ssse3<unsigned char, false>(unsigned char const*, unsigned char* (&) [4], int, int (&) [4], int, int):
✓ Branch 44 → 45 taken 5 times.
✗ Branch 44 → 77 not taken.
void convert_rgb_to_rgbp_ssse3<unsigned char, true>(unsigned char const*, unsigned char* (&) [4], int, int (&) [4], int, int):
✓ Branch 44 → 45 taken 5 times.
✗ Branch 44 → 78 not taken.
void convert_rgb_to_rgbp_ssse3<unsigned short, false>(unsigned char const*, unsigned char* (&) [4], int, int (&) [4], int, int):
✓ Branch 44 → 45 taken 5 times.
✗ Branch 44 → 77 not taken.
void convert_rgb_to_rgbp_ssse3<unsigned short, true>(unsigned char const*, unsigned char* (&) [4], int, int (&) [4], int, int):
✓ Branch 44 → 45 taken 5 times.
✗ Branch 44 → 78 not taken.
|
20 | if (wmod != width) { |
| 560 | // width = 17: 0..7 8..15, 16 | ||
| 561 | // last_start = 1 (9..16 8 pixels) width - pixels_at_a_time | ||
| 562 | 20 | size_t x = (width - pixels_at_a_time); | |
| 563 | 20 | BGRA_1 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(srcp + x * 48 / pixels_at_a_time)); | |
| 564 | 20 | BGRA_2 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(srcp + x * 48 / pixels_at_a_time + 16)); | |
| 565 | 40 | BGRA_3 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(srcp + x * 48 / pixels_at_a_time + 32)); | |
| 566 | |||
| 567 | 20 | auto pack_lo = _mm_shuffle_epi8(BGRA_1, mask); // 111111111111: BBBBGGGGRRRR and rest: BGRB | BBGGRR and rest: BBGG | |
| 568 | 20 | BGRA_1 = _mm_alignr_epi8(BGRA_2, BGRA_1, 12); | |
| 569 | 20 | auto pack_hi = _mm_shuffle_epi8(BGRA_1, mask); // 222222222222: BBBBGGGGRRRR | BBGGRR | |
| 570 | 20 | BGRA_2 = _mm_alignr_epi8(BGRA_3, BGRA_2, 8); | |
| 571 | 20 | auto pack_lo2 = _mm_shuffle_epi8(BGRA_2, mask); // 333333333333: BBBBGGGGRRRR | BBGGRR | |
| 572 | 20 | BGRA_3 = _mm_srli_si128(BGRA_3, 4); // to use the same mask | |
| 573 | 20 | auto pack_hi2 = _mm_shuffle_epi8(BGRA_3, mask); // 444444444444: BBBBGGGGRRRR | BBGGRR | |
| 574 | |||
| 575 | 20 | __m128i BG1 = _mm_unpacklo_epi32(pack_lo, pack_hi); // BBBB_lo BBBB_hi GGGG_lo GGGG_hi | |
| 576 | 20 | __m128i BG2 = _mm_unpacklo_epi32(pack_lo2, pack_hi2); // BBBB_lo BBBB_hi GGGG_lo GGGG_hi | |
| 577 | 20 | __m128i RA1 = _mm_unpackhi_epi32(pack_lo, pack_hi); // RRRR_lo RRRR_hi AAAA_lo AAAA_hi | |
| 578 | 20 | __m128i RA2 = _mm_unpackhi_epi32(pack_lo2, pack_hi2); // RRRR_lo RRRR_hi AAAA_lo AAAA_hi | |
| 579 | 20 | __m128i B = _mm_unpacklo_epi64(BG1, BG2); | |
| 580 | 20 | _mm_storeu_si128(reinterpret_cast<__m128i *>(dstp[1] + x * sizeof(pixel_t)), B); // B | |
| 581 | 20 | __m128i G = _mm_unpackhi_epi64(BG1, BG2); | |
| 582 | 20 | _mm_storeu_si128(reinterpret_cast<__m128i *>(dstp[0] + x * sizeof(pixel_t)), G); // G | |
| 583 | 20 | __m128i R = _mm_unpacklo_epi64(RA1, RA2); | |
| 584 | 20 | _mm_storeu_si128(reinterpret_cast<__m128i *>(dstp[2] + x * sizeof(pixel_t)), R); // R | |
| 585 | if (targetHasAlpha) | ||
| 586 | 10 | _mm_storeu_si128(reinterpret_cast<__m128i *>(dstp[3] + x * sizeof(pixel_t)), max_pixel_value); // A | |
| 587 | } | ||
| 588 | 20 | srcp -= src_pitch; // source packed RGB is upside down | |
| 589 | 20 | dstp[0] += dst_pitch[0]; | |
| 590 | 20 | dstp[1] += dst_pitch[1]; | |
| 591 | 20 | dstp[2] += dst_pitch[2]; | |
| 592 | if (targetHasAlpha) | ||
| 593 | 10 | dstp[3] += dst_pitch[3]; | |
| 594 | } | ||
| 595 | 4 | } | |
| 596 | |||
| 597 | //instantiate | ||
| 598 | //template<typename pixel_t, bool targetHasAlpha> | ||
| 599 | template void convert_rgb_to_rgbp_ssse3<uint8_t, false>(const BYTE* srcp, BYTE* (&dstp)[4], int src_pitch, int(&dst_pitch)[4], int width, int height); | ||
| 600 | template void convert_rgb_to_rgbp_ssse3<uint8_t, true>(const BYTE* srcp, BYTE* (&dstp)[4], int src_pitch, int(&dst_pitch)[4], int width, int height); | ||
| 601 | template void convert_rgb_to_rgbp_ssse3<uint16_t, false>(const BYTE* srcp, BYTE* (&dstp)[4], int src_pitch, int(&dst_pitch)[4], int width, int height); | ||
| 602 | template void convert_rgb_to_rgbp_ssse3<uint16_t, true>(const BYTE* srcp, BYTE* (&dstp)[4], int src_pitch, int(&dst_pitch)[4], int width, int height); | ||
| 603 | |||
| 604 | |||
| 605 | // minimum width: 32 bytes (8 RGBA pixels for 8 bits, 4 RGBA pixels for 16 bits) | ||
| 606 | // RGB32/64 -> RGBP(A)8/16 SSE2 implementation. Ugly and not very quick. | ||
| 607 | template<typename pixel_t, bool targetHasAlpha> | ||
| 608 | 4 | void convert_rgba_to_rgbp_sse2(const BYTE* srcp, BYTE* (&dstp)[4], | |
| 609 | int src_pitch, int(&dst_pitch)[4], int width, int height) | ||
| 610 | { | ||
| 611 | 4 | const int pixels_at_a_time = (sizeof(pixel_t) == 1) ? 8 : 4; | |
| 612 | 4 | __m128i zero = _mm_setzero_si128(); | |
| 613 | |||
| 614 |
8/8void convert_rgba_to_rgbp_sse2<unsigned char, false>(unsigned char const*, unsigned char* (&) [4], int, int (&) [4], int, int):
✓ Branch 46 → 5 taken 5 times.
✓ Branch 46 → 47 taken 1 time.
void convert_rgba_to_rgbp_sse2<unsigned char, true>(unsigned char const*, unsigned char* (&) [4], int, int (&) [4], int, int):
✓ Branch 49 → 5 taken 5 times.
✓ Branch 49 → 50 taken 1 time.
void convert_rgba_to_rgbp_sse2<unsigned short, false>(unsigned char const*, unsigned char* (&) [4], int, int (&) [4], int, int):
✓ Branch 26 → 5 taken 5 times.
✓ Branch 26 → 27 taken 1 time.
void convert_rgba_to_rgbp_sse2<unsigned short, true>(unsigned char const*, unsigned char* (&) [4], int, int (&) [4], int, int):
✓ Branch 29 → 5 taken 5 times.
✓ Branch 29 → 30 taken 1 time.
|
24 | for (int y = height; y > 0; --y) { |
| 615 | // Avisynth's scanline alignment is 64 bytes, so no remainder handling is needed for 8-bit (16 pixels) and 16-bit (8 pixels) formats. | ||
| 616 |
8/8void convert_rgba_to_rgbp_sse2<unsigned char, false>(unsigned char const*, unsigned char* (&) [4], int, int (&) [4], int, int):
✓ Branch 44 → 6 taken 20 times.
✓ Branch 44 → 45 taken 5 times.
void convert_rgba_to_rgbp_sse2<unsigned char, true>(unsigned char const*, unsigned char* (&) [4], int, int (&) [4], int, int):
✓ Branch 47 → 6 taken 20 times.
✓ Branch 47 → 48 taken 5 times.
void convert_rgba_to_rgbp_sse2<unsigned short, false>(unsigned char const*, unsigned char* (&) [4], int, int (&) [4], int, int):
✓ Branch 24 → 6 taken 20 times.
✓ Branch 24 → 25 taken 5 times.
void convert_rgba_to_rgbp_sse2<unsigned short, true>(unsigned char const*, unsigned char* (&) [4], int, int (&) [4], int, int):
✓ Branch 27 → 6 taken 20 times.
✓ Branch 27 → 28 taken 5 times.
|
100 | for (int x = 0; x < width; x += pixels_at_a_time) { |
| 617 | 80 | const BYTE* src = srcp + x * 4 * sizeof(pixel_t); | |
| 618 | 80 | __m128i lo = _mm_load_si128(reinterpret_cast<const __m128i*>(src)); | |
| 619 | 160 | __m128i hi = _mm_load_si128(reinterpret_cast<const __m128i*>(src + 16)); | |
| 620 | __m128i ch0, ch1; | ||
| 621 | |||
| 622 | if constexpr (sizeof(pixel_t) == 1) { | ||
| 623 | 40 | __m128i w0 = _mm_unpacklo_epi8(lo, zero); | |
| 624 | 40 | __m128i w1 = _mm_unpackhi_epi8(lo, zero); | |
| 625 | 40 | __m128i c0 = _mm_unpacklo_epi16(w0, w1); | |
| 626 | 40 | __m128i c1 = _mm_unpackhi_epi16(w0, w1); | |
| 627 | 40 | __m128i lo_bg = _mm_unpacklo_epi16(c0, c1); | |
| 628 | 40 | __m128i lo_ra = _mm_unpackhi_epi16(c0, c1); | |
| 629 | 40 | __m128i w2 = _mm_unpacklo_epi8(hi, zero); | |
| 630 | 40 | __m128i w3 = _mm_unpackhi_epi8(hi, zero); | |
| 631 | 40 | __m128i c2 = _mm_unpacklo_epi16(w2, w3); | |
| 632 | 40 | __m128i c3 = _mm_unpackhi_epi16(w2, w3); | |
| 633 | 40 | __m128i hi_bg = _mm_unpacklo_epi16(c2, c3); | |
| 634 | 40 | __m128i hi_ra = _mm_unpackhi_epi16(c2, c3); | |
| 635 | 40 | ch0 = _mm_shuffle_epi32(_mm_packus_epi16(lo_bg, hi_bg), _MM_SHUFFLE(3, 1, 2, 0)); | |
| 636 | 40 | ch1 = _mm_shuffle_epi32(_mm_packus_epi16(lo_ra, hi_ra), _MM_SHUFFLE(3, 1, 2, 0)); | |
| 637 | } | ||
| 638 | else { | ||
| 639 | 40 | __m128i t0 = _mm_unpacklo_epi16(lo, hi); | |
| 640 | 40 | __m128i t1 = _mm_unpackhi_epi16(lo, hi); | |
| 641 | 40 | ch0 = _mm_unpacklo_epi16(t0, t1); | |
| 642 | 40 | ch1 = _mm_unpackhi_epi16(t0, t1); | |
| 643 | } | ||
| 644 | // Stores 8 byte per channel, so we can use storel_epi64. The high 64 bits of ch0/ch1 are ignored. | ||
| 645 | 80 | _mm_storel_epi64(reinterpret_cast<__m128i*>(dstp[1] + x * sizeof(pixel_t)), ch0); // B | |
| 646 | 80 | _mm_storeh_pd(reinterpret_cast<double*>(dstp[0] + x * sizeof(pixel_t)),_mm_castsi128_pd(ch0)); // G | |
| 647 | 80 | _mm_storel_epi64(reinterpret_cast<__m128i*>(dstp[2] + x * sizeof(pixel_t)), ch1); // R | |
| 648 | if constexpr (targetHasAlpha) | ||
| 649 | 40 | _mm_storeh_pd(reinterpret_cast<double*>(dstp[3] + x * sizeof(pixel_t)), _mm_castsi128_pd(ch1)); // A | |
| 650 | } | ||
| 651 | |||
| 652 | 20 | srcp -= src_pitch; | |
| 653 | 20 | dstp[0] += dst_pitch[0]; | |
| 654 | 20 | dstp[1] += dst_pitch[1]; | |
| 655 | 20 | dstp[2] += dst_pitch[2]; | |
| 656 | if constexpr (targetHasAlpha) | ||
| 657 | 10 | dstp[3] += dst_pitch[3]; | |
| 658 | } | ||
| 659 | 4 | } | |
| 660 | |||
| 661 | // Instantiations | ||
| 662 | template void convert_rgba_to_rgbp_sse2<uint8_t, false>(const BYTE*, BYTE* (&)[4], int, int(&)[4], int, int); | ||
| 663 | template void convert_rgba_to_rgbp_sse2<uint8_t, true>(const BYTE*, BYTE* (&)[4], int, int(&)[4], int, int); | ||
| 664 | template void convert_rgba_to_rgbp_sse2<uint16_t, false>(const BYTE*, BYTE* (&)[4], int, int(&)[4], int, int); | ||
| 665 | template void convert_rgba_to_rgbp_sse2<uint16_t, true>(const BYTE*, BYTE* (&)[4], int, int(&)[4], int, int); | ||
| 666 | |||
| 667 | |||
| 668 | template<typename pixel_t, bool targetHasAlpha> | ||
| 669 | #if defined(GCC) || defined(CLANG) | ||
| 670 | __attribute__((__target__("ssse3"))) | ||
| 671 | #endif | ||
| 672 | 4 | void convert_rgba_to_rgbp_ssse3(const BYTE* srcp, BYTE* (&dstp)[4], int src_pitch, int(&dst_pitch)[4], int width, int height) | |
| 673 | { | ||
| 674 | 4 | const int pixels_at_a_time = (sizeof(pixel_t) == 1) ? 8 : 4; | |
| 675 | |||
| 676 | __m128i mask; | ||
| 677 | if constexpr (sizeof(pixel_t) == 1) | ||
| 678 | 2 | mask = _mm_set_epi8(15, 11, 7, 3, 14, 10, 6, 2, 13, 9, 5, 1, 12, 8, 4, 0); | |
| 679 | else | ||
| 680 | 2 | mask = _mm_set_epi8(15, 14, 7, 6, 13, 12, 5, 4, 11, 10, 3, 2, 9, 8, 1, 0); | |
| 681 | |||
| 682 |
8/8void convert_rgba_to_rgbp_ssse3<unsigned char, false>(unsigned char const*, unsigned char* (&) [4], int, int (&) [4], int, int):
✓ Branch 26 → 5 taken 5 times.
✓ Branch 26 → 27 taken 1 time.
void convert_rgba_to_rgbp_ssse3<unsigned char, true>(unsigned char const*, unsigned char* (&) [4], int, int (&) [4], int, int):
✓ Branch 29 → 5 taken 5 times.
✓ Branch 29 → 30 taken 1 time.
void convert_rgba_to_rgbp_ssse3<unsigned short, false>(unsigned char const*, unsigned char* (&) [4], int, int (&) [4], int, int):
✓ Branch 26 → 5 taken 5 times.
✓ Branch 26 → 27 taken 1 time.
void convert_rgba_to_rgbp_ssse3<unsigned short, true>(unsigned char const*, unsigned char* (&) [4], int, int (&) [4], int, int):
✓ Branch 29 → 5 taken 5 times.
✓ Branch 29 → 30 taken 1 time.
|
24 | for (int y = height; y > 0; --y) { |
| 683 | // Avisynth's scanline alignment is 64 bytes, so no remainder handling is needed for 8 RGB32 or 4 RGB64 pixels | ||
| 684 |
8/8void convert_rgba_to_rgbp_ssse3<unsigned char, false>(unsigned char const*, unsigned char* (&) [4], int, int (&) [4], int, int):
✓ Branch 24 → 6 taken 20 times.
✓ Branch 24 → 25 taken 5 times.
void convert_rgba_to_rgbp_ssse3<unsigned char, true>(unsigned char const*, unsigned char* (&) [4], int, int (&) [4], int, int):
✓ Branch 27 → 6 taken 20 times.
✓ Branch 27 → 28 taken 5 times.
void convert_rgba_to_rgbp_ssse3<unsigned short, false>(unsigned char const*, unsigned char* (&) [4], int, int (&) [4], int, int):
✓ Branch 24 → 6 taken 20 times.
✓ Branch 24 → 25 taken 5 times.
void convert_rgba_to_rgbp_ssse3<unsigned short, true>(unsigned char const*, unsigned char* (&) [4], int, int (&) [4], int, int):
✓ Branch 27 → 6 taken 20 times.
✓ Branch 27 → 28 taken 5 times.
|
100 | for (int x = 0; x < width; x += pixels_at_a_time) { |
| 685 | 80 | __m128i BGRA_lo = _mm_load_si128(reinterpret_cast<const __m128i*>(srcp + x * 4 * sizeof(pixel_t))); | |
| 686 | 160 | __m128i BGRA_hi = _mm_load_si128(reinterpret_cast<const __m128i*>(srcp + x * 4 * sizeof(pixel_t) + 16)); | |
| 687 | 80 | __m128i pack_lo = _mm_shuffle_epi8(BGRA_lo, mask); | |
| 688 | 80 | __m128i pack_hi = _mm_shuffle_epi8(BGRA_hi, mask); | |
| 689 | 80 | __m128i eightbytes_of_pixels = _mm_unpacklo_epi32(pack_lo, pack_hi); | |
| 690 | 80 | _mm_storel_epi64(reinterpret_cast<__m128i*>(dstp[1] + x * sizeof(pixel_t)), eightbytes_of_pixels); // B | |
| 691 | 80 | _mm_storeh_pd(reinterpret_cast<double*>(dstp[0] + x * sizeof(pixel_t)), _mm_castsi128_pd(eightbytes_of_pixels)); // G | |
| 692 | 80 | eightbytes_of_pixels = _mm_unpackhi_epi32(pack_lo, pack_hi); | |
| 693 | 80 | _mm_storel_epi64(reinterpret_cast<__m128i*>(dstp[2] + x * sizeof(pixel_t)), eightbytes_of_pixels); // R | |
| 694 | if constexpr (targetHasAlpha) | ||
| 695 | 40 | _mm_storeh_pd(reinterpret_cast<double*>(dstp[3] + x * sizeof(pixel_t)), _mm_castsi128_pd(eightbytes_of_pixels)); // A | |
| 696 | } | ||
| 697 | 20 | srcp -= src_pitch; | |
| 698 | 20 | dstp[0] += dst_pitch[0]; | |
| 699 | 20 | dstp[1] += dst_pitch[1]; | |
| 700 | 20 | dstp[2] += dst_pitch[2]; | |
| 701 | if constexpr (targetHasAlpha) | ||
| 702 | 10 | dstp[3] += dst_pitch[3]; | |
| 703 | } | ||
| 704 | 4 | } | |
| 705 | |||
| 706 | //instantiate | ||
| 707 | //template<typename pixel_t, bool targetHasAlpha> | ||
| 708 | template void convert_rgba_to_rgbp_ssse3<uint8_t, false>(const BYTE* srcp, BYTE* (&dstp)[4], int src_pitch, int(&dst_pitch)[4], int width, int height); | ||
| 709 | template void convert_rgba_to_rgbp_ssse3<uint8_t, true>(const BYTE* srcp, BYTE* (&dstp)[4], int src_pitch, int(&dst_pitch)[4], int width, int height); | ||
| 710 | template void convert_rgba_to_rgbp_ssse3<uint16_t, false>(const BYTE* srcp, BYTE* (&dstp)[4], int src_pitch, int(&dst_pitch)[4], int width, int height); | ||
| 711 | template void convert_rgba_to_rgbp_ssse3<uint16_t, true>(const BYTE* srcp, BYTE* (&dstp)[4], int src_pitch, int(&dst_pitch)[4], int width, int height); | ||
| 712 | |||
| 713 | template<typename pixel_t, bool hasSrcAlpha> | ||
| 714 | 4 | void convert_rgbp_to_rgba_sse2(const BYTE* (&srcp)[4], BYTE* dstp, int(&src_pitch)[4], int dst_pitch, int width, int height) | |
| 715 | { | ||
| 716 | 4 | const int pixels_at_a_time = 8 / sizeof(pixel_t); // 8x uint8_t, 4x uint16_t | |
| 717 | 4 | const __m128i transparent = _mm_set1_epi8((char)0xFF); | |
| 718 | // Avisynth's scanline alignment is 64 bytes, so no remainder handling is needed for 8 RGB32 or 4 RGB64 pixels | ||
| 719 |
8/8void convert_rgbp_to_rgba_sse2<unsigned char, false>(unsigned char const* (&) [4], unsigned char*, int (&) [4], int, int, int):
✓ Branch 39 → 7 taken 5 times.
✓ Branch 39 → 40 taken 1 time.
void convert_rgbp_to_rgba_sse2<unsigned char, true>(unsigned char const* (&) [4], unsigned char*, int (&) [4], int, int, int):
✓ Branch 45 → 7 taken 5 times.
✓ Branch 45 → 46 taken 1 time.
void convert_rgbp_to_rgba_sse2<unsigned short, false>(unsigned char const* (&) [4], unsigned char*, int (&) [4], int, int, int):
✓ Branch 39 → 7 taken 5 times.
✓ Branch 39 → 40 taken 1 time.
void convert_rgbp_to_rgba_sse2<unsigned short, true>(unsigned char const* (&) [4], unsigned char*, int (&) [4], int, int, int):
✓ Branch 45 → 7 taken 5 times.
✓ Branch 45 → 46 taken 1 time.
|
24 | for (int y = 0; y < height; y++) { |
| 720 |
8/8void convert_rgbp_to_rgba_sse2<unsigned char, false>(unsigned char const* (&) [4], unsigned char*, int (&) [4], int, int, int):
✓ Branch 37 → 8 taken 30 times.
✓ Branch 37 → 38 taken 5 times.
void convert_rgbp_to_rgba_sse2<unsigned char, true>(unsigned char const* (&) [4], unsigned char*, int (&) [4], int, int, int):
✓ Branch 43 → 8 taken 30 times.
✓ Branch 43 → 44 taken 5 times.
void convert_rgbp_to_rgba_sse2<unsigned short, false>(unsigned char const* (&) [4], unsigned char*, int (&) [4], int, int, int):
✓ Branch 37 → 8 taken 30 times.
✓ Branch 37 → 38 taken 5 times.
void convert_rgbp_to_rgba_sse2<unsigned short, true>(unsigned char const* (&) [4], unsigned char*, int (&) [4], int, int, int):
✓ Branch 43 → 8 taken 30 times.
✓ Branch 43 → 44 taken 5 times.
|
140 | for (int x = 0; x < width; x += pixels_at_a_time) { |
| 721 | __m128i R, G, B, A; | ||
| 722 | 120 | G = _mm_loadl_epi64(reinterpret_cast<const __m128i*>(srcp[0] + x * sizeof(pixel_t))); | |
| 723 | 120 | B = _mm_loadl_epi64(reinterpret_cast<const __m128i*>(srcp[1] + x * sizeof(pixel_t))); | |
| 724 | 120 | R = _mm_loadl_epi64(reinterpret_cast<const __m128i*>(srcp[2] + x * sizeof(pixel_t))); | |
| 725 | if constexpr (hasSrcAlpha) | ||
| 726 | 120 | A = _mm_loadl_epi64(reinterpret_cast<const __m128i*>(srcp[3] + x * sizeof(pixel_t))); | |
| 727 | else | ||
| 728 | 60 | A = transparent; | |
| 729 | |||
| 730 | if constexpr (sizeof(pixel_t) == 1) { | ||
| 731 | 60 | __m128i BG = _mm_unpacklo_epi8(B, G); | |
| 732 | 60 | __m128i RA = _mm_unpacklo_epi8(R, A); | |
| 733 | 60 | _mm_store_si128(reinterpret_cast<__m128i*>(dstp + x * 4), _mm_unpacklo_epi16(BG, RA)); // pixels 0..3 | |
| 734 | 60 | _mm_store_si128(reinterpret_cast<__m128i*>(dstp + x * 4 + 16), _mm_unpackhi_epi16(BG, RA)); // pixels 4..7 | |
| 735 | } | ||
| 736 | else { | ||
| 737 | 60 | __m128i BG = _mm_unpacklo_epi16(B, G); | |
| 738 | 60 | __m128i RA = _mm_unpacklo_epi16(R, A); | |
| 739 | 60 | _mm_store_si128(reinterpret_cast<__m128i*>(dstp + x * 8), _mm_unpacklo_epi32(BG, RA)); // pixels 0..1 | |
| 740 | 60 | _mm_store_si128(reinterpret_cast<__m128i*>(dstp + x * 8 + 16), _mm_unpackhi_epi32(BG, RA)); // pixels 2..3 | |
| 741 | } | ||
| 742 | } | ||
| 743 | 20 | dstp -= dst_pitch; | |
| 744 | 20 | srcp[0] += src_pitch[0]; | |
| 745 | 20 | srcp[1] += src_pitch[1]; | |
| 746 | 20 | srcp[2] += src_pitch[2]; | |
| 747 | if constexpr (hasSrcAlpha) | ||
| 748 | 10 | srcp[3] += src_pitch[3]; | |
| 749 | } | ||
| 750 | 4 | } | |
| 751 | |||
| 752 | //instantiate | ||
| 753 | //template<typename pixel_t, bool hasSrcAlpha> | ||
| 754 | template void convert_rgbp_to_rgba_sse2<uint8_t, false>(const BYTE* (&srcp)[4], BYTE* dstp, int(&src_pitch)[4], int dst_pitch, int width, int height); | ||
| 755 | template void convert_rgbp_to_rgba_sse2<uint8_t, true>(const BYTE* (&srcp)[4], BYTE* dstp, int(&src_pitch)[4], int dst_pitch, int width, int height); | ||
| 756 | template void convert_rgbp_to_rgba_sse2<uint16_t, false>(const BYTE* (&srcp)[4], BYTE* dstp, int(&src_pitch)[4], int dst_pitch, int width, int height); | ||
| 757 | template void convert_rgbp_to_rgba_sse2<uint16_t, true>(const BYTE* (&srcp)[4], BYTE* dstp, int(&src_pitch)[4], int dst_pitch, int width, int height); | ||
| 758 | |||
| 759 | |||
| 760 |