我有8位像素数据的一个结构:
struct __attribute__((aligned(4))) pixels {
char r;
char g;
char b;
char a;
}
我想使用SSE指令来计算这些像素(即,Paeth变换)某些事情。 我怎样才能这些像素到SSE寄存器作为32位无符号整数加载?
我有8位像素数据的一个结构:
struct __attribute__((aligned(4))) pixels {
char r;
char g;
char b;
char a;
}
我想使用SSE指令来计算这些像素(即,Paeth变换)某些事情。 我怎样才能这些像素到SSE寄存器作为32位无符号整数加载?
好,使用SSE2整数内在从<emmintrin.h>
首先加载东西进入寄存器的低32位:
__m128i xmm0 = _mm_cvtsi32_si128(*(const int*)&pixel);
然后第一解压缩那些8位值写入16位值的寄存器的低64位,用0交织它们:
xmm0 = _mm_unpacklo_epi8(xmm0, _mm_setzero_si128());
并再次解开这些16位值到32位值:
xmm0 = _mm_unpacklo_epi16(xmm0, _mm_setzero_si128());
您现在应该有各像素为32位的整数的SSE寄存器的各4种成分。
我刚才读,要获得这些值作为32位有符号整数,但我不知道是什么感觉在[-127,127]使得签署像素。 但如果你的像素值确实是负的,用零交织将无法正常工作,因为它使一个负8位数字为正16位数(从而解释你的号码为无符号像素值)。 负数已经与被扩展1
!而非0
S,但不幸的是,将必须由组分基础的成分,在该SSE并不好上动态地决定。
你可以做的是比较消极的价值观和使用所产生的遮光罩(幸好使用1...1
为真, 0...0
假)作为interleavand,而不是零寄存器:
xmm0 = _mm_unpacklo_epi8(xmm0, _mm_cmplt_epi8(xmm0, _mm_setzero_si128()));
xmm0 = _mm_unpacklo_epi16(xmm0, _mm_cmplt_epi16(xmm0, _mm_setzero_si128()));
这将正确地延长负数1
秒和阳性与0
秒。 但是,当然,这额外的开销(在可能需要2-4额外的SSE指令的形式)仅neccessary如果您最初的8位像素值可以永远是负面的,我仍然怀疑。 但如果这是真的话,你应该考虑,而signed char
超过char
,因为后者具有实现定义的符号性(以同样的方式,你应该使用unsigned char
,如果这些都是常见的无符号[0,255]像素值)。
虽然,作为澄清,你不需要签署-8位到32位的转换,但对于完整性哈罗德的缘故曾经为基于SSE2的符号扩展另外一个很不错的主意,而不是使用上述基于比较版。 我们首先解压缩8位值到32位的值,而不是低字节的高字节。 由于我们不关心的下部,我们只是再次使用8位值,这可以让我们从需要额外零寄存器和一个额外的举动:
xmm0 = _mm_unpacklo_epi8(xmm0, xmm0);
xmm0 = _mm_unpacklo_epi16(xmm0, xmm0);
现在我们只需要执行和高位字节到低位字节,它不正确的符号扩展为负值的算术右移:
xmm0 = _mm_srai_epi32(xmm0, 24);
这应该是更多的指令数和注册比我的上述SSE2版本高效。
而且因为它应该比上述零扩展,即使在指令数量相等的单个像素(但分摊到1个时多指令多像素)和多注册有效的(因为没有多余的零寄存器),它甚至可能用于无符号到符号转换如果寄存器是罕见的,但随后用逻辑移位( _mm_srli_epi32
)代替算术移位。
由于哈罗德的评论,甚至有前8至32变换一个更好的选择。 如果你有SSE4支持(SSE4.1要准确),其具有用于执行完全转化从4填充的8位值的寄存器的低32位分成4个32位值在整个寄存器指令,无论是对符号和无符号的8位值:
xmm0 = _mm_cvtepu8_epi32(xmm0); //or _mm_cvtepi8_epi32 for signed 8-bit values
至于扭转这种转变的跟进,首先我们收拾符号的32位整数为16位有符号整数和饱和:
xmm0 = _mm_packs_epi32(xmm0, xmm0);
然后我们包中的16位值形成用饱和无符号的8位值:
xmm0 = _mm_packus_epi16(xmm0, xmm0);
然后,我们终于可以把我们的像素从寄存器的低32位:
*(int*)&pixel = _mm_cvtsi128_si32(xmm0);
由于该饱和度,整个过程将autmatically映射到任何负值0
和大于任何值255
到255
,与彩色像素工作时,其通常意。
如果包装的32位值时回确实需要截断,而不是饱和的unsigned char
s,则你需要这个做自己,因为只有上交所提供饱和包装说明。 但是,这可以通过做一个简单的实现:
xmm0 = _mm_and_si128(xmm0, _mm_set1_epi32(0xFF));
右上面的包装程序之前。 当分摊在多个像素这应达到仅有2额外的SSE指令,或只有1个额外的指令。