2011-12-22 94 views
4

我已经制作了一个用于张贴图像的功能。如何将_m128i转换为带有SSE的无符号整数?

// =(
#define ARGB_COLOR(a, r, g, b) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b)) 

inline UINT PosterizeColor(const UINT &color, const float &nColors) 
{ 
    __m128 clr = _mm_cvtepi32_ps( _mm_cvtepu8_epi32((__m128i&)color) ); 

    clr = _mm_mul_ps(clr, _mm_set_ps1(nColors/255.0f) ); 
    clr = _mm_round_ps(clr, _MM_FROUND_TO_NEAREST_INT); 
    clr = _mm_mul_ps(clr, _mm_set_ps1(255.0f/nColors) ); 

    __m128i iClr = _mm_cvttps_epi32(clr); 

    return ARGB_COLOR(iClr.m128i_u8[12], 
         iClr.m128i_u8[8], 
         iClr.m128i_u8[4], 
         iClr.m128i_u8[0]); 
} 
在第一线

,我解开颜色分为4个浮点,但我不能找到合适的方式做相反。

我搜索通过上证所文档,找不到的_mm_cvtepu8_epi32

反向确实存在一个?

回答

5

不幸的是,即使在AVX中也没有这样做的说明(我没有意识到)。所以你必须手动完成,就像现在一样。

但是,您目前的方法是非常不理想的,而您依靠的是.m128i_u8这是一个MSVC扩展。根据我对MSVC的经验,它将使用对齐的缓冲区来访问各个元素。由于部分单词访问,这有非常严重的处罚。

而不是.m128i_u8,请使用_mm_extract_epi32()。这是在SSE4.1中。但是你已经依靠与_mm_cvtepu8_epi32()的SSE4.1。

由于您使用的是1字节的粒度,所以这种情况尤其糟糕。如果您使用的是2字节(16位整数)粒度,则使用shuffle intrinsics有效的解决方案。

+0

_mm_extract_epi32()帮助了一点,但你所说的“非常次优”是什么意思? – bitwise

+0

一般来说,当您存储一些数据,然后立即尝试以不同的字号访问它时,将会有一个巨大的惩罚。从我所看到的,MSVC提取'xmm'寄存器组件的方法就是:存储到内存中,并单独访问这些单词。但我想这个特例并不是最坏的情况。 – Mysticial

+0

好的,无论如何,对于2048x2048它运行在22ms,我认为现在已经足够了。谢谢=) – bitwise

8

_mm_shuffle_epi8_mm_cvtsi128_si32组合是你所需要的:

static const __m128i shuffleMask = _mm_setr_epi8(0, 4, 8, 12, -1, -1, -1, -1, 
               -1, -1, -1, -1, -1, -1, -1, -1); 
UINT color = _mm_cvtsi128_si32(_mm_shuffle_epi8(iClr, shuffleMask)); 
+0

小错误:'_mm_set_epi8'应该是'_mm_setr_epi8'。否则,这实际上工作!我很惊讶,+1。我没有意识到SSSE3有一个字节粒度的洗牌。 – Mysticial

+0

感谢这一点,但我也发现我可以做到这一点,这给了我几乎相同的结果,如上所示: \t \t iClr = _mm_packs_epi32(iClr,_mm_setzero_si128()); \t \t iClr = _mm_packus_epi16(iClr,_mm_setzero_si128()); UINT color =(UINT)_mm_extract_epi32(iClr,0); - 我还使用整数数学重写了例程,然后将其转换为asm,从而为2048x2048图像生成8〜9 ms的最佳结果。 – bitwise

+0

@bitwise我认为这应该是被接受的答案。 – Antonio

相关问题