OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2012 The Android Open Source Project | 2 * Copyright 2012 The Android Open Source Project |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include <emmintrin.h> | 8 #include <emmintrin.h> |
9 #include "SkBitmapProcState_opts_SSE2.h" | 9 #include "SkBitmapProcState_opts_SSE2.h" |
10 #include "SkBlitRow_opts_SSE2.h" | 10 #include "SkBlitRow_opts_SSE2.h" |
(...skipping 216 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
227 while (count > 0) { | 227 while (count > 0) { |
228 *dst = SkBlendARGB32(*src, *dst, alpha); | 228 *dst = SkBlendARGB32(*src, *dst, alpha); |
229 src++; | 229 src++; |
230 dst++; | 230 dst++; |
231 count--; | 231 count--; |
232 } | 232 } |
233 } | 233 } |
234 | 234 |
235 #define SK_SUPPORT_LEGACY_COLOR32_MATHx | 235 #define SK_SUPPORT_LEGACY_COLOR32_MATHx |
236 | 236 |
237 /* SSE2 version of Color32(), portable version is in core/SkBlitRow_D32.cpp */ | 237 /* SSE2 version of Color32() |
238 // Color32 and its SIMD specializations use the blend_perfect algorithm from tes
ts/BlendTest.cpp. | 238 * portable version is in core/SkBlitRow_D32.cpp |
239 // An acceptable alternative is blend_256_round_alt, which is faster but not qui
te perfect. | 239 */ |
| 240 // Color32 and its SIMD specializations use the blend_256_round_alt algorithm |
| 241 // from tests/BlendTest.cpp. It's not quite perfect, but it's never wrong in th
e |
| 242 // interesting edge cases, and it's quite a bit faster than blend_perfect. |
| 243 // |
| 244 // blend_256_round_alt is our currently blessed algorithm. Please use it or an
analogous one. |
240 void Color32_SSE2(SkPMColor dst[], const SkPMColor src[], int count, SkPMColor c
olor) { | 245 void Color32_SSE2(SkPMColor dst[], const SkPMColor src[], int count, SkPMColor c
olor) { |
241 switch (SkGetPackedA32(color)) { | 246 switch (SkGetPackedA32(color)) { |
242 case 0: memmove(dst, src, count * sizeof(SkPMColor)); return; | 247 case 0: memmove(dst, src, count * sizeof(SkPMColor)); return; |
243 case 255: sk_memset32(dst, color, count); return; | 248 case 255: sk_memset32(dst, color, count); return; |
244 } | 249 } |
245 | 250 |
246 __m128i color_2x_high = _mm_unpacklo_epi8(_mm_setzero_si128(), _mm_set1_epi3
2(color)), | 251 __m128i colorHigh = _mm_unpacklo_epi8(_mm_setzero_si128(), _mm_set1_epi32(co
lor)); |
247 invA_8x = _mm_set1_epi16(255 - SkGetPackedA32(color)); | 252 #ifdef SK_SUPPORT_LEGACY_COLOR32_MATH // blend_256_plus1_trunc, busted |
| 253 __m128i colorAndRound = colorHigh; |
| 254 #else // blend_256_round_alt, good |
| 255 __m128i colorAndRound = _mm_add_epi16(colorHigh, _mm_set1_epi16(128)); |
| 256 #endif |
| 257 |
| 258 unsigned invA = 255 - SkGetPackedA32(color); |
| 259 #ifdef SK_SUPPORT_LEGACY_COLOR32_MATH // blend_256_plus1_trunc, busted |
| 260 __m128i invA16 = _mm_set1_epi16(invA); |
| 261 #else // blend_256_round_alt, good |
| 262 SkASSERT(invA + (invA >> 7) < 256); // We should still fit in the low byte
here. |
| 263 __m128i invA16 = _mm_set1_epi16(invA + (invA >> 7)); |
| 264 #endif |
248 | 265 |
249 // Does the core work of blending color onto 4 pixels, returning the resulti
ng 4 pixels. | 266 // Does the core work of blending color onto 4 pixels, returning the resulti
ng 4 pixels. |
250 auto kernel = [&](const __m128i& src_4x) -> __m128i { | 267 auto kernel = [&](const __m128i& src4) -> __m128i { |
251 __m128i lo = _mm_mullo_epi16(invA_8x, _mm_unpacklo_epi8(src_4x, _mm_setz
ero_si128())), | 268 __m128i lo = _mm_mullo_epi16(invA16, _mm_unpacklo_epi8(src4, _mm_setzero
_si128())), |
252 hi = _mm_mullo_epi16(invA_8x, _mm_unpackhi_epi8(src_4x, _mm_setz
ero_si128())); | 269 hi = _mm_mullo_epi16(invA16, _mm_unpackhi_epi8(src4, _mm_setzero
_si128())); |
253 #ifndef SK_SUPPORT_LEGACY_COLOR32_MATH | 270 return _mm_packus_epi16(_mm_srli_epi16(_mm_add_epi16(colorAndRound, lo),
8), |
254 lo = _mm_add_epi16(lo, _mm_set1_epi16(128)); | 271 _mm_srli_epi16(_mm_add_epi16(colorAndRound, hi),
8)); |
255 hi = _mm_add_epi16(hi, _mm_set1_epi16(128)); | |
256 lo = _mm_add_epi16(lo, _mm_srli_epi16(lo, 8)); | |
257 hi = _mm_add_epi16(hi, _mm_srli_epi16(hi, 8)); | |
258 #endif | |
259 return _mm_packus_epi16(_mm_srli_epi16(_mm_add_epi16(color_2x_high, lo),
8), | |
260 _mm_srli_epi16(_mm_add_epi16(color_2x_high, hi),
8)); | |
261 }; | 272 }; |
262 | 273 |
263 while (count >= 8) { | 274 while (count >= 8) { |
264 __m128i dst0 = kernel(_mm_loadu_si128((const __m128i*)(src+0))), | 275 __m128i dst0 = kernel(_mm_loadu_si128((const __m128i*)(src+0))), |
265 dst4 = kernel(_mm_loadu_si128((const __m128i*)(src+4))); | 276 dst4 = kernel(_mm_loadu_si128((const __m128i*)(src+4))); |
266 _mm_storeu_si128((__m128i*)(dst+0), dst0); | 277 _mm_storeu_si128((__m128i*)(dst+0), dst0); |
267 _mm_storeu_si128((__m128i*)(dst+4), dst4); | 278 _mm_storeu_si128((__m128i*)(dst+4), dst4); |
268 src += 8; | 279 src += 8; |
269 dst += 8; | 280 dst += 8; |
270 count -= 8; | 281 count -= 8; |
(...skipping 941 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1212 uint32_t dst_expanded = SkExpand_rgb_16(*dst); | 1223 uint32_t dst_expanded = SkExpand_rgb_16(*dst); |
1213 dst_expanded = dst_expanded * (SkAlpha255To256(255 - a) >> 3); | 1224 dst_expanded = dst_expanded * (SkAlpha255To256(255 - a) >> 3); |
1214 // now src and dst expanded are in g:11 r:10 x:1 b:10 | 1225 // now src and dst expanded are in g:11 r:10 x:1 b:10 |
1215 *dst = SkCompact_rgb_16((src_expanded + dst_expanded) >> 5); | 1226 *dst = SkCompact_rgb_16((src_expanded + dst_expanded) >> 5); |
1216 } | 1227 } |
1217 dst += 1; | 1228 dst += 1; |
1218 DITHER_INC_X(x); | 1229 DITHER_INC_X(x); |
1219 } while (--count != 0); | 1230 } while (--count != 0); |
1220 } | 1231 } |
1221 } | 1232 } |
OLD | NEW |