AVX2 缩小转换,从 uint16_t 到 uint8_t

问题描述 投票:0回答:1

我想使用 AVX2 将 2d 数组从 16 位缩小到 8 位。有效的C++代码如下:

  auto * s = reinterpret_cast<uint16_t *>(i_frame.Y);
  auto * d = narrowed.data();

  for (auto y = 0; y < i_frame.Height; y++, s += i_frame.Pitch_Luma / 2, d += o_frame.Width)
  {
      for (auto x = 0; x < i_frame.Width; x++)
      {
          d[x] = static_cast<uint8_t>(s[x]);
      }
  }

然后我想也许使用 AVX2 会更有效(我们所有的系统都有 AVX2 支持):

 auto * s = reinterpret_cast<uint16_t *>(i_frame.Y);
 auto * d = narrowed.data();

 for (auto y = 0; y < i_frame.Height; ++y, s += i_frame.Pitch_Luma / 2, d += o_frame.Width)
 {
     for (auto x = 0; x < i_frame.Width; x += 16)
     {
         auto src = _mm256_load_si256(reinterpret_cast<const __m256i *>(s + x));            
         auto v = _mm256_packus_epi16(src, _mm256_setzero_si256());

         v = _mm256_permute4x64_epi64(v, _MM_SHUFFLE(3, 1, 2, 0));

         _mm_store_si128(reinterpret_cast<__m128i *>(d + x), _mm256_extracti128_si256(v, 0));
     }
 }

问题是我的 AVX2 转换代码是否是最佳的和/或正确的方法。我可能缺少一个 AVX2 命令,该命令使这变得非常简单。至少我支持扩大转变。

avx2 narrowing
1个回答
0
投票

vpackuswb
vpermq
对此很好,但您可以安排一些事情,以便使用相同的说明完成双倍的工作:

for (size_t x = 0; x < width; x += 32)
{
    auto src1 = _mm256_load_si256(reinterpret_cast<const __m256i *>(s + x));
    auto src2 = _mm256_load_si256(reinterpret_cast<const __m256i *>(s + x + 16));
    auto v = _mm256_packus_epi16(src1, src2);

    v = _mm256_permute4x64_epi64(v, _MM_SHUFFLE(3, 1, 2, 0));

    _mm256_store_si256(reinterpret_cast<__m256i *>(d + x), v);
}

这可能不是一个完全的替代品,因为展开因子发生了变化,因此这可能需要在图像边缘附近额外小心。如果目标仅 16 对齐(或者如果可能的话增加对齐),您可能还需要未对齐的存储。

© www.soinside.com 2019 - 2024. All rights reserved.