title: SSE2 Color Blending
body: <p>I've a code doing a simple color blending:</p>
  
  <pre><code>  dr = (((dr-sr)*sa)&gt;&gt;8) + sr;
    dg = (((dg-sg)*sa)&gt;&gt;8) + sg;
    db = (((db-sb)*sa)&gt;&gt;8) + sb;
  </code></pre>
  
  <p>Where <code>sr,sg,sb</code> are source color, <code>sa</code> is source alpha, <code>dr,dg,db</code> is the color already in frame buffer.</p>
  
  <p>Now obviously this code is the single biggest bottleneck, because it is done for millions of pixels, so I tried to optimize it using GCC/Clang's SSE intrinsics:</p>
  
  <pre><code>__m128 srgb = _mm_cvtepi32_ps(_mm_setr_epi32(sb,sg,sr,0));
  __m128 drgb = _mm_cvtepi32_ps(_mm_shuffle_epi8(_mm_set1_epi32(dst_rgb),imask));
  __m128 msa = _mm_set1_ps((float)sa*(1.0f/255.0f));
  __m128 r1 = _mm_add_ps(_mm_mul_ps(_mm_sub_ps(drgb,srgb), msa), srgb);
  __m128 r2 = _mm_cvtps_epi32(r1);
  dst_rgb = _mm_extract_epi32(_mm_shuffle_epi8(r2,omask),0);
  </code></pre>
  
  <p>I had to use floats, because GCC's SSE intrinsics don't appear to have proper int32 multiply to do the <code>color * sa</code>. I also cant really use _mm_set1_epi32(src_rgb) and source color in XMM registers, because sr,sg,sb are passed through several lookup tables, before blending. AVX2 does support lookup tables with gather operations, but SSE2 doesn't appear to.</p>
  
  <p>Unfortunately it only slowed down the code. Maybe I'm doing something wrong or SSE's FPU just can't compete with integer operators? Maybe I should use MMX, or MMX is even slower on modern CPUs? I've -march=native -O3 -ffast-math options turned on.</p>
  
  <p>@harold suggested doing full integer SIMD version, but it is still slower than non-SSE:</p>
  
  <pre><code>static uint8_t imask_[] = { 12+0, 0xff, 0xff, 0xff
                             , 8+1, 0xff, 0xff, 0xff
                             , 4+2, 0xff, 0xff, 0xff
                             ,   3, 0xff, 0xff, 0xff};
  static uint8_t omask_[] = {0,4,8,12
                            ,0xff, 0xff, 0xff, 0xff
                            ,0xff, 0xff, 0xff, 0xff
                            ,0xff, 0xff, 0xff, 0xff};
  #define imask (*(__m128i*)imask_)
  #define omask (*(__m128i*)omask_)
      /* ... */
  __m128 msa = _mm_set1_epi32(sa&lt;&lt;8);
  __m128 srgb = _mm_setr_epi32(sb,sg,sr,0);
  __m128 drgb = _mm_shuffle_epi8(_mm_set1_epi32(DC),imask);
  __m128 r2 = _mm_add_epi16(_mm_mulhi_epu16(_mm_sub_epi16(drgb,srgb), msa), srgb);
  DC = _mm_extract_epi32(_mm_shuffle_epi8(r2,omask),0);
  </code></pre>
  
  <p><strong>UPD:</strong>
  I've managed to squeeze a few 2-3 FPS out of that integer SSE code by loading src_color directly into SSE register, where possible, using the __m128 srgb = _mm_shuffle_epi8(_mm_set1_epi32(c),sse_imsk), which is faster than _mm_setr_epi32. Still not a huge improvement, compared to say loop unrolling for 8 pixels, which provided 4-6 FPS.</p>