Cleanup with SkAlphaMulQ_SSE2()

Related nanobench results:
before:
  10M   18      7.03µs  7.31µs  7.38µs  8.46µs  6%      ▂▁▂▂▂▃▄▁█▁      8888    bitmaprect_80_filter_identity
  10M   43      6.96µs  6.97µs  6.99µs  7.19µs  1%      ▁▂▁▁▁▁▁█▁▁      8888    bitmaprect_80_nofilter_identity
  10M   14      35.7µs  35.8µs  35.9µs  36.3µs  1%      ▃▂▁▂▁█▂▁▁▁      8888    bitmap_BGRA_8888_update_scale_bilerp
  10M   16      35.5µs  35.6µs  35.7µs  36.3µs  1%      █▅▂▁▁▁▃▂▁▁      8888    bitmap_BGRA_8888_update_volatile_scale_bilerp
  10M   16      35.4µs  35.4µs  35.5µs  36.8µs  1%      ▂▁█▁▁▁▁▂▁▁      8888    bitmap_BGRA_8888_scale_bilerp
  10M   25      16.4µs  16.6µs  16.7µs  17.4µs  2%      ▂▁▁▂▁▁▁▅▅█      8888    bitmap_Index_8
  10M   15      37.9µs  38µs    38µs    38.4µs  0%      ▄▆▂▁▁▁█▂▁▁      8888    bitmap_RGB_565
  10M   33      11.1µs  11.1µs  11.1µs  11.2µs  0%      ▆▂█▂▂▂▁▁▂▁      8888    bitmap_BGRA_8888_scale
after:
  10M   9       7.04µs  7.06µs  7.1µs   7.32µs  1%      █▅▂▁▁▂▁▁▁▁      8888    bitmaprect_80_filter_identity
  10M   18      7.01µs  7.02µs  7.05µs  7.25µs  1%      █▂▁▁▁▁▁▁▁▁      8888    bitmaprect_80_nofilter_identity
  10M   5       33.9µs  34µs    34.1µs  34.5µs  1%      █▃▂▂▁▁▁▅▃▂      8888    bitmap_BGRA_8888_update_scale_bilerp
  10M   7       35.5µs  35.5µs  35.6µs  36.3µs  1%      ▃▂▂▁▂▁▂▁█▂      8888    bitmap_BGRA_8888_update_volatile_scale_bilerp
  10M   7       35.5µs  35.5µs  35.7µs  36.8µs  1%      ▂▁▁▁▁▁▁▁▁█      8888    bitmap_BGRA_8888_scale_bilerp
  10M   11      16.4µs  16.4µs  16.4µs  16.6µs  0%      █▂▁▁▂▁▁▁▂▁      8888    bitmap_Index_8
  10M   7       37.3µs  37.4µs  38.4µs  47.8µs  9%      ▁▁▁▁▁▁▁▁▁█      8888    bitmap_RGB_565
  10M   33      11µs    11µs    11.1µs  11.2µs  1%      ▄█▅▃▂▁▁▁▁▁      8888    bitmap_BGRA_8888_scale

BUG=skia:

Review URL: https://codereview.chromium.org/755573002
This commit is contained in:
qiankun.miao 2014-11-25 05:59:38 -08:00 committed by Commit bot
parent 10e23caea3
commit 533a32782f
2 changed files with 26 additions and 73 deletions

View File

@ -38,57 +38,14 @@ void S32_Blend_BlitRow32_SSE2(SkPMColor* SK_RESTRICT dst,
const __m128i *s = reinterpret_cast<const __m128i*>(src);
__m128i *d = reinterpret_cast<__m128i*>(dst);
__m128i rb_mask = _mm_set1_epi32(0x00FF00FF);
__m128i ag_mask = _mm_set1_epi32(0xFF00FF00);
// Move scale factors to upper byte of word
__m128i src_scale_wide = _mm_set1_epi16(src_scale << 8);
__m128i dst_scale_wide = _mm_set1_epi16(dst_scale << 8);
while (count >= 4) {
// Load 4 pixels each of src and dest.
__m128i src_pixel = _mm_loadu_si128(s);
__m128i dst_pixel = _mm_load_si128(d);
// Interleave Atom port 0/1 operations based on the execution port
// constraints that multiply can only be executed on port 0 (while
// boolean operations can be executed on either port 0 or port 1)
// because GCC currently doesn't do a good job scheduling
// instructions based on these constraints.
// Get red and blue pixels into lower byte of each word.
// (0, r, 0, b, 0, r, 0, b, 0, r, 0, b, 0, r, 0, b)
__m128i src_rb = _mm_and_si128(rb_mask, src_pixel);
// Multiply by scale.
// (4 x (0, rs.h, 0, bs.h))
// where rs.h stands for the higher byte of r * scale, and
// bs.h the higher byte of b * scale.
src_rb = _mm_mulhi_epu16(src_rb, src_scale_wide);
// Get alpha and green pixels into higher byte of each word.
// (a, 0, g, 0, a, 0, g, 0, a, 0, g, 0, a, 0, g, 0)
__m128i src_ag = _mm_and_si128(ag_mask, src_pixel);
// Multiply by scale.
// (4 x (as.h, as.l, gs.h, gs.l))
src_ag = _mm_mulhi_epu16(src_ag, src_scale_wide);
// Clear the lower byte of the a*scale and g*scale results
// (4 x (as.h, 0, gs.h, 0))
src_ag = _mm_and_si128(src_ag, ag_mask);
// Operations the destination pixels are the same as on the
// source pixels. See the comments above.
__m128i dst_rb = _mm_and_si128(rb_mask, dst_pixel);
dst_rb = _mm_mulhi_epu16(dst_rb, dst_scale_wide);
__m128i dst_ag = _mm_and_si128(ag_mask, dst_pixel);
dst_ag = _mm_mulhi_epu16(dst_ag, dst_scale_wide);
dst_ag = _mm_and_si128(dst_ag, ag_mask);
// Combine back into RGBA.
// (4 x (as.h, rs.h, gs.h, bs.h))
src_pixel = _mm_or_si128(src_rb, src_ag);
dst_pixel = _mm_or_si128(dst_rb, dst_ag);
src_pixel = SkAlphaMulQ_SSE2(src_pixel, src_scale);
dst_pixel = SkAlphaMulQ_SSE2(dst_pixel, dst_scale);
// Add result
__m128i result = _mm_add_epi8(src_pixel, dst_pixel);
@ -368,34 +325,12 @@ void Color32_SSE2(SkPMColor dst[], const SkPMColor src[], int count,
const __m128i *s = reinterpret_cast<const __m128i*>(src);
__m128i *d = reinterpret_cast<__m128i*>(dst);
__m128i rb_mask = _mm_set1_epi32(0x00FF00FF);
__m128i src_scale_wide = _mm_set1_epi16(scale);
__m128i color_wide = _mm_set1_epi32(color);
while (count >= 4) {
// Load 4 pixels each of src and dest.
__m128i src_pixel = _mm_loadu_si128(s);
src_pixel = SkAlphaMulQ_SSE2(src_pixel, scale);
// Get red and blue pixels into lower byte of each word.
__m128i src_rb = _mm_and_si128(rb_mask, src_pixel);
// Get alpha and green into lower byte of each word.
__m128i src_ag = _mm_srli_epi16(src_pixel, 8);
// Multiply by scale.
src_rb = _mm_mullo_epi16(src_rb, src_scale_wide);
src_ag = _mm_mullo_epi16(src_ag, src_scale_wide);
// Divide by 256.
src_rb = _mm_srli_epi16(src_rb, 8);
src_ag = _mm_andnot_si128(rb_mask, src_ag);
// Combine back into RGBA.
src_pixel = _mm_or_si128(src_rb, src_ag);
// Add color to result.
__m128i result = _mm_add_epi8(color_wide, src_pixel);
// Store result.
_mm_store_si128(d, result);
s++;
d++;

View File

@ -42,24 +42,42 @@ static inline __m128i SkAlphaMulAlpha_SSE2(const __m128i& a,
return prod;
}
static const __m128i rb_mask = _mm_set1_epi32(0x00FF00FF);
static const __m128i ag_mask = _mm_set1_epi32(0xFF00FF00);
// Portable version SkAlphaMulQ is in SkColorPriv.h.
static inline __m128i SkAlphaMulQ_SSE2(const __m128i& c, const __m128i& scale) {
__m128i mask = _mm_set1_epi32(0xFF00FF);
__m128i s = _mm_or_si128(_mm_slli_epi32(scale, 16), scale);
// uint32_t rb = ((c & mask) * scale) >> 8
__m128i rb = _mm_and_si128(mask, c);
__m128i rb = _mm_and_si128(rb_mask, c);
rb = _mm_mullo_epi16(rb, s);
rb = _mm_srli_epi16(rb, 8);
// uint32_t ag = ((c >> 8) & mask) * scale
__m128i ag = _mm_srli_epi16(c, 8);
ASSERT_EQ(ag, _mm_and_si128(mask, ag)); // ag = _mm_srli_epi16(c, 8) did this for us.
ASSERT_EQ(ag, _mm_and_si128(rb_mask, ag)); // ag = _mm_srli_epi16(c, 8) did this for us.
ag = _mm_mullo_epi16(ag, s);
// (rb & mask) | (ag & ~mask)
ASSERT_EQ(rb, _mm_and_si128(mask, rb)); // rb = _mm_srli_epi16(rb, 8) did this for us.
ag = _mm_andnot_si128(mask, ag);
ASSERT_EQ(rb, _mm_and_si128(rb_mask, rb)); // rb = _mm_srli_epi16(rb, 8) did this for us.
ag = _mm_and_si128(ag_mask, ag);
return _mm_or_si128(rb, ag);
}
// Fast path for SkAlphaMulQ_SSE2 with a constant scale factor.
static inline __m128i SkAlphaMulQ_SSE2(const __m128i& c, const unsigned scale) {
__m128i s = _mm_set1_epi16(scale << 8); // Move scale factor to upper byte of word.
// With mulhi, red and blue values are already in the right place and
// don't need to be divided by 256.
__m128i rb = _mm_and_si128(rb_mask, c);
rb = _mm_mulhi_epu16(rb, s);
__m128i ag = _mm_and_si128(ag_mask, c);
ag = _mm_mulhi_epu16(ag, s); // Alpha and green values are in the higher byte of each word.
ag = _mm_and_si128(ag_mask, ag);
return _mm_or_si128(rb, ag);
}