2011-12-22 4 views
4

나는 이미지를 posterizing하기위한 함수를 만들었다._m128i를 SSE가있는 부호없는 int로 변환하려면 어떻게해야합니까?

// =(
#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

의 반대를 찾을 수 없습니다?

답변

5

불행히도 AVX (내가 아는 사람은 아님)에서도 그렇게 할 수있는 지침이 없습니다. 그래서 지금 당장 수동으로해야 할 것입니다.

그러나 현재 방법은 매우 차선책이며 .m128i_u8은 MSVC 확장 프로그램입니다. MSVC에 대한 나의 경험을 바탕으로, 개별 요소에 액세스하기 위해 정렬 된 버퍼를 사용할 것입니다. 이것은 부분 단어 접근 때문에 매우 과중한 처벌을받습니다.

.m128i_u8 대신 _mm_extract_epi32()을 사용하십시오. 이것은 SSE4.1에 있습니다. 하지만 이미 SSE4.1에 _mm_cvtepu8_epi32()으로 의존하고 있습니다.

1 바이트 단위로 작업하기 때문에 이러한 상황은 특히 좋지 않습니다. 대신 2 바이트 (16 비트 정수) 단위로 작업하는 경우 shuffle intrinsics을 사용하는 효율적인 솔루션이 있습니다.

+0

_mm_extract_epi32()가 조금 도움이,하지만 당신은 "매우 서브 최적의"무엇을 의미합니까? – bitwise

+0

일반적으로 데이터를 저장 한 후 즉시 다른 단어 크기로 다시 액세스하려고하면 엄청난 벌금이 부과됩니다. 필자가 보았던 'xmm'레지스터의 구성 요소를 추출하는 MSVC의 방법은 메모리에 저장하고 별도로 단어에 액세스하는 것입니다. 그러나 나는이 특별한 경우가 최악의 시나리오가 아니라고 생각한다. – 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()); \t \t UINT color = (UINT) _mm_extract_epi32 (iClr, 0); - 정수 수학을 사용하여 루틴을 다시 작성한 다음 asm으로 변환하여 2048x2048 이미지에 대해 8 ~ 9ms의 최상의 결과를 얻었습니다. – bitwise

+0

@bitwise 이것이 받아 들여진 대답이어야한다고 생각합니다. – Antonio

관련 문제