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 214 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
225 } | 225 } |
226 | 226 |
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 |
| 236 |
| 237 /* SSE2 version of Color32() |
| 238 * portable version is in core/SkBlitRow_D32.cpp |
| 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. |
| 245 void Color32_SSE2(SkPMColor dst[], const SkPMColor src[], int count, SkPMColor c
olor) { |
| 246 switch (SkGetPackedA32(color)) { |
| 247 case 0: memmove(dst, src, count * sizeof(SkPMColor)); return; |
| 248 case 255: sk_memset32(dst, color, count); return; |
| 249 } |
| 250 |
| 251 __m128i colorHigh = _mm_unpacklo_epi8(_mm_setzero_si128(), _mm_set1_epi32(co
lor)); |
| 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 |
| 265 |
| 266 // Does the core work of blending color onto 4 pixels, returning the resulti
ng 4 pixels. |
| 267 auto kernel = [&](const __m128i& src4) -> __m128i { |
| 268 __m128i lo = _mm_mullo_epi16(invA16, _mm_unpacklo_epi8(src4, _mm_setzero
_si128())), |
| 269 hi = _mm_mullo_epi16(invA16, _mm_unpackhi_epi8(src4, _mm_setzero
_si128())); |
| 270 return _mm_packus_epi16(_mm_srli_epi16(_mm_add_epi16(colorAndRound, lo),
8), |
| 271 _mm_srli_epi16(_mm_add_epi16(colorAndRound, hi),
8)); |
| 272 }; |
| 273 |
| 274 while (count >= 8) { |
| 275 __m128i dst0 = kernel(_mm_loadu_si128((const __m128i*)(src+0))), |
| 276 dst4 = kernel(_mm_loadu_si128((const __m128i*)(src+4))); |
| 277 _mm_storeu_si128((__m128i*)(dst+0), dst0); |
| 278 _mm_storeu_si128((__m128i*)(dst+4), dst4); |
| 279 src += 8; |
| 280 dst += 8; |
| 281 count -= 8; |
| 282 } |
| 283 if (count >= 4) { |
| 284 _mm_storeu_si128((__m128i*)dst, kernel(_mm_loadu_si128((const __m128i*)s
rc))); |
| 285 src += 4; |
| 286 dst += 4; |
| 287 count -= 4; |
| 288 } |
| 289 if (count >= 2) { |
| 290 _mm_storel_epi64((__m128i*)dst, kernel(_mm_loadl_epi64((const __m128i*)s
rc))); |
| 291 src += 2; |
| 292 dst += 2; |
| 293 count -= 2; |
| 294 } |
| 295 if (count >= 1) { |
| 296 *dst = _mm_cvtsi128_si32(kernel(_mm_cvtsi32_si128(*src))); |
| 297 } |
| 298 } |
| 299 |
235 void Color32A_D565_SSE2(uint16_t dst[], SkPMColor src, int count, int x, int y)
{ | 300 void Color32A_D565_SSE2(uint16_t dst[], SkPMColor src, int count, int x, int y)
{ |
236 SkASSERT(count > 0); | 301 SkASSERT(count > 0); |
237 | 302 |
238 uint32_t src_expand = (SkGetPackedG32(src) << 24) | | 303 uint32_t src_expand = (SkGetPackedG32(src) << 24) | |
239 (SkGetPackedR32(src) << 13) | | 304 (SkGetPackedR32(src) << 13) | |
240 (SkGetPackedB32(src) << 2); | 305 (SkGetPackedB32(src) << 2); |
241 unsigned scale = SkAlpha255To256(0xFF - SkGetPackedA32(src)) >> 3; | 306 unsigned scale = SkAlpha255To256(0xFF - SkGetPackedA32(src)) >> 3; |
242 | 307 |
243 // Check if we have enough pixels to run SIMD | 308 // Check if we have enough pixels to run SIMD |
244 if (count >= (int)(8 + (((16 - (size_t)dst) & 0x0F) >> 1))) { | 309 if (count >= (int)(8 + (((16 - (size_t)dst) & 0x0F) >> 1))) { |
(...skipping 913 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1158 uint32_t dst_expanded = SkExpand_rgb_16(*dst); | 1223 uint32_t dst_expanded = SkExpand_rgb_16(*dst); |
1159 dst_expanded = dst_expanded * (SkAlpha255To256(255 - a) >> 3); | 1224 dst_expanded = dst_expanded * (SkAlpha255To256(255 - a) >> 3); |
1160 // 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 |
1161 *dst = SkCompact_rgb_16((src_expanded + dst_expanded) >> 5); | 1226 *dst = SkCompact_rgb_16((src_expanded + dst_expanded) >> 5); |
1162 } | 1227 } |
1163 dst += 1; | 1228 dst += 1; |
1164 DITHER_INC_X(x); | 1229 DITHER_INC_X(x); |
1165 } while (--count != 0); | 1230 } while (--count != 0); |
1166 } | 1231 } |
1167 } | 1232 } |
OLD | NEW |