title: Fastest 50% scaling of (A)RGB32 images using sse intrinsics
body: <p>I want to scale down images as fast as I can in c++. <a href="http://blog.qt.io/blog/2009/01/20/50-scaling-of-argb32-image/" rel="nofollow noreferrer">This article</a> describes how to efficiently average 32bit rgb images down 50%. It is fast and looks good. </p>
  
  <p>I have tried modifying that approach using sse intrinsics. The code below works, with or without SSE enabled. Surprisingly, though, the speedup is negligible.</p>
  
  <p>Can anybody see a way of improving the SSE code. The two lines creating vars shuffle1 and shuffle2 seems two be candidates(using some clever shifting or similar).</p>
  
  <pre class="lang-cpp prettyprint-override"><code>/*
   * Calculates the average of two rgb32 pixels.
   */
  inline static uint32_t avg(uint32_t a, uint32_t b)
  {
      return (((a^b) &amp; 0xfefefefeUL) &gt;&gt; 1) + (a&amp;b);
  }
  
  /*
   * Calculates the average of four rgb32 pixels.
   */
  inline static uint32_t avg(const uint32_t a[2], const uint32_t b[2])
  {
      return avg(avg(a[0], a[1]), avg(b[0], b[1]));
  }
  
  /*
   * Calculates the average of two rows of rgb32 pixels.
   */
  void average2Rows(const uint32_t* src_row1, const uint32_t* src_row2, uint32_t* dst_row, int w)
  {
  #if !defined(__SSE)
          for (int x = w; x; --x, dst_row++, src_row1 += 2, src_row2 += 2)
              * dst_row = avg(src_row1, src_row2);
  #else
          for (int x = w; x; x-=4, dst_row+=4, src_row1 += 8, src_row2 += 8)
          {
              __m128i left  = _mm_avg_epu8(_mm_load_si128((__m128i const*)src_row1), _mm_load_si128((__m128i const*)src_row2));
              __m128i right = _mm_avg_epu8(_mm_load_si128((__m128i const*)(src_row1+4)), _mm_load_si128((__m128i const*)(src_row2+4)));
  
              __m128i shuffle1 = _mm_set_epi32( right.m128i_u32[2], right.m128i_u32[0], left.m128i_u32[2], left.m128i_u32[0]);
              __m128i shuffle2 = _mm_set_epi32( right.m128i_u32[3], right.m128i_u32[1], left.m128i_u32[3], left.m128i_u32[1]);
  
              _mm_store_si128((__m128i *)dst_row, _mm_avg_epu8(shuffle1, shuffle2));
          }
  #endif
  }
  </code></pre>