2011-05-11 14 views
7

मैं बाहर एक यथोचित तेज द्विरेखीय छानने समारोह सिर्फ एक नमूना फ़िल्टर किए गए के लिए एक समय में अब एक व्यायाम के रूप intrinsics का उपयोग कर के लिए इस्तेमाल किया जा रहा है में लगाने की कोशिश कर रहा हूँ - SSE41 अप करने के लिए ठीक है।द्विरेखीय फिल्टर

inline __m128i DivideBy255_8xUint16(const __m128i value) 
{ 
    // Blinn 16bit divide by 255 trick but across 8 packed 16bit values 
    const __m128i plus128 = _mm_add_epi16(value, _mm_set1_epi16(128)); 
    const __m128i plus128ThenDivideBy256 = _mm_srli_epi16(plus128, 8);   // TODO: Should this be an arithmetic or logical shift or does it matter? 
    const __m128i partial = _mm_add_epi16(plus128, plus128ThenDivideBy256); 
    const __m128i result = _mm_srli_epi16(partial, 8);       // TODO: Should this be an arithmetic or logical shift or does it matter? 


    return result; 
} 


inline uint32_t BilinearSSE41(const uint8_t* data, uint32_t pitch, uint32_t width, uint32_t height, float u, float v) 
{ 
    // TODO: There are probably intrinsics I haven't found yet to avoid using these? 
    // 0x80 is high bit set which means zero out that component 
    const __m128i unpack_fraction_u_mask = _mm_set_epi8(0x80, 0, 0x80, 0, 0x80, 0, 0x80, 0, 0x80, 0, 0x80, 0, 0x80, 0, 0x80, 0); 
    const __m128i unpack_fraction_v_mask = _mm_set_epi8(0x80, 1, 0x80, 1, 0x80, 1, 0x80, 1, 0x80, 1, 0x80, 1, 0x80, 1, 0x80, 1); 
    const __m128i unpack_two_texels_mask = _mm_set_epi8(0x80, 7, 0x80, 6, 0x80, 5, 0x80, 4, 0x80, 3, 0x80, 2, 0x80, 1, 0x80, 0); 


    // TODO: Potentially wasting two channels of operations for now 
    const __m128i size = _mm_set_epi32(0, 0, height - 1, width - 1); 
    const __m128 uv = _mm_set_ps(0.0f, 0.0f, v, u); 

    const __m128 floor_uv_f = _mm_floor_ps(uv); 
    const __m128 fraction_uv_f = _mm_sub_ps(uv, floor_uv_f); 
    const __m128 fraction255_uv_f = _mm_mul_ps(fraction_uv_f, _mm_set_ps1(255.0f)); 
    const __m128i fraction255_uv_i = _mm_cvttps_epi32(fraction255_uv_f); // TODO: Did this get rounded correctly? 

    const __m128i fraction255_u_i = _mm_shuffle_epi8(fraction255_uv_i, unpack_fraction_u_mask); // Splat fraction_u*255 across all 16 bit words 
    const __m128i fraction255_v_i = _mm_shuffle_epi8(fraction255_uv_i, unpack_fraction_v_mask); // Splat fraction_v*255 across all 16 bit words 

    const __m128i inverse_fraction255_u_i = _mm_sub_epi16(_mm_set1_epi16(255), fraction255_u_i); 
    const __m128i inverse_fraction255_v_i = _mm_sub_epi16(_mm_set1_epi16(255), fraction255_v_i); 

    const __m128i floor_uv_i = _mm_cvttps_epi32(floor_uv_f); 
    const __m128i clipped_floor_uv_i = _mm_min_epu32(floor_uv_i, size); // TODO: I haven't clamped this probably if uv was less than zero yet... 


    // TODO: Calculating the addresses in the SSE register set would maybe be better 

    int u0 = _mm_extract_epi32(floor_uv_i, 0); 
    int v0 = _mm_extract_epi32(floor_uv_i, 1); 


    const uint8_t* row = data + (u0<<2) + pitch*v0; 


    const __m128i row0_packed = _mm_loadl_epi64((const __m128i*)data); 
    const __m128i row0 = _mm_shuffle_epi8(row0_packed, unpack_two_texels_mask); 

    const __m128i row1_packed = _mm_loadl_epi64((const __m128i*)(data + pitch)); 
    const __m128i row1 = _mm_shuffle_epi8(row1_packed, unpack_two_texels_mask); 


    // Compute (row0*fraction)/255 + row1*(255 - fraction)/255 - probably slight precision loss across addition! 
    const __m128i vlerp0 = DivideBy255_8xUint16(_mm_mullo_epi16(row0, fraction255_v_i)); 
    const __m128i vlerp1 = DivideBy255_8xUint16(_mm_mullo_epi16(row1, inverse_fraction255_v_i)); 
    const __m128i vlerp = _mm_adds_epi16(vlerp0, vlerp1); 

    const __m128i hlerp0 = DivideBy255_8xUint16(_mm_mullo_epi16(vlerp, fraction255_u_i)); 
    const __m128i hlerp1 = DivideBy255_8xUint16(_mm_srli_si128(_mm_mullo_epi16(vlerp, inverse_fraction255_u_i), 16 - 2*4)); 
    const __m128i hlerp = _mm_adds_epi16(hlerp0, hlerp1); 


    // Pack down to 8bit from 16bit components and return 32bit ARGB result 
    return _mm_extract_epi32(_mm_packus_epi16(hlerp, hlerp), 0); 
} 

कोड मान लिया गया छवि डेटा ARGB8 है और एक अतिरिक्त स्तंभ और पंक्ति शाखा के बिना किनारे मामलों को संभालने के लिए है:

अब तक मैं निम्नलिखित है।

मैं क्या निर्देश के बारे में सलाह के बाद कर रहा हूँ मैं इस gangly गड़बड़ की और निश्चित रूप से आकार नीचे लाने के लिए यह कैसे तेजी से चलाने के लिए सुधार किया जा सकता का उपयोग कर सकते हैं!

धन्यवाद :)

उत्तर

1

कुछ भी नहीं है विशिष्ट अपने कोड के बारे में कहने के लिए। लेकिन मैंने एसएसई 2 का उपयोग करके अपना खुद का बिलीनेर स्केलिंग कोड लिखा था। अधिक जानकारी के लिए StackOverflow प्रश्न Help me improve some more SSE2 code देखें।

मेरी कोड में मैं नहीं बल्कि प्रति पिक्सेल से पहले क्षैतिज और ऊर्ध्वाधर भिन्न और अनुक्रमित की गणना। मुझे लगता है कि यह तेज़ है।

core2 CPUs के तहत मेरे कोड ऐसा नहीं precalc कर तेजी से हो सकता है स्मृति सीमित बजाय cpu हो रहा है।

1

आपकी टिप्पणी को नोटिस किया गया "TODO: क्या यह अंकगणित या तार्किक बदलाव होना चाहिए या इससे कोई फर्क पड़ता है?"

अंकगणितीय शिफ्ट हस्ताक्षरित पूर्णांक के लिए है। तार्किक बदलाव हस्ताक्षरित पूर्णांक के लिए है।

0x80000000 >> 4 is 0xf8000000 // Arithmetic shift 
    0x80000000 >> 4 is 0x08000000 // Logical shift 
संबंधित मुद्दे