我正在根据pixman描述的算法在by Intel [pdf]中实现快速的x888-> 565像素转换功能。他们的代码将x888-> 555转换为我想转换为565的代码。不幸的是,转换为565意味着高位被设置,这意味着我不能使用有符号饱和包指令。直到SSE4.1才添加未签名的打包指令packusdw。我想用SSE2实现其功能或找到另一种方法。
此函数需要两个XMM寄存器,每个寄存器包含4个32位像素,并输出一个包含8个转换后的RGB565像素的XMM寄存器。
static force_inline __m128i
pack_565_2packedx128_128 (__m128i lo, __m128i hi)
{
__m128i rb0 = _mm_and_si128 (lo, mask_565_rb);
__m128i rb1 = _mm_and_si128 (hi, mask_565_rb);
__m128i t0 = _mm_madd_epi16 (rb0, mask_565_pack_multiplier);
__m128i t1 = _mm_madd_epi16 (rb1, mask_565_pack_multiplier);
__m128i g0 = _mm_and_si128 (lo, mask_green);
__m128i g1 = _mm_and_si128 (hi, mask_green);
t0 = _mm_or_si128 (t0, g0);
t1 = _mm_or_si128 (t1, g1);
t0 = _mm_srli_epi32 (t0, 5);
t1 = _mm_srli_epi32 (t1, 5);
/* XXX: maybe there's a way to do this relatively efficiently with SSE2? */
return _mm_packus_epi32 (t0, t1);
}
我想到的想法:
减去0x8000,_mm_packs_epi32,将0x8000重新添加到每个565像素。我已经尝试过了,但是无法完成这项工作。
t0 = _mm_sub_epi16 (t0, mask_8000);
t1 = _mm_sub_epi16 (t1, mask_8000);
t0 = _mm_packs_epi32 (t0, t1);
return _mm_add_epi16 (t0, mask_8000);
随机播放数据而不是打包数据。适用于MMX,但由于SSE 16位混洗仅适用于高或低64位,因此会变得混乱。
保存高位,将它们设置为零,打包,然后恢复它们。似乎很混乱。
我还有其他方法(希望更有效)吗?
最佳答案
您可以先签名扩展值,然后使用_mm_packs_epi32
:
t0 = _mm_slli_epi32 (t0, 16);
t0 = _mm_srai_epi32 (t0, 16);
t1 = _mm_slli_epi32 (t1, 16);
t1 = _mm_srai_epi32 (t1, 16);
t0 = _mm_packs_epi32 (t0, t1);
您实际上可以将其与以前的班次结合起来以保存两条指令:
t0 = _mm_slli_epi32 (t0, 16 - 5);
t0 = _mm_srai_epi32 (t0, 16);
t1 = _mm_slli_epi32 (t1, 16 - 5);
t1 = _mm_srai_epi32 (t1, 16);
t0 = _mm_packs_epi32 (t0, t1);
关于x86 - 使用SSE2模拟packusdw功能,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/11024652/