mirror of
https://github.com/opencv/opencv.git
synced 2026-09-11 04:43:22 -05:00
imgproc: faster bit-exact BGR(A)2GRAY on x86 AVX-512
Use vpmaddwd on BGRA and vpermb+vpmaddwd on BGR; fall back to the universal SIMD kernel.
This commit is contained in:
@@ -746,6 +746,58 @@ struct RGB2Gray<uchar>
|
||||
short cb = coeffs[0], cg = coeffs[1], cr = coeffs[2];
|
||||
int i = 0;
|
||||
|
||||
#if CV_AVX512_SKX
|
||||
// Bit-exact x86 fast paths. BGRA: no channel deinterleave at all - the 4-byte
|
||||
// pixel feeds vpmaddwd directly. BGR (VBMI): vpermb deinterleaves into b/g pairs
|
||||
// + r, then one vpmaddwd (b*cb+g*cg) and one vpmulld (r*cr). Full 15-bit -> maxErr 0.
|
||||
const __m512i vdelta = _mm512_set1_epi32(1 << (shift - 1));
|
||||
// The final block is clamped to [n-16, n) so any remainder is covered by one
|
||||
// overlapping (idempotent) store instead of a scalar tail - no odd-width penalty.
|
||||
if (n >= 16 && scn == 4)
|
||||
{
|
||||
const __m512i coef = _mm512_set1_epi64(((int64_t)cr << 32) | ((int64_t)((uint16_t)cg) << 16) | (uint16_t)cb);
|
||||
const __m512i idxEven = _mm512_setr_epi32(0,2,4,6,8,10,12,14, 16,18,20,22,24,26,28,30);
|
||||
const __m512i idxOdd = _mm512_setr_epi32(1,3,5,7,9,11,13,15, 17,19,21,23,25,27,29,31);
|
||||
auto do16 = [&](int j)
|
||||
{
|
||||
__m512i a = _mm512_madd_epi16(_mm512_cvtepu8_epi16(_mm256_loadu_si256((const __m256i*)(src + (size_t)j*4))), coef);
|
||||
__m512i b = _mm512_madd_epi16(_mm512_cvtepu8_epi16(_mm256_loadu_si256((const __m256i*)(src + (size_t)j*4 + 32))), coef);
|
||||
__m512i bg = _mm512_permutex2var_epi32(a, idxEven, b);
|
||||
__m512i rr = _mm512_permutex2var_epi32(a, idxOdd, b);
|
||||
__m512i y = _mm512_srli_epi32(_mm512_add_epi32(_mm512_add_epi32(bg, rr), vdelta), shift);
|
||||
_mm_storeu_si128((__m128i*)(dst + j), _mm512_cvtusepi32_epi8(y));
|
||||
};
|
||||
for (; i + 16 <= n; i += 16) do16(i);
|
||||
if (i < n) do16(n - 16);
|
||||
return;
|
||||
}
|
||||
#if CV_AVX_512VBMI
|
||||
if (n >= 16 && scn == 3)
|
||||
{
|
||||
static const uint8_t idxb[64] = {
|
||||
0,1, 3,4, 6,7, 9,10, 12,13, 15,16, 18,19, 21,22, 24,25, 27,28, 30,31, 33,34, 36,37, 39,40, 42,43, 45,46,
|
||||
2,5,8,11,14,17,20,23,26,29,32,35,38,41,44,47, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
|
||||
const __m512i vidx = _mm512_loadu_si512(idxb);
|
||||
const __m512i coef_bg = _mm512_set1_epi32(((uint32_t)((uint16_t)cg) << 16) | (uint16_t)cb);
|
||||
const __m512i vcr = _mm512_set1_epi32(cr);
|
||||
auto do16 = [&](int j)
|
||||
{
|
||||
__m512i s = _mm512_maskz_loadu_epi8(0x0000FFFFFFFFFFFFULL, src + (size_t)j*3);
|
||||
__m512i perm = _mm512_permutexvar_epi8(vidx, s);
|
||||
__m256i bg = _mm512_castsi512_si256(perm);
|
||||
__m128i r8 = _mm512_extracti32x4_epi32(perm, 2);
|
||||
__m512i bgs = _mm512_madd_epi16(_mm512_cvtepu8_epi16(bg), coef_bg);
|
||||
__m512i y = _mm512_add_epi32(bgs, _mm512_mullo_epi32(_mm512_cvtepu8_epi32(r8), vcr));
|
||||
y = _mm512_srli_epi32(_mm512_add_epi32(y, vdelta), shift);
|
||||
_mm_storeu_si128((__m128i*)(dst + j), _mm512_cvtusepi32_epi8(y));
|
||||
};
|
||||
for (; i + 16 <= n; i += 16) do16(i);
|
||||
if (i < n) do16(n - 16);
|
||||
return;
|
||||
}
|
||||
#endif // CV_AVX_512VBMI
|
||||
#endif // CV_AVX512_SKX
|
||||
|
||||
#if (CV_SIMD || CV_SIMD_SCALABLE)
|
||||
const int vsize = VTraits<v_uint8>::vlanes();
|
||||
v_int16 bg2y;
|
||||
|
||||
Reference in New Issue
Block a user