如何使用SSE将_m128i转换为无符号整型?

How do I convert _m128i to an unsigned int with SSE?

本文关键字:无符号 整型 转换 m128i 何使用 SSE      更新时间:2023-10-16

我编写了一个图像隔色的函数。

// =(
#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个浮点数,但我找不到正确的方法来反向操作。

我搜索了SSE文档,找不到_mm_cvtepu8_epi32的反向

存在吗?

您需要的是_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));

不幸的是,即使在AVX中也没有这样做的指令(据我所知没有)。所以你必须像现在这样手动操作。

然而,你目前的方法是非常次优的,你依赖于.m128i_u8,这是一个MSVC扩展。根据我使用MSVC的经验,它将使用对齐的缓冲区来访问各个元素。由于部分字访问,这有一个非常重的惩罚。

_mm_extract_epi32()代替.m128i_u8。这是在SSE4.1。但你已经依赖于SSE4.1与_mm_cvtepu8_epi32()

这种情况尤其糟糕,因为您使用的是1字节粒度。如果您使用的是2字节(16位整数)粒度,那么有一个使用shuffle intrinsic的有效解决方案。