convert/intel/convert_rgb_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 | #include <avs/alignment.h> | ||
| 36 | #ifdef _MSC_VER | ||
| 37 | #include <intrin.h> | ||
| 38 | #else | ||
| 39 | #include <x86intrin.h> | ||
| 40 | #endif | ||
| 41 | #include <immintrin.h> | ||
| 42 | |||
| 43 | #ifndef _mm256_set_m128i | ||
| 44 | #define _mm256_set_m128i(v0, v1) _mm256_insertf128_si256(_mm256_castsi128_si256(v1), (v0), 1) | ||
| 45 | #endif | ||
| 46 | |||
| 47 | #ifndef _mm256_set_m128 | ||
| 48 | #define _mm256_set_m128(v0, v1) _mm256_insertf128_ps(_mm256_castps128_ps256(v1), (v0), 1) | ||
| 49 | #endif | ||
| 50 | |||
| 51 | #include "convert_rgb_avx2.h" | ||
| 52 | |||
| 53 | // minimum width: 48*2 bytes | ||
| 54 | template<typename pixel_t, bool targetHasAlpha> | ||
| 55 | 4 | void convert_rgb_to_rgbp_avx2(const BYTE *srcp, BYTE * (&dstp)[4], int src_pitch, int(&dst_pitch)[4], int width, int height) | |
| 56 | { | ||
| 57 | // RGB24: 2x3x16 bytes cycle, 2x16*(RGB) 8bit pixels | ||
| 58 | // RGB48: 2x3x16 bytes cycle, 2x8*(RGB) 16bit pixels | ||
| 59 | // 0123456789ABCDEF 0123456789ABCDEF 0123456789ABCDEF | ||
| 60 | // BGRBGRBGRBGRBGRB GRBGRBGRBGRBGRBG RBGRBGRBGRBGRBGR // 8 bit | ||
| 61 | // 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 | ||
| 62 | // 1111111111112222 2222222233333333 3333444444444444 | ||
| 63 | |||
| 64 | 4 | constexpr int pixels_at_a_time = (sizeof(pixel_t) == 1) ? 32 : 16; | |
| 65 | 4 | const int wmod = (width / pixels_at_a_time) * pixels_at_a_time; // 8 pixels for 8 bit, 4 pixels for 16 bit | |
| 66 | __m256i mask; | ||
| 67 | if constexpr(sizeof(pixel_t) == 1) | ||
| 68 | 2 | mask = _mm256_set_epi8(15, 14, 13, 12, 11, 8, 5, 2, 10, 7, 4, 1, 9, 6, 3, 0, | |
| 69 | 15, 14, 13, 12, 11, 8, 5, 2, 10, 7, 4, 1, 9, 6, 3, 0); // same for both lanes | ||
| 70 | else | ||
| 71 | 2 | mask = _mm256_set_epi8(15, 14, 13, 12, 11, 10, 5, 4, 9, 8, 3, 2, 7, 6, 1, 0, | |
| 72 | 15, 14, 13, 12, 11, 10, 5, 4, 9, 8, 3, 2, 7, 6, 1, 0); // same for both lanes | ||
| 73 | |||
| 74 | __m256i max_pixel_value; | ||
| 75 | if constexpr(sizeof(pixel_t) == 1) | ||
| 76 | 2 | max_pixel_value = _mm256_set1_epi8((char)0xFF); | |
| 77 | else | ||
| 78 | 2 | max_pixel_value = _mm256_set1_epi16((short)0xFFFF); // bits_per_pixel is 16 | |
| 79 | |||
| 80 | // read-optimized | ||
| 81 | #define SRC_ADDRESS_ADVANCES | ||
| 82 | #ifdef SRC_ADDRESS_ADVANCES | ||
| 83 | 4 | srcp -= src_pitch * (height - 1); // source packed RGB is upside down | |
| 84 | 4 | dstp[0] += dst_pitch[0] * (height - 1); | |
| 85 | 4 | dstp[1] += dst_pitch[1] * (height - 1); | |
| 86 | 4 | dstp[2] += dst_pitch[2] * (height - 1); | |
| 87 | if (targetHasAlpha) | ||
| 88 | 2 | dstp[3] += dst_pitch[3] * (height - 1); | |
| 89 | #endif | ||
| 90 | |||
| 91 |
8/8void convert_rgb_to_rgbp_avx2<unsigned char, false>(unsigned char const*, unsigned char* (&) [4], int, int (&) [4], int, int):
✓ Branch 104 → 10 taken 5 times.
✓ Branch 104 → 105 taken 1 time.
void convert_rgb_to_rgbp_avx2<unsigned char, true>(unsigned char const*, unsigned char* (&) [4], int, int (&) [4], int, int):
✓ Branch 103 → 9 taken 5 times.
✓ Branch 103 → 104 taken 1 time.
void convert_rgb_to_rgbp_avx2<unsigned short, false>(unsigned char const*, unsigned char* (&) [4], int, int (&) [4], int, int):
✓ Branch 104 → 10 taken 5 times.
✓ Branch 104 → 105 taken 1 time.
void convert_rgb_to_rgbp_avx2<unsigned short, true>(unsigned char const*, unsigned char* (&) [4], int, int (&) [4], int, int):
✓ Branch 103 → 9 taken 5 times.
✓ Branch 103 → 104 taken 1 time.
|
24 | for (int y = 0; y < height; y++) { |
| 92 |
8/8void convert_rgb_to_rgbp_avx2<unsigned char, false>(unsigned char const*, unsigned char* (&) [4], int, int (&) [4], int, int):
✓ Branch 56 → 11 taken 5 times.
✓ Branch 56 → 57 taken 5 times.
void convert_rgb_to_rgbp_avx2<unsigned char, true>(unsigned char const*, unsigned char* (&) [4], int, int (&) [4], int, int):
✓ Branch 55 → 10 taken 5 times.
✓ Branch 55 → 56 taken 5 times.
void convert_rgb_to_rgbp_avx2<unsigned short, false>(unsigned char const*, unsigned char* (&) [4], int, int (&) [4], int, int):
✓ Branch 56 → 11 taken 5 times.
✓ Branch 56 → 57 taken 5 times.
void convert_rgb_to_rgbp_avx2<unsigned short, true>(unsigned char const*, unsigned char* (&) [4], int, int (&) [4], int, int):
✓ Branch 55 → 10 taken 5 times.
✓ Branch 55 → 56 taken 5 times.
|
40 | for (int x = 0; x < wmod; x += pixels_at_a_time) { |
| 93 | 20 | auto BGRA_1_Lo48 = _mm_load_si128(reinterpret_cast<const __m128i*>(srcp + x * 2 * 48 / pixels_at_a_time)); | |
| 94 | 20 | auto BGRA_2_Lo48 = _mm_load_si128(reinterpret_cast<const __m128i*>(srcp + x * 2 * 48 / pixels_at_a_time + 16)); | |
| 95 | 20 | auto BGRA_3_Lo48 = _mm_load_si128(reinterpret_cast<const __m128i*>(srcp + x * 2 * 48 / pixels_at_a_time + 32)); | |
| 96 | |||
| 97 | 20 | auto BGRA_1_Hi48 = _mm_load_si128(reinterpret_cast<const __m128i*>(srcp + x * 2 * 48 / pixels_at_a_time + 0 + 48)); | |
| 98 | 20 | auto BGRA_2_Hi48 = _mm_load_si128(reinterpret_cast<const __m128i*>(srcp + x * 2 * 48 / pixels_at_a_time + 16 + 48)); | |
| 99 | 20 | auto BGRA_3_Hi48 = _mm_load_si128(reinterpret_cast<const __m128i*>(srcp + x * 2 * 48 / pixels_at_a_time + 32 + 48)); | |
| 100 | |||
| 101 | 20 | auto BGRA_1 = _mm256_set_m128i(BGRA_1_Hi48, BGRA_1_Lo48); | |
| 102 | 20 | auto BGRA_2 = _mm256_set_m128i(BGRA_2_Hi48, BGRA_2_Lo48); | |
| 103 | 40 | auto BGRA_3 = _mm256_set_m128i(BGRA_3_Hi48, BGRA_3_Lo48); | |
| 104 | |||
| 105 | 20 | auto pack_lo = _mm256_shuffle_epi8(BGRA_1, mask); // 111111111111: BBBBGGGGRRRR and rest: BGRB | BBGGRR and rest: BBGG | |
| 106 | 20 | BGRA_1 = _mm256_alignr_epi8(BGRA_2, BGRA_1, 12); | |
| 107 | 20 | auto pack_hi = _mm256_shuffle_epi8(BGRA_1, mask); // 222222222222: BBBBGGGGRRRR | BBGGRR | |
| 108 | 20 | BGRA_2 = _mm256_alignr_epi8(BGRA_3, BGRA_2, 8); | |
| 109 | 20 | auto pack_lo2 = _mm256_shuffle_epi8(BGRA_2, mask); // 333333333333: BBBBGGGGRRRR | BBGGRR | |
| 110 | 20 | BGRA_3 = _mm256_srli_si256(BGRA_3, 4); // to use the same mask | |
| 111 | 20 | auto pack_hi2 = _mm256_shuffle_epi8(BGRA_3, mask); // 444444444444: BBBBGGGGRRRR | BBGGRR | |
| 112 | |||
| 113 | 20 | auto BG1 = _mm256_unpacklo_epi32(pack_lo, pack_hi); // BBBB_lo BBBB_hi GGGG_lo GGGG_hi | |
| 114 | 20 | auto BG2 = _mm256_unpacklo_epi32(pack_lo2, pack_hi2); // BBBB_lo BBBB_hi GGGG_lo GGGG_hi | |
| 115 | 20 | auto RA1 = _mm256_unpackhi_epi32(pack_lo, pack_hi); // RRRR_lo RRRR_hi AAAA_lo AAAA_hi | |
| 116 | 20 | auto RA2 = _mm256_unpackhi_epi32(pack_lo2, pack_hi2); // RRRR_lo RRRR_hi AAAA_lo AAAA_hi | |
| 117 | 20 | auto B = _mm256_unpacklo_epi64(BG1, BG2); | |
| 118 | 20 | _mm256_stream_si256(reinterpret_cast<__m256i *>(dstp[1] + x * sizeof(pixel_t)), B); // B | |
| 119 | 20 | auto G = _mm256_unpackhi_epi64(BG1, BG2); | |
| 120 | 20 | _mm256_stream_si256(reinterpret_cast<__m256i *>(dstp[0] + x * sizeof(pixel_t)), G); // G | |
| 121 | 20 | auto R = _mm256_unpacklo_epi64(RA1, RA2); | |
| 122 | 20 | _mm256_stream_si256(reinterpret_cast<__m256i *>(dstp[2] + x * sizeof(pixel_t)), R); // R | |
| 123 | if (targetHasAlpha) | ||
| 124 | 10 | _mm256_stream_si256(reinterpret_cast<__m256i *>(dstp[3] + x * sizeof(pixel_t)), max_pixel_value); // A | |
| 125 | } | ||
| 126 | // rest, unaligned but simd | ||
| 127 |
4/8void convert_rgb_to_rgbp_avx2<unsigned char, false>(unsigned char const*, unsigned char* (&) [4], int, int (&) [4], int, int):
✓ Branch 57 → 58 taken 5 times.
✗ Branch 57 → 102 not taken.
void convert_rgb_to_rgbp_avx2<unsigned char, true>(unsigned char const*, unsigned char* (&) [4], int, int (&) [4], int, int):
✓ Branch 56 → 57 taken 5 times.
✗ Branch 56 → 102 not taken.
void convert_rgb_to_rgbp_avx2<unsigned short, false>(unsigned char const*, unsigned char* (&) [4], int, int (&) [4], int, int):
✓ Branch 57 → 58 taken 5 times.
✗ Branch 57 → 102 not taken.
void convert_rgb_to_rgbp_avx2<unsigned short, true>(unsigned char const*, unsigned char* (&) [4], int, int (&) [4], int, int):
✓ Branch 56 → 57 taken 5 times.
✗ Branch 56 → 102 not taken.
|
20 | if (wmod != width) { |
| 128 | 20 | size_t x = (width - pixels_at_a_time); | |
| 129 | 20 | auto BGRA_1_Lo48 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(srcp + x * 2 * 48 / pixels_at_a_time)); | |
| 130 | 20 | auto BGRA_2_Lo48 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(srcp + x * 2 * 48 / pixels_at_a_time + 16)); | |
| 131 | 20 | auto BGRA_3_Lo48 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(srcp + x * 2 * 48 / pixels_at_a_time + 32)); | |
| 132 | |||
| 133 | 20 | auto BGRA_1_Hi48 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(srcp + x * 2 * 48 / pixels_at_a_time + 0 + 48)); | |
| 134 | 20 | auto BGRA_2_Hi48 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(srcp + x * 2 * 48 / pixels_at_a_time + 16 + 48)); | |
| 135 | 20 | auto BGRA_3_Hi48 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(srcp + x * 2 * 48 / pixels_at_a_time + 32 + 48)); | |
| 136 | |||
| 137 | 20 | auto BGRA_1 = _mm256_set_m128i(BGRA_1_Hi48, BGRA_1_Lo48); | |
| 138 | 20 | auto BGRA_2 = _mm256_set_m128i(BGRA_2_Hi48, BGRA_2_Lo48); | |
| 139 | 40 | auto BGRA_3 = _mm256_set_m128i(BGRA_3_Hi48, BGRA_3_Lo48); | |
| 140 | |||
| 141 | 20 | auto pack_lo = _mm256_shuffle_epi8(BGRA_1, mask); // 111111111111: BBBBGGGGRRRR and rest: BGRB | BBGGRR and rest: BBGG | |
| 142 | 20 | BGRA_1 = _mm256_alignr_epi8(BGRA_2, BGRA_1, 12); | |
| 143 | 20 | auto pack_hi = _mm256_shuffle_epi8(BGRA_1, mask); // 222222222222: BBBBGGGGRRRR | BBGGRR | |
| 144 | 20 | BGRA_2 = _mm256_alignr_epi8(BGRA_3, BGRA_2, 8); | |
| 145 | 20 | auto pack_lo2 = _mm256_shuffle_epi8(BGRA_2, mask); // 333333333333: BBBBGGGGRRRR | BBGGRR | |
| 146 | 20 | BGRA_3 = _mm256_srli_si256(BGRA_3, 4); // to use the same mask | |
| 147 | 20 | auto pack_hi2 = _mm256_shuffle_epi8(BGRA_3, mask); // 444444444444: BBBBGGGGRRRR | BBGGRR | |
| 148 | |||
| 149 | 20 | auto BG1 = _mm256_unpacklo_epi32(pack_lo, pack_hi); // BBBB_lo BBBB_hi GGGG_lo GGGG_hi | |
| 150 | 20 | auto BG2 = _mm256_unpacklo_epi32(pack_lo2, pack_hi2); // BBBB_lo BBBB_hi GGGG_lo GGGG_hi | |
| 151 | 20 | auto RA1 = _mm256_unpackhi_epi32(pack_lo, pack_hi); // RRRR_lo RRRR_hi AAAA_lo AAAA_hi | |
| 152 | 20 | auto RA2 = _mm256_unpackhi_epi32(pack_lo2, pack_hi2); // RRRR_lo RRRR_hi AAAA_lo AAAA_hi | |
| 153 | 20 | auto B = _mm256_unpacklo_epi64(BG1, BG2); | |
| 154 | 20 | _mm256_storeu_si256(reinterpret_cast<__m256i*>(dstp[1] + x * sizeof(pixel_t)), B); // B | |
| 155 | 20 | auto G = _mm256_unpackhi_epi64(BG1, BG2); | |
| 156 | 20 | _mm256_storeu_si256(reinterpret_cast<__m256i*>(dstp[0] + x * sizeof(pixel_t)), G); // G | |
| 157 | 20 | auto R = _mm256_unpacklo_epi64(RA1, RA2); | |
| 158 | 20 | _mm256_storeu_si256(reinterpret_cast<__m256i*>(dstp[2] + x * sizeof(pixel_t)), R); // R | |
| 159 | if (targetHasAlpha) | ||
| 160 | 10 | _mm256_storeu_si256(reinterpret_cast<__m256i*>(dstp[3] + x * sizeof(pixel_t)), max_pixel_value); // A | |
| 161 | } | ||
| 162 | #ifdef SRC_ADDRESS_ADVANCES | ||
| 163 | 20 | srcp += src_pitch; // source packed RGB is upside down | |
| 164 | 20 | dstp[0] -= dst_pitch[0]; | |
| 165 | 20 | dstp[1] -= dst_pitch[1]; | |
| 166 | 20 | dstp[2] -= dst_pitch[2]; | |
| 167 | if (targetHasAlpha) | ||
| 168 | 10 | dstp[3] -= dst_pitch[3]; | |
| 169 | #else | ||
| 170 | srcp -= src_pitch; // source packed RGB is upside down | ||
| 171 | dstp[0] += dst_pitch[0]; | ||
| 172 | dstp[1] += dst_pitch[1]; | ||
| 173 | dstp[2] += dst_pitch[2]; | ||
| 174 | if (targetHasAlpha) | ||
| 175 | dstp[3] += dst_pitch[3]; | ||
| 176 | #endif | ||
| 177 | } | ||
| 178 | #undef SRC_ADDRESS_ADVANCES | ||
| 179 | 4 | } | |
| 180 | |||
| 181 | // Instantiate them | ||
| 182 | template void convert_rgb_to_rgbp_avx2<uint8_t, false>(const BYTE *srcp, BYTE * (&dstp)[4], int src_pitch, int(&dst_pitch)[4], int width, int height); | ||
| 183 | template void convert_rgb_to_rgbp_avx2<uint8_t, true>(const BYTE *srcp, BYTE * (&dstp)[4], int src_pitch, int(&dst_pitch)[4], int width, int height); | ||
| 184 | template void convert_rgb_to_rgbp_avx2<uint16_t, false>(const BYTE *srcp, BYTE * (&dstp)[4], int src_pitch, int(&dst_pitch)[4], int width, int height); | ||
| 185 | template void convert_rgb_to_rgbp_avx2<uint16_t, true>(const BYTE *srcp, BYTE * (&dstp)[4], int src_pitch, int(&dst_pitch)[4], int width, int height); | ||
| 186 | |||
| 187 | template<typename pixel_t, bool targetHasAlpha> | ||
| 188 | 6 | void convert_rgba_to_rgbp_avx2(const BYTE* srcp, BYTE* (&dstp)[4], | |
| 189 | int src_pitch, int(&dst_pitch)[4], int width, int height) | ||
| 190 | { | ||
| 191 | 6 | const int pixels_per_iter = (sizeof(pixel_t) == 1) ? 16 : 8; | |
| 192 | // 8-bit: process 16 pixels per loop (64 bytes in -> four 16-byte stores out) | ||
| 193 | // 16-bit: process 8 pixels per loop (64 bytes in -> four 16-byte stores out) | ||
| 194 | __m128i mask128; | ||
| 195 | if constexpr (sizeof(pixel_t) == 1) | ||
| 196 | 3 | mask128 = _mm_set_epi8(15, 11, 7, 3, 14, 10, 6, 2, 13, 9, 5, 1, 12, 8, 4, 0); | |
| 197 | else | ||
| 198 | 3 | mask128 = _mm_set_epi8(15, 14, 7, 6, 13, 12, 5, 4, 11, 10, 3, 2, 9, 8, 1, 0); | |
| 199 | 6 | __m256i vmask = _mm256_broadcastsi128_si256(mask128); | |
| 200 | // Avisynth's scanline alignment is 64 bytes, so no remainder hanfling is needed for 16 RGB32 or 8 RGB64 pixels | ||
| 201 |
8/8void convert_rgba_to_rgbp_avx2<unsigned char, false>(unsigned char const*, unsigned char* (&) [4], int, int (&) [4], int, int):
✓ Branch 42 → 7 taken 8 times.
✓ Branch 42 → 43 taken 2 times.
void convert_rgba_to_rgbp_avx2<unsigned char, true>(unsigned char const*, unsigned char* (&) [4], int, int (&) [4], int, int):
✓ Branch 43 → 7 taken 5 times.
✓ Branch 43 → 44 taken 1 time.
void convert_rgba_to_rgbp_avx2<unsigned short, false>(unsigned char const*, unsigned char* (&) [4], int, int (&) [4], int, int):
✓ Branch 42 → 7 taken 5 times.
✓ Branch 42 → 43 taken 1 time.
void convert_rgba_to_rgbp_avx2<unsigned short, true>(unsigned char const*, unsigned char* (&) [4], int, int (&) [4], int, int):
✓ Branch 43 → 7 taken 8 times.
✓ Branch 43 → 44 taken 2 times.
|
32 | for (int y = 0; y < height; ++y) { |
| 202 |
8/8void convert_rgba_to_rgbp_avx2<unsigned char, false>(unsigned char const*, unsigned char* (&) [4], int, int (&) [4], int, int):
✓ Branch 40 → 8 taken 13 times.
✓ Branch 40 → 41 taken 8 times.
void convert_rgba_to_rgbp_avx2<unsigned char, true>(unsigned char const*, unsigned char* (&) [4], int, int (&) [4], int, int):
✓ Branch 41 → 8 taken 10 times.
✓ Branch 41 → 42 taken 5 times.
void convert_rgba_to_rgbp_avx2<unsigned short, false>(unsigned char const*, unsigned char* (&) [4], int, int (&) [4], int, int):
✓ Branch 40 → 8 taken 10 times.
✓ Branch 40 → 41 taken 5 times.
void convert_rgba_to_rgbp_avx2<unsigned short, true>(unsigned char const*, unsigned char* (&) [4], int, int (&) [4], int, int):
✓ Branch 41 → 8 taken 13 times.
✓ Branch 41 → 42 taken 8 times.
|
72 | for (int x = 0; x < width; x += pixels_per_iter) { |
| 203 | 46 | __m256i srcA = _mm256_load_si256(reinterpret_cast<const __m256i*>(srcp + x * 4 * sizeof(pixel_t))); | |
| 204 | 92 | __m256i srcB = _mm256_load_si256(reinterpret_cast<const __m256i*>(srcp + (x + pixels_per_iter / 2) * 4 * sizeof(pixel_t))); | |
| 205 | |||
| 206 | 46 | __m256i shufA = _mm256_shuffle_epi8(srcA, vmask); | |
| 207 | 46 | __m256i shufB = _mm256_shuffle_epi8(srcB, vmask); | |
| 208 | |||
| 209 | 46 | __m128i a_lo = _mm256_castsi256_si128(shufA); | |
| 210 | 46 | __m128i a_hi = _mm256_extracti128_si256(shufA, 1); | |
| 211 | 46 | __m128i b_lo = _mm256_castsi256_si128(shufB); | |
| 212 | 46 | __m128i b_hi = _mm256_extracti128_si256(shufB, 1); | |
| 213 | |||
| 214 | 46 | __m128i bg_0 = _mm_unpacklo_epi32(a_lo, a_hi); | |
| 215 | 46 | __m128i ra_0 = _mm_unpackhi_epi32(a_lo, a_hi); | |
| 216 | 46 | __m128i bg_1 = _mm_unpacklo_epi32(b_lo, b_hi); | |
| 217 | 46 | __m128i ra_1 = _mm_unpackhi_epi32(b_lo, b_hi); | |
| 218 | |||
| 219 | 46 | __m128i chB = _mm_unpacklo_epi64(bg_0, bg_1); | |
| 220 | 46 | __m128i chG = _mm_unpackhi_epi64(bg_0, bg_1); | |
| 221 | 46 | __m128i chR = _mm_unpacklo_epi64(ra_0, ra_1); | |
| 222 | 46 | __m128i chA = _mm_unpackhi_epi64(ra_0, ra_1); | |
| 223 | |||
| 224 | 46 | _mm_store_si128(reinterpret_cast<__m128i*>(dstp[1] + x * sizeof(pixel_t)), chB); | |
| 225 | 46 | _mm_store_si128(reinterpret_cast<__m128i*>(dstp[0] + x * sizeof(pixel_t)), chG); | |
| 226 | 46 | _mm_store_si128(reinterpret_cast<__m128i*>(dstp[2] + x * sizeof(pixel_t)), chR); | |
| 227 | if constexpr (targetHasAlpha) | ||
| 228 | 23 | _mm_store_si128(reinterpret_cast<__m128i*>(dstp[3] + x * sizeof(pixel_t)), chA); | |
| 229 | } | ||
| 230 | |||
| 231 | 26 | srcp -= src_pitch; // source packed RGB is upside down | |
| 232 | 26 | dstp[0] += dst_pitch[0]; | |
| 233 | 26 | dstp[1] += dst_pitch[1]; | |
| 234 | 26 | dstp[2] += dst_pitch[2]; | |
| 235 | if constexpr (targetHasAlpha) | ||
| 236 | 13 | dstp[3] += dst_pitch[3]; | |
| 237 | } | ||
| 238 | 6 | } | |
| 239 | |||
| 240 | // Instantiate them | ||
| 241 | template void convert_rgba_to_rgbp_avx2<uint8_t, false>(const BYTE* srcp, BYTE* (&dstp)[4], int src_pitch, int(&dst_pitch)[4], int width, int height); | ||
| 242 | template void convert_rgba_to_rgbp_avx2<uint8_t, true>(const BYTE* srcp, BYTE* (&dstp)[4], int src_pitch, int(&dst_pitch)[4], int width, int height); | ||
| 243 | template void convert_rgba_to_rgbp_avx2<uint16_t, false>(const BYTE* srcp, BYTE* (&dstp)[4], int src_pitch, int(&dst_pitch)[4], int width, int height); | ||
| 244 | template void convert_rgba_to_rgbp_avx2<uint16_t, true>(const BYTE* srcp, BYTE* (&dstp)[4], int src_pitch, int(&dst_pitch)[4], int width, int height); | ||
| 245 | |||
| 246 | // Planar RGB(A) → packed RGBA32/RGBA64 (reverse of convert_rgba_to_rgbp_avx2) | ||
| 247 | // | ||
| 248 | // Main loop: 128 bytes written per iteration | ||
| 249 | // uint8_t: 32 pixels → 4 × _mm256_store_si256 | ||
| 250 | // uint16_t: 16 pixels → 4 × _mm256_store_si256 | ||
| 251 | // Tail: 64 bytes (one half-iteration, uses SSE2 128-bit stores) | ||
| 252 | // uint8_t: 16 pixels → 4 × _mm_store_si128 | ||
| 253 | // uint16_t: 8 pixels → 4 × _mm_store_si128 | ||
| 254 | // | ||
| 255 | // Scanline alignment is 64 bytes (Avisynth guarantee), so aligned SIMD | ||
| 256 | // loads/stores are safe. The tail is handled fully in SIMD, potentially | ||
| 257 | // overreading/overwriting into padded bytes (same strategy as SSE2 path). | ||
| 258 | |||
| 259 | template<typename pixel_t, bool hasSrcAlpha> | ||
| 260 | 5 | void convert_rgbp_to_rgba_avx2(const BYTE* (&srcp)[4], BYTE* dstp, int(&src_pitch)[4], int dst_pitch, int width, int height) | |
| 261 | { | ||
| 262 | // big: pixels processed per 128-byte iteration; small: 64-byte tail size | ||
| 263 | 5 | constexpr int big_pixels = (sizeof(pixel_t) == 1) ? 32 : 16; | |
| 264 | 5 | constexpr int small_pixels = big_pixels / 2; // 16 (u8) or 8 (u16) | |
| 265 | 5 | const int wmod = (width / big_pixels) * big_pixels; | |
| 266 | |||
| 267 | 5 | const __m256i transparent256 = _mm256_set1_epi8((char)0xFF); | |
| 268 | 5 | const __m128i transparent128 = _mm_set1_epi8((char)0xFF); | |
| 269 | |||
| 270 |
8/8void convert_rgbp_to_rgba_avx2<unsigned char, false>(unsigned char const* (&) [4], unsigned char*, int (&) [4], int, int, int):
✓ Branch 70 → 11 taken 8 times.
✓ Branch 70 → 71 taken 2 times.
void convert_rgbp_to_rgba_avx2<unsigned char, true>(unsigned char const* (&) [4], unsigned char*, int (&) [4], int, int, int):
✓ Branch 74 → 11 taken 5 times.
✓ Branch 74 → 75 taken 1 time.
void convert_rgbp_to_rgba_avx2<unsigned short, false>(unsigned char const* (&) [4], unsigned char*, int (&) [4], int, int, int):
✓ Branch 70 → 11 taken 5 times.
✓ Branch 70 → 71 taken 1 time.
void convert_rgbp_to_rgba_avx2<unsigned short, true>(unsigned char const* (&) [4], unsigned char*, int (&) [4], int, int, int):
✓ Branch 74 → 11 taken 5 times.
✓ Branch 74 → 75 taken 1 time.
|
28 | for (int y = 0; y < height; y++) { |
| 271 | // main loop: 128 bytes output per iteration | ||
| 272 |
8/8void convert_rgbp_to_rgba_avx2<unsigned char, false>(unsigned char const* (&) [4], unsigned char*, int (&) [4], int, int, int):
✓ Branch 39 → 12 taken 5 times.
✓ Branch 39 → 40 taken 8 times.
void convert_rgbp_to_rgba_avx2<unsigned char, true>(unsigned char const* (&) [4], unsigned char*, int (&) [4], int, int, int):
✓ Branch 41 → 12 taken 5 times.
✓ Branch 41 → 42 taken 5 times.
void convert_rgbp_to_rgba_avx2<unsigned short, false>(unsigned char const* (&) [4], unsigned char*, int (&) [4], int, int, int):
✓ Branch 39 → 12 taken 5 times.
✓ Branch 39 → 40 taken 5 times.
void convert_rgbp_to_rgba_avx2<unsigned short, true>(unsigned char const* (&) [4], unsigned char*, int (&) [4], int, int, int):
✓ Branch 41 → 12 taken 5 times.
✓ Branch 41 → 42 taken 5 times.
|
43 | for (int x = 0; x < wmod; x += big_pixels) { |
| 273 | 20 | __m256i G = _mm256_load_si256(reinterpret_cast<const __m256i*>(srcp[0] + x * sizeof(pixel_t))); | |
| 274 | 20 | __m256i B = _mm256_load_si256(reinterpret_cast<const __m256i*>(srcp[1] + x * sizeof(pixel_t))); | |
| 275 | 20 | __m256i R = _mm256_load_si256(reinterpret_cast<const __m256i*>(srcp[2] + x * sizeof(pixel_t))); | |
| 276 | __m256i A; | ||
| 277 | if constexpr (hasSrcAlpha) | ||
| 278 | 20 | A = _mm256_load_si256(reinterpret_cast<const __m256i*>(srcp[3] + x * sizeof(pixel_t))); | |
| 279 | else | ||
| 280 | 10 | A = transparent256; | |
| 281 | |||
| 282 | __m256i u0, u1, u2, u3; | ||
| 283 | if constexpr (sizeof(pixel_t) == 1) { | ||
| 284 | 10 | __m256i BG_lo = _mm256_unpacklo_epi8(B, G); | |
| 285 | 10 | __m256i BG_hi = _mm256_unpackhi_epi8(B, G); | |
| 286 | 10 | __m256i RA_lo = _mm256_unpacklo_epi8(R, A); | |
| 287 | 10 | __m256i RA_hi = _mm256_unpackhi_epi8(R, A); | |
| 288 | 10 | u0 = _mm256_unpacklo_epi16(BG_lo, RA_lo); // [px 0-3 | px16-19] | |
| 289 | 10 | u1 = _mm256_unpackhi_epi16(BG_lo, RA_lo); // [px 4-7 | px20-23] | |
| 290 | 10 | u2 = _mm256_unpacklo_epi16(BG_hi, RA_hi); // [px 8-11 | px24-27] | |
| 291 | 10 | u3 = _mm256_unpackhi_epi16(BG_hi, RA_hi); // [px12-15 | px28-31] | |
| 292 | } else { | ||
| 293 | 10 | __m256i BG_lo = _mm256_unpacklo_epi16(B, G); | |
| 294 | 10 | __m256i BG_hi = _mm256_unpackhi_epi16(B, G); | |
| 295 | 10 | __m256i RA_lo = _mm256_unpacklo_epi16(R, A); | |
| 296 | 10 | __m256i RA_hi = _mm256_unpackhi_epi16(R, A); | |
| 297 | 10 | u0 = _mm256_unpacklo_epi32(BG_lo, RA_lo); // [px 0-1 | px 8-9 ] | |
| 298 | 10 | u1 = _mm256_unpackhi_epi32(BG_lo, RA_lo); // [px 2-3 | px10-11] | |
| 299 | 10 | u2 = _mm256_unpacklo_epi32(BG_hi, RA_hi); // [px 4-5 | px12-13] | |
| 300 | 10 | u3 = _mm256_unpackhi_epi32(BG_hi, RA_hi); // [px 6-7 | px14-15] | |
| 301 | } | ||
| 302 | 20 | BYTE* d = dstp + x * 4 * sizeof(pixel_t); | |
| 303 | 20 | _mm256_store_si256(reinterpret_cast<__m256i*>(d + 0), _mm256_permute2x128_si256(u0, u1, 0x20)); | |
| 304 | 20 | _mm256_store_si256(reinterpret_cast<__m256i*>(d + 32), _mm256_permute2x128_si256(u2, u3, 0x20)); | |
| 305 | 20 | _mm256_store_si256(reinterpret_cast<__m256i*>(d + 64), _mm256_permute2x128_si256(u0, u1, 0x31)); | |
| 306 | 20 | _mm256_store_si256(reinterpret_cast<__m256i*>(d + 96), _mm256_permute2x128_si256(u2, u3, 0x31)); | |
| 307 | } | ||
| 308 | |||
| 309 | // tail: process remaining pixels in small SIMD chunks | ||
| 310 | // (may touch padded bytes beyond logical width) | ||
| 311 |
8/8void convert_rgbp_to_rgba_avx2<unsigned char, false>(unsigned char const* (&) [4], unsigned char*, int (&) [4], int, int, int):
✓ Branch 68 → 41 taken 8 times.
✓ Branch 68 → 69 taken 8 times.
void convert_rgbp_to_rgba_avx2<unsigned char, true>(unsigned char const* (&) [4], unsigned char*, int (&) [4], int, int, int):
✓ Branch 72 → 43 taken 5 times.
✓ Branch 72 → 73 taken 5 times.
void convert_rgbp_to_rgba_avx2<unsigned short, false>(unsigned char const* (&) [4], unsigned char*, int (&) [4], int, int, int):
✓ Branch 68 → 41 taken 5 times.
✓ Branch 68 → 69 taken 5 times.
void convert_rgbp_to_rgba_avx2<unsigned short, true>(unsigned char const* (&) [4], unsigned char*, int (&) [4], int, int, int):
✓ Branch 72 → 43 taken 5 times.
✓ Branch 72 → 73 taken 5 times.
|
46 | for (int tx = wmod; tx < width; tx += small_pixels) { |
| 312 | 23 | __m128i tG = _mm_load_si128(reinterpret_cast<const __m128i*>(srcp[0] + tx * sizeof(pixel_t))); | |
| 313 | 23 | __m128i tB = _mm_load_si128(reinterpret_cast<const __m128i*>(srcp[1] + tx * sizeof(pixel_t))); | |
| 314 | 23 | __m128i tR = _mm_load_si128(reinterpret_cast<const __m128i*>(srcp[2] + tx * sizeof(pixel_t))); | |
| 315 | __m128i tA; | ||
| 316 | if constexpr (hasSrcAlpha) | ||
| 317 | 10 | tA = _mm_load_si128(reinterpret_cast<const __m128i*>(srcp[3] + tx * sizeof(pixel_t))); | |
| 318 | else | ||
| 319 | 13 | tA = transparent128; | |
| 320 | |||
| 321 | 23 | BYTE* d = dstp + tx * 4 * sizeof(pixel_t); | |
| 322 | if constexpr (sizeof(pixel_t) == 1) { | ||
| 323 | 13 | __m128i BG_lo = _mm_unpacklo_epi8(tB, tG); | |
| 324 | 13 | __m128i BG_hi = _mm_unpackhi_epi8(tB, tG); | |
| 325 | 13 | __m128i RA_lo = _mm_unpacklo_epi8(tR, tA); | |
| 326 | 13 | __m128i RA_hi = _mm_unpackhi_epi8(tR, tA); | |
| 327 | 13 | _mm_store_si128(reinterpret_cast<__m128i*>(d + 0), _mm_unpacklo_epi16(BG_lo, RA_lo)); // px tx+0..3 | |
| 328 | 13 | _mm_store_si128(reinterpret_cast<__m128i*>(d + 16), _mm_unpackhi_epi16(BG_lo, RA_lo)); // px tx+4..7 | |
| 329 | 13 | _mm_store_si128(reinterpret_cast<__m128i*>(d + 32), _mm_unpacklo_epi16(BG_hi, RA_hi)); // px tx+8..11 | |
| 330 | 13 | _mm_store_si128(reinterpret_cast<__m128i*>(d + 48), _mm_unpackhi_epi16(BG_hi, RA_hi)); // px tx+12..15 | |
| 331 | } else { | ||
| 332 | 10 | __m128i BG_lo = _mm_unpacklo_epi16(tB, tG); | |
| 333 | 10 | __m128i BG_hi = _mm_unpackhi_epi16(tB, tG); | |
| 334 | 10 | __m128i RA_lo = _mm_unpacklo_epi16(tR, tA); | |
| 335 | 10 | __m128i RA_hi = _mm_unpackhi_epi16(tR, tA); | |
| 336 | 10 | _mm_store_si128(reinterpret_cast<__m128i*>(d + 0), _mm_unpacklo_epi32(BG_lo, RA_lo)); // px tx+0..1 | |
| 337 | 10 | _mm_store_si128(reinterpret_cast<__m128i*>(d + 16), _mm_unpackhi_epi32(BG_lo, RA_lo)); // px tx+2..3 | |
| 338 | 10 | _mm_store_si128(reinterpret_cast<__m128i*>(d + 32), _mm_unpacklo_epi32(BG_hi, RA_hi)); // px tx+4..5 | |
| 339 | 10 | _mm_store_si128(reinterpret_cast<__m128i*>(d + 48), _mm_unpackhi_epi32(BG_hi, RA_hi)); // px tx+6..7 | |
| 340 | } | ||
| 341 | } | ||
| 342 | |||
| 343 | 23 | dstp -= dst_pitch; | |
| 344 | 23 | srcp[0] += src_pitch[0]; | |
| 345 | 23 | srcp[1] += src_pitch[1]; | |
| 346 | 23 | srcp[2] += src_pitch[2]; | |
| 347 | if constexpr (hasSrcAlpha) | ||
| 348 | 10 | srcp[3] += src_pitch[3]; | |
| 349 | } | ||
| 350 | 5 | } | |
| 351 | |||
| 352 | // Instantiate them | ||
| 353 | template void convert_rgbp_to_rgba_avx2<uint8_t, false>(const BYTE* (&srcp)[4], BYTE* dstp, int(&src_pitch)[4], int dst_pitch, int width, int height); | ||
| 354 | template void convert_rgbp_to_rgba_avx2<uint8_t, true>(const BYTE* (&srcp)[4], BYTE* dstp, int(&src_pitch)[4], int dst_pitch, int width, int height); | ||
| 355 | template void convert_rgbp_to_rgba_avx2<uint16_t, false>(const BYTE* (&srcp)[4], BYTE* dstp, int(&src_pitch)[4], int dst_pitch, int width, int height); | ||
| 356 | template void convert_rgbp_to_rgba_avx2<uint16_t, true>(const BYTE* (&srcp)[4], BYTE* dstp, int(&src_pitch)[4], int dst_pitch, int width, int height); | ||
| 357 |