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 |
235 /* SSE2 version of Color32() | 237 /* SSE2 version of Color32() |
236 * portable version is in core/SkBlitRow_D32.cpp | 238 * portable version is in core/SkBlitRow_D32.cpp |
237 */ | 239 */ |
238 void Color32_SSE2(SkPMColor dst[], const SkPMColor src[], int count, | 240 // Color32 and its SIMD specializations use the blend_256_round_alt algorithm |
239 SkPMColor color) { | 241 // from tests/BlendTest.cpp. It's not quite perfect, but it's never wrong in th
e |
240 if (count <= 0) { | 242 // interesting edge cases, and it's quite a bit faster than blend_perfect. |
241 return; | 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; |
242 } | 249 } |
243 | 250 |
244 if (0 == color) { | 251 __m128i colorHigh = _mm_unpacklo_epi8(_mm_setzero_si128(), _mm_set1_epi32(co
lor)); |
245 if (src != dst) { | 252 #ifdef SK_SUPPORT_LEGACY_COLOR32_MATH // blend_256_plus1_trunc, busted |
246 memcpy(dst, src, count * sizeof(SkPMColor)); | 253 __m128i colorAndRound = colorHigh; |
247 } | 254 #else // blend_256_round_alt, good |
248 return; | 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; |
249 } | 282 } |
250 | 283 if (count >= 4) { |
251 unsigned colorA = SkGetPackedA32(color); | 284 _mm_storeu_si128((__m128i*)dst, kernel(_mm_loadu_si128((const __m128i*)s
rc))); |
252 if (255 == colorA) { | 285 src += 4; |
253 sk_memset32(dst, color, count); | 286 dst += 4; |
254 } else { | 287 count -= 4; |
255 unsigned scale = 256 - SkAlpha255To256(colorA); | 288 } |
256 | 289 if (count >= 2) { |
257 if (count >= 4) { | 290 _mm_storel_epi64((__m128i*)dst, kernel(_mm_loadl_epi64((const __m128i*)s
rc))); |
258 SkASSERT(((size_t)dst & 0x03) == 0); | 291 src += 2; |
259 while (((size_t)dst & 0x0F) != 0) { | 292 dst += 2; |
260 *dst = color + SkAlphaMulQ(*src, scale); | 293 count -= 2; |
261 src++; | 294 } |
262 dst++; | 295 if (count >= 1) { |
263 count--; | 296 *dst = _mm_cvtsi128_si32(kernel(_mm_cvtsi32_si128(*src))); |
264 } | |
265 | |
266 const __m128i *s = reinterpret_cast<const __m128i*>(src); | |
267 __m128i *d = reinterpret_cast<__m128i*>(dst); | |
268 __m128i color_wide = _mm_set1_epi32(color); | |
269 while (count >= 4) { | |
270 __m128i src_pixel = _mm_loadu_si128(s); | |
271 src_pixel = SkAlphaMulQ_SSE2(src_pixel, scale); | |
272 | |
273 __m128i result = _mm_add_epi8(color_wide, src_pixel); | |
274 _mm_store_si128(d, result); | |
275 s++; | |
276 d++; | |
277 count -= 4; | |
278 } | |
279 src = reinterpret_cast<const SkPMColor*>(s); | |
280 dst = reinterpret_cast<SkPMColor*>(d); | |
281 } | |
282 | |
283 while (count > 0) { | |
284 *dst = color + SkAlphaMulQ(*src, scale); | |
285 src += 1; | |
286 dst += 1; | |
287 count--; | |
288 } | |
289 } | 297 } |
290 } | 298 } |
291 | 299 |
292 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)
{ |
293 SkASSERT(count > 0); | 301 SkASSERT(count > 0); |
294 | 302 |
295 uint32_t src_expand = (SkGetPackedG32(src) << 24) | | 303 uint32_t src_expand = (SkGetPackedG32(src) << 24) | |
296 (SkGetPackedR32(src) << 13) | | 304 (SkGetPackedR32(src) << 13) | |
297 (SkGetPackedB32(src) << 2); | 305 (SkGetPackedB32(src) << 2); |
298 unsigned scale = SkAlpha255To256(0xFF - SkGetPackedA32(src)) >> 3; | 306 unsigned scale = SkAlpha255To256(0xFF - SkGetPackedA32(src)) >> 3; |
(...skipping 916 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1215 uint32_t dst_expanded = SkExpand_rgb_16(*dst); | 1223 uint32_t dst_expanded = SkExpand_rgb_16(*dst); |
1216 dst_expanded = dst_expanded * (SkAlpha255To256(255 - a) >> 3); | 1224 dst_expanded = dst_expanded * (SkAlpha255To256(255 - a) >> 3); |
1217 // 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 |
1218 *dst = SkCompact_rgb_16((src_expanded + dst_expanded) >> 5); | 1226 *dst = SkCompact_rgb_16((src_expanded + dst_expanded) >> 5); |
1219 } | 1227 } |
1220 dst += 1; | 1228 dst += 1; |
1221 DITHER_INC_X(x); | 1229 DITHER_INC_X(x); |
1222 } while (--count != 0); | 1230 } while (--count != 0); |
1223 } | 1231 } |
1224 } | 1232 } |
OLD | NEW |