made countNonZero SSE code SSE2-compliant and portable

This commit is contained in:
Vadim Pisarevsky 2012-07-30 16:02:49 +04:00
parent 72a4f1924d
commit b9d7c712f5

View File

@ -221,39 +221,42 @@ static int countNonZero_(const T* src, int len )
return nz; return nz;
} }
template <> static int countNonZero8u( const uchar* src, int len )
int countNonZero_ <uchar> (const uchar* src, int len)
{ {
int i=0, nz = 0; int i=0, nz = 0;
#if (defined CV_SSE4_2 && CV_SSE4_2 && (_WIN64 || __amd64__)) #if CV_SSE2
if(USE_SSE4_2)//5x-6x if(USE_SSE2)//5x-6x
{ {
__m128i pattern = _mm_setzero_si128 (); __m128i pattern = _mm_setzero_si128 ();
__m128i inv = _mm_set1_epi8((char)1); static uchar tab[256];
__int64 CV_DECL_ALIGNED(16) buf[2]; static volatile bool initialized = false;
for (; i<=len-16; i+=16) if( !initialized )
{ {
__m128i r0 = _mm_lddqu_si128((const __m128i*)(src+i)); // we compute inverse popcount table,
__m128i res = _mm_cmpeq_epi8(r0, pattern); // since we pass (img[x] == 0) mask as index in the table.
res = _mm_add_epi8(res, inv);//11111111+1=00000000, 00000000+1=00000001 for( int j = 0; j < 256; j++ )
_mm_store_si128 ((__m128i*)buf, res); {
int val = 0;
__int64 countLow = _mm_popcnt_u64(buf[0]); for( int mask = 1; mask < 256; mask += mask )
nz += countLow; val += (j & mask) == 0;
tab[j] = (uchar)val;
__int64 countHigh = _mm_popcnt_u64(buf[1]); }
nz +=countHigh; initialized = true;
} }
}
#endif for (; i<=len-16; i+=16)
for( ; i < len; i++ ) {
nz += src[i] != 0; __m128i r0 = _mm_loadu_si128((const __m128i*)(src+i));
int val = _mm_movemask_epi8(_mm_cmpeq_epi8(r0, pattern));
nz += tab[val & 255] + tab[val >> 8];
}
}
#endif
for( ; i < len; i++ )
nz += src[i] != 0;
return nz; return nz;
} }
static int countNonZero8u( const uchar* src, int len )
{ return countNonZero_(src, len); }
static int countNonZero16u( const ushort* src, int len ) static int countNonZero16u( const ushort* src, int len )
{ return countNonZero_(src, len); } { return countNonZero_(src, len); }