sve*_*evs 1 c++ intrinsics avx avx2
我在使用 AVX2 进行图像转换时看到了这个很棒的答案__m128i,并且认为我会尝试使用 AVX2 来看看是否可以更快地获得它。该任务是获取输入 RGB 图像并将其转换为 RGBA(注意另一个问题是 BGRA,但这并不是一个很大的区别......)。
如果需要,我可以包含更多代码,但是这些东西变得非常冗长,而且我陷入了看似非常简单的事情。假设对于此代码,所有内容都是 32 字节对齐、使用-mavx2等进行编译。
给定输入uint8_t *sourceRGB 和输出uint8_t *destinationRGBA,它会像这样(只是尝试用条纹填充图像的四分之一 [因为这是矢量土地])。
#include <immintrin.h>
__m256i *src = (__m256i *) source;
__m256i *dest = (__m256i *) destination;
// for this particular image
unsigned width = 640;
unsigned height = 480;
unsigned unroll_N = (width * height) / 32;
for(unsigned idx = 0; idx < unroll_N; ++idx) {
// Load first portion and fill all of dest[0]
__m256i src_0 = src[0];
__m256i tmp_0 = _mm256_shuffle_epi8(src_0,
_mm256_set_epi8(
0x80, 23, 22, 21,// A07 B07 G07 R07
0x80, 20, 19, 18,// A06 B06 G06 R06
0x80, 17, 16, 15,// A05 B05 G05 R05
0x80, 14, 13, 12,// A04 B04 G04 R04
0x80, 11, 10, 9,// A03 B03 G03 R03
0x80, 8, 7, 6,// A02 B02 G02 R02
0x80, 5, 4, 3,// A01 B01 G01 R01
0x80, 2, 1, 0 // A00 B00 G00 R00
)
);
dest[0] = tmp_0;
// move the input / output pointers forward
src += 3;
dest += 4;
}// end for
Run Code Online (Sandbox Code Playgroud)
这实际上根本不起作用。每个“季度”都会出现条纹。
0x80应该用于0x00在蒙版中
创建OR像0xff链接的答案一样)。04它似乎与行有关07,如果我让它们全部0x80离开00-03不一致就会消失。
我在这里缺少什么?就像我可能用完了寄存器之类的吗?我会对此感到非常惊讶...
使用
_mm256_set_epi8(
// 0x80, 23, 22, 21,// A07 B07 G07 R07
// 0x80, 20, 19, 18,// A06 B06 G06 R06
// 0x80, 17, 16, 15,// A05 B05 G05 R05
// 0x80, 14, 13, 12,// A04 B04 G04 R04
0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80,
0x80, 11, 10, 9,// A03 B03 G03 R03
0x80, 8, 7, 6,// A02 B02 G02 R02
0x80, 5, 4, 3,// A01 B01 G01 R01
0x80, 2, 1, 0 // A00 B00 G00 R00
)
Run Code Online (Sandbox Code Playgroud)
_mm256_shuffle_epi8工作方式类似于并排两次_mm_shuffle_epi8,而不是像更有用(但可能更高延迟)的全角随机播放,可以将任何字节放在任何地方。这是来自www.officedaytime.com/simd512e的图表:
AVX512VBMI 具有新的字节粒度混洗,例如vpermb可以跨通道的混洗,但当前处理器尚不支持该指令集扩展。