2012-10-03 2 views
0

MMX SSE를 동등한 C 코드로 변환 중입니다. 거의 변환했지만 이미지 품질이 올바르지 않거나 이미지에 약간의 노이즈가 있음을 알 수 있습니다. 나는 지난 5 일 동안 코드를 디버깅하고 있지만 왜 일어나는지 알지 못합니다. 너희들이이 문제를 조사하고 나를 도와 주면 매우 행복해 할 것이다.MMX SSE에서 C 코드로 변환 할 때 이미지 품질이 저하됩니다.

ORIGINAL SSE 코드 :

void unpack_8bit_to_16bit(__m128i *a, __m128i* b0, __m128i* b1) 
{ 
    __m128i zero = _mm_setzero_si128(); 
    b0 = _mm_unpacklo_epi8(a, zero); 
    b1 = _mm_unpackhi_epi8(a, zero); 
} 

void convolve_cols_3x3(const unsigned char* in, int16_t* out_v, int16_t* out_h, int w, int h) 
{ 
    using namespace std; 
    assert(w % 16 == 0 && "width must be multiple of 16!"); 
    const int w_chunk = w/16; 
    __m128i* i0  = (__m128i*)(in); 
    __m128i* i1  = (__m128i*)(in) + w_chunk*1; 
    __m128i* i2  = (__m128i*)(in) + w_chunk*2; 
    __m128i* result_h = (__m128i*)(out_h) + 2*w_chunk; 
    __m128i* result_v = (__m128i*)(out_v) + 2*w_chunk; 
    __m128i* end_input = (__m128i*)(in) + w_chunk*h; 

    for(; i2 != end_input; i0++, i1++, i2++, result_v+=2, result_h+=2) 
    { 
     *result_h  = _mm_setzero_si128(); 
     *(result_h+1) = _mm_setzero_si128(); 
     *result_v  = _mm_setzero_si128(); 
     *(result_v+1) = _mm_setzero_si128(); 
     __m128i ilo, ihi; 
     unpack_8bit_to_16bit(*i0, ihi, ilo); 
     *result_h  = _mm_add_epi16(ihi, *result_h); 
     *(result_h+1) = _mm_add_epi16(ilo, *(result_h+1)); 
     *result_v  = _mm_add_epi16(*result_v, ihi); 
     *(result_v+1) = _mm_add_epi16(*(result_v+1), ilo); 
     unpack_8bit_to_16bit(*i1, ihi, ilo); 
     *result_v  = _mm_add_epi16(*result_v, ihi); 
     *(result_v+1) = _mm_add_epi16(*(result_v+1), ilo); 
     *result_v  = _mm_add_epi16(*result_v, ihi); 
     *(result_v+1) = _mm_add_epi16(*(result_v+1), ilo); 
     unpack_8bit_to_16bit(*i2, ihi, ilo); 
     *result_h  = _mm_sub_epi16(*result_h, ihi); 
     *(result_h+1) = _mm_sub_epi16(*(result_h+1), ilo); 
     *result_v  = _mm_add_epi16(*result_v, ihi); 
     *(result_v+1) = _mm_add_epi16(*(result_v+1), ilo); 
    } 
} 

코드가 읽을 수없는 경우 내가

void convolve_cols_3x3(const unsigned char* in, int16_t* out_v, int16_t* out_h, int w, int h) 
{ 
    using namespace std; 
    assert(w % 16 == 0 && "width must be multiple of 16!"); 
    const int w_chunk = w/16; 

    uint8_t* i0  = (uint8_t*)(in); 
    uint8_t* i1  = (uint8_t*)(in) + w_chunk*1*16; 
    uint8_t* i2  = (uint8_t*)(in) + w_chunk*2*16; 
    int16_t* result_h = (int16_t*)(out_h) + 2*w_chunk*16; 
    int16_t* result_v = (int16_t*)(out_v) + 2*w_chunk*16; 
    uint8_t* end_input = (uint8_t*)(in) + w_chunk*h*16; 
    for(; i2 != end_input; i0+= 16, i1+= 16, i2+= 16, result_v+= 16, result_h+= 16) 
    { 
     for (int i=0; i<8;i++) 
     { 
      result_h[i]  = 0; 
      result_h[i + 8] = 0; 
      result_v[i]  = 0; 
      result_v[i + 8] = 0; 
      result_h[i]  = (int16_t)(i0[i]) + result_h[i] ; 
      result_h[i + 8] = (int16_t)(i0[i + 8]) + result_h[i + 8] ; 
      result_v[i]  = (int16_t)(i0[i]) + result_v[i] ; 
      result_v[i + 8] = (int16_t)(i0[i + 8]) + result_v[i + 8] ; 
      result_v[i]  = (int16_t)(i1[i]) + result_v[i] ; 
      result_v[i + 8] = (int16_t)(i1[i + 8]) + result_v[i + 8] ; 
      result_v[i]  = (int16_t)(i1[i]) + result_v[i] ; 
      result_v[i + 8] = (int16_t)(i1[i + 8]) + result_v[i + 8] ; 
      result_h[i]  = result_h[i] - (int16_t)(i2[i]); 
      result_h[i + 8] = result_h[i + 8] - (int16_t)(i2[i + 8]); 
      result_v[i]  = (int16_t)(i2[i]) + result_v[i] ; 
      result_v[i + 8] = (int16_t)(i2[i + 8]) + result_v[i + 8] ; 
     } 
    } 
} 

죄송합니다 아래에 주어진 변환 된 코드입니다. wh은 너비와 높이를 나타냅니다. out_hout_v은 나중에 다른 용도로 사용되는 두 개의 매개 변수입니다.

+0

적어도 하나 SSE 코드에 버그가있는 것 같습니다 : 당신은 또한 이전에 16 비트 정수를 읽을 필요가있는 경우 최종 수정 된 코드는 다음과 같을 수 사용되기 전에. 또는'unpack_8bit_to_16bit' 줄을 실수로 삭제 했습니까? –

+0

@paul :: ihi 및 ilo는 unpack_8bit_to_16bit (---) 함수에 대한 참조로 전달되므로 원본 sse 코드에서 초기화됩니다. 변환 된 코드에서는 함수 호출을 최소화하기 위해 i0, i1 및 i2를 직접 사용했습니다 ... – user1717323

+0

코드를 다시 살펴보십시오. 특히이 두 줄은 :'__m128i ilo, ihi; * result_h = _mm_add_epi16 (ihi, * result_h); ' –

답변

0

버그가 포인터 계산 및 소스 데이터 읽기에있는 것 같습니다. 포인터 변수 i0, i1, i2는 부호없는 char입니다. 코드에서이 같은 라인 :

result_h[i + 8] = (int16_t)(i0[i + 8]) + result_h[i + 8] ; 

이를해야합니다

result_h[i + 8] = (int16_t)(i0[i*2 + 16]) + result_h[i + 8] ; 

int16_t에 대한 캐스트는 I0의 대괄호 내의 오프셋 (offset)에 영향을주지 않습니다. 16 바이트 구조 (__m128i)로 작업하지만 8 바이트 오프셋으로 액세스합니다. 또한 i0과 i1이 가리키는 정수 중 하위 8 비트 만 사용합니다. 원래 SSE 코드에서는 16 비트 정수를 읽습니다. 초기화되지 않은 ihi```ilo`과 :

result_h[i + 8] = *(int16_t *)(&i0[i*2 + 16]) + result_h[i + 8]; 
+0

@ user1717323 - 내 솔루션을 사용해 보셨습니까? – BitBank

+0

노크 - 누구 집? – BitBank

관련 문제