_mm256_shuffle_epi 意外 __256i 向量
unexpected _mm256_shuffle_epi with __256i vectors
我已经看到 this great answer 使用 __m128i
进行图像转换,我想我会尝试使用 AVX2 看看我是否可以更快地获得它。任务是获取输入的 RGB 图像并将其转换为 RGBA(注意另一个问题是 BGRA,但这并没有太大的区别...)。
如果需要,我可以包含更多代码,但是这些东西变得非常冗长,我被困在看似非常简单的事情上。假设对于这段代码,所有内容都是 32 字节对齐的,使用 -mavx2
编译,等等
给定输入 uint8_t *source
RGB 和输出 uint8_t *destination
RGBA,它是这样的(只是试图用条纹填充图像的四分之一 [因为这是矢量土地])。
#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
这根本行不通。每个 "quarter".
中都出现了条纹
- 我的理解是
0x80
应该用来在掩码中创建0x00
- 那里的值是什么并不重要(它是 alpha 通道,在实际代码中它得到
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
)
_mm256_shuffle_epi8
的工作方式类似于并排 _mm_shuffle_epi8
的两倍,而不是更有用(但可能延迟更高)的全角洗牌,可以将任何字节放在任何地方。这是来自 www.officedaytime.com/simd512e 的图表:
AVX512VBMI 具有新的字节粒度洗牌,例如 vpermb
可以跨通道,但当前的处理器尚不支持该指令集扩展。
我已经看到 this great answer 使用 __m128i
进行图像转换,我想我会尝试使用 AVX2 看看我是否可以更快地获得它。任务是获取输入的 RGB 图像并将其转换为 RGBA(注意另一个问题是 BGRA,但这并没有太大的区别...)。
如果需要,我可以包含更多代码,但是这些东西变得非常冗长,我被困在看似非常简单的事情上。假设对于这段代码,所有内容都是 32 字节对齐的,使用 -mavx2
编译,等等
给定输入 uint8_t *source
RGB 和输出 uint8_t *destination
RGBA,它是这样的(只是试图用条纹填充图像的四分之一 [因为这是矢量土地])。
#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
这根本行不通。每个 "quarter".
中都出现了条纹- 我的理解是
0x80
应该用来在掩码中创建0x00
- 那里的值是什么并不重要(它是 alpha 通道,在实际代码中它得到
OR
和0xff
,就像链接的答案一样)。
- 那里的值是什么并不重要(它是 alpha 通道,在实际代码中它得到
- 它似乎与
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
)
_mm256_shuffle_epi8
的工作方式类似于并排 _mm_shuffle_epi8
的两倍,而不是更有用(但可能延迟更高)的全角洗牌,可以将任何字节放在任何地方。这是来自 www.officedaytime.com/simd512e 的图表:
AVX512VBMI 具有新的字节粒度洗牌,例如 vpermb
可以跨通道,但当前的处理器尚不支持该指令集扩展。