此问题与之前回答的问题有关: Fast 24-bit array -> 32-bit array conversion? 在一个答案中,interjay友情地发布了用于转换RGB24的SSE3代码 - > RGB32,但我还需要反向转换(RGB32 - > RGB24)。我给了它一个镜头(见下文),我的代码肯定有效,但它比interjay的代码更复杂,而且明显更慢。我无法看到如何完全颠倒指令:_mm_alignr_epi8在这种情况下似乎没有用,但我并不像我应该那样熟悉SSE3。不对称是不可避免的,还是有更快的替代变化和ORing?
RGB32 - > RGB24:
__m128i *src = ...
__m128i *dst = ...
__m128i mask = _mm_setr_epi8(0,1,2,4, 5,6,8,9, 10,12,13,14, -1,-1,-1,-1);
for (UINT i = 0; i < Pixels; i += 16) {
__m128i sa = _mm_shuffle_epi8(_mm_load_si128(src), mask);
__m128i sb = _mm_shuffle_epi8(_mm_load_si128(src + 1), mask);
__m128i sc = _mm_shuffle_epi8(_mm_load_si128(src + 2), mask);
__m128i sd = _mm_shuffle_epi8(_mm_load_si128(src + 3), mask);
_mm_store_si128(dst, _mm_or_si128(sa, _mm_slli_si128(sb, 12)));
_mm_store_si128(dst + 1, _mm_or_si128(_mm_srli_si128(sb, 4), _mm_slli_si128(sc, 8)));
_mm_store_si128(dst + 2, _mm_or_si128(_mm_srli_si128(sc, 8), _mm_slli_si128(sd, 4)));
src += 4;
dst += 3;
}
RGB24 - &gt; RGB32(礼貌的interjay):
__m128i *src = ...
__m128i *dst = ...
__m128i mask = _mm_setr_epi8(0,1,2,-1, 3,4,5,-1, 6,7,8,-1, 9,10,11,-1);
for (UINT i = 0; i < Pixels; i += 16) {
__m128i sa = _mm_load_si128(src);
__m128i sb = _mm_load_si128(src + 1);
__m128i sc = _mm_load_si128(src + 2);
__m128i val = _mm_shuffle_epi8(sa, mask);
_mm_store_si128(dst, val);
val = _mm_shuffle_epi8(_mm_alignr_epi8(sb, sa, 12), mask);
_mm_store_si128(dst + 1, val);
val = _mm_shuffle_epi8(_mm_alignr_epi8(sc, sb, 8), mask);
_mm_store_si128(dst + 2, val);
val = _mm_shuffle_epi8(_mm_alignr_epi8(sc, sc, 4), mask);
_mm_store_si128(dst + 3, val);
src += 3;
dst += 4;
}
答案 0 :(得分:0)
您可以使用this answer并将随机播放掩码更改为RGB32到RGB24。
最大的区别是直接计算shuffle并使用按位运算来避免移位。此外,使用对齐的流式写入而不是对齐的写入不会污染缓存。
答案 1 :(得分:0)
老问题,但我试图解决同样的问题......
如果右对齐第二个操作数,可以使用palignr,即将低位字节置为零。您需要第二个,第三个和第四个单词的左对齐版本,以及第一个,第二个和第三个单词的右对齐版本。
对于第二个和第三个词,如果我使用移位来计算左对齐版本的右对齐版本,GCC会稍微高兴一些。如果我使用两个不同的pshufb,它会产生3个不必要的动作。
这是代码。它恰好使用8个寄存器;如果您处于64位模式,可以尝试将其展开两次。
__m128i mask_right = _mm_set_epi8(14, 13, 12, 10, 9, 8, 6, 5, 4, 2, 1, 0, 0x80, 0x80, 0x80, 0x80);
__m128i mask = _mm_set_epi8(0x80, 0x80, 0x80, 0x80, 14, 13, 12, 10, 9, 8, 6, 5, 4, 2, 1, 0);
for (; n; n -= 16, d += 48, s += 64) {
__m128i v0 = _mm_load_si128((__m128i *) &s[0]);
__m128i v1 = _mm_load_si128((__m128i *) &s[16]);
__m128i v2 = _mm_load_si128((__m128i *) &s[32]);
__m128i v3 = _mm_load_si128((__m128i *) &s[48]);
v0 = _mm_shuffle_epi8(v0, mask_right);
v1 = _mm_shuffle_epi8(v1, mask);
v2 = _mm_shuffle_epi8(v2, mask);
v3 = _mm_shuffle_epi8(v3, mask);
v0 = _mm_alignr_epi8(v1, v0, 4);
v1 = _mm_slli_si128(v1, 4); // mask -> mask_right
v1 = _mm_alignr_epi8(v2, v1, 8);
v2 = _mm_slli_si128(v2, 4); // mask -> mask_right
v2 = _mm_alignr_epi8(v3, v2, 12);
_mm_store_si128((__m128i *) &d[0], v0);
_mm_store_si128((__m128i *) &d[16], v1);
_mm_store_si128((__m128i *) &d[32], v2);
}
中心部分也可能是这样写的。编译器产生的指令少一些,看起来它有更多的并行性,但是需要基准测试来给出正确的答案:
v0 = _mm_shuffle_epi8(v0, mask_right);
v1 = _mm_shuffle_epi8(v1, mask);
v2 = _mm_shuffle_epi8(v2, mask_right);
v3 = _mm_shuffle_epi8(v3, mask);
__m128i v2l = v2;
v0 = _mm_alignr_epi8(v1, v0, 4);
v1 = _mm_slli_si128(v1, 4); // mask -> mask_right
v2 = _mm_alignr_epi8(v3, v2, 12);
v2l = _mm_srli_si128(v2l, 4); // mask_right -> mask
v1 = _mm_alignr_epi8(v2l, v1, 8);