convert/intel/convert_rgb_avx512.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/config.h> | ||
| 36 | #include <avs/types.h> | ||
| 37 | #include <cstdint> | ||
| 38 | |||
| 39 | #include "../../filters/intel/check_avx512.h" // compiler avx512 directives check | ||
| 40 | #include "convert_rgb_avx512.h" | ||
| 41 | |||
| 42 | #include <immintrin.h> // Includes AVX-512 intrinsics | ||
| 43 | |||
| 44 | template<typename pixel_t, bool targetHasAlpha> | ||
| 45 | ✗ | void convert_rgba_to_rgbp_avx512vbmi(const BYTE *srcp, BYTE * (&dstp)[4], | |
| 46 | int src_pitch, int (&dst_pitch)[4], int width, int height) | ||
| 47 | { | ||
| 48 | // 8-bit: 16 BGRA8 pixels = 64 bytes fits in one ZMM | ||
| 49 | // 16-bit: 8 BGRA16 pixels = 64 bytes fits in one ZMM | ||
| 50 | ✗ | const int pixels_at_a_time = (sizeof(pixel_t) == 1) ? 16 : 8; | |
| 51 | |||
| 52 | // Build the vpermb index vector, constant, computed once | ||
| 53 | __m512i perm; | ||
| 54 | if constexpr (sizeof(pixel_t) == 1) { | ||
| 55 | // B channel: bytes 0,4,8,...,60 (stride 4, offset 0) | ||
| 56 | // G channel: bytes 1,5,9,...,61 (stride 4, offset 1) | ||
| 57 | // R channel: bytes 2,6,10,...,62 (stride 4, offset 2) | ||
| 58 | // A channel: bytes 3,7,11,...,63 (stride 4, offset 3) | ||
| 59 | alignas(64) uint8_t idx[64]; | ||
| 60 | ✗ | for (int i = 0; i < 16; i++) idx[i] = i * 4 + 0; // B | |
| 61 | ✗ | for (int i = 0; i < 16; i++) idx[16+i] = i * 4 + 1; // G | |
| 62 | ✗ | for (int i = 0; i < 16; i++) idx[32+i] = i * 4 + 2; // R | |
| 63 | ✗ | for (int i = 0; i < 16; i++) idx[48+i] = i * 4 + 3; // A | |
| 64 | ✗ | perm = _mm512_load_si512(reinterpret_cast<const __m512i *>(idx)); | |
| 65 | } | ||
| 66 | else { | ||
| 67 | alignas(64) uint8_t idx[64]; | ||
| 68 | ✗ | for (int i = 0; i < 8; i++) { | |
| 69 | ✗ | idx[i * 2 + 0] = (uint8_t)(i * 8 + 0); // B low byte | |
| 70 | ✗ | idx[i * 2 + 1] = (uint8_t)(i * 8 + 1); // B high byte | |
| 71 | ✗ | idx[16 + i * 2 + 0] = (uint8_t)(i * 8 + 2); // G low byte | |
| 72 | ✗ | idx[16 + i * 2 + 1] = (uint8_t)(i * 8 + 3); // G high byte | |
| 73 | ✗ | idx[32 + i * 2 + 0] = (uint8_t)(i * 8 + 4); // R low byte | |
| 74 | ✗ | idx[32 + i * 2 + 1] = (uint8_t)(i * 8 + 5); // R high byte | |
| 75 | ✗ | idx[48 + i * 2 + 0] = (uint8_t)(i * 8 + 6); // A low byte | |
| 76 | ✗ | idx[48 + i * 2 + 1] = (uint8_t)(i * 8 + 7); // A high byte | |
| 77 | } | ||
| 78 | ✗ | perm = _mm512_load_si512(reinterpret_cast<const __m512i*>(idx)); | |
| 79 | } | ||
| 80 | |||
| 81 | // No remainder: BGRA source is 4 bytes/pixel, 64-byte aligned scanlines guarantee width is a multiple of 16 (8-bit) or 8 (16-bit) | ||
| 82 | ✗ | for (int y = height; y > 0; --y) { | |
| 83 | ✗ | for (int x = 0; x < width; x += pixels_at_a_time) { | |
| 84 | ✗ | __m512i src = _mm512_load_si512( | |
| 85 | ✗ | reinterpret_cast<const __m512i *>(srcp + x * 4 * sizeof(pixel_t))); | |
| 86 | |||
| 87 | // 64-byte cross-lane permutation | ||
| 88 | // Result layout: | ||
| 89 | // bytes 0-15: B0..B15 (8-bit) or B0..B7 as pairs (16-bit) | ||
| 90 | // bytes 16-31: G channel | ||
| 91 | // bytes 32-47: R channel | ||
| 92 | // bytes 48-63: A channel | ||
| 93 | ✗ | __m512i result = _mm512_permutexvar_epi8(perm, src); | |
| 94 | |||
| 95 | // Extract each 128-bit quarter and store | ||
| 96 | // _mm512_extracti32x4_epi32: extract 128-bit lane 0,1,2,3 | ||
| 97 | ✗ | __m128i B = _mm512_extracti32x4_epi32(result, 0); | |
| 98 | ✗ | __m128i G = _mm512_extracti32x4_epi32(result, 1); | |
| 99 | ✗ | __m128i R = _mm512_extracti32x4_epi32(result, 2); | |
| 100 | ✗ | __m128i A = _mm512_extracti32x4_epi32(result, 3); | |
| 101 | |||
| 102 | ✗ | _mm_store_si128(reinterpret_cast<__m128i *>(dstp[1] + x * sizeof(pixel_t)), B); | |
| 103 | ✗ | _mm_store_si128(reinterpret_cast<__m128i *>(dstp[0] + x * sizeof(pixel_t)), G); | |
| 104 | ✗ | _mm_store_si128(reinterpret_cast<__m128i *>(dstp[2] + x * sizeof(pixel_t)), R); | |
| 105 | if constexpr (targetHasAlpha) | ||
| 106 | ✗ | _mm_store_si128(reinterpret_cast<__m128i *>(dstp[3] + x * sizeof(pixel_t)), A); | |
| 107 | } | ||
| 108 | |||
| 109 | |||
| 110 | ✗ | srcp -= src_pitch; | |
| 111 | ✗ | dstp[0] += dst_pitch[0]; | |
| 112 | ✗ | dstp[1] += dst_pitch[1]; | |
| 113 | ✗ | dstp[2] += dst_pitch[2]; | |
| 114 | if constexpr (targetHasAlpha) | ||
| 115 | ✗ | dstp[3] += dst_pitch[3]; | |
| 116 | } | ||
| 117 | ✗ | } | |
| 118 | |||
| 119 | // Instantiations | ||
| 120 | template void convert_rgba_to_rgbp_avx512vbmi<uint8_t, false>(const BYTE* srcp, BYTE* (&dstp)[4], int src_pitch, int(&dst_pitch)[4], int width, int height); | ||
| 121 | template void convert_rgba_to_rgbp_avx512vbmi<uint8_t, true>(const BYTE* srcp, BYTE* (&dstp)[4], int src_pitch, int(&dst_pitch)[4], int width, int height); | ||
| 122 | template void convert_rgba_to_rgbp_avx512vbmi<uint16_t, false>(const BYTE* srcp, BYTE* (&dstp)[4], int src_pitch, int(&dst_pitch)[4], int width, int height); | ||
| 123 | template void convert_rgba_to_rgbp_avx512vbmi<uint16_t, true>(const BYTE* srcp, BYTE* (&dstp)[4], int src_pitch, int(&dst_pitch)[4], int width, int height); | ||
| 124 |