1/* 2 * Copyright 2011 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8#include "SkBlitRow.h" 9#include "SkBlitMask.h" 10#include "SkColorPriv.h" 11#include "SkUtils.h" 12 13#define UNROLL 14 15static void S32_Opaque_BlitRow32(SkPMColor* SK_RESTRICT dst, 16 const SkPMColor* SK_RESTRICT src, 17 int count, U8CPU alpha) { 18 SkASSERT(255 == alpha); 19 sk_memcpy32(dst, src, count); 20} 21 22static void S32_Blend_BlitRow32(SkPMColor* SK_RESTRICT dst, 23 const SkPMColor* SK_RESTRICT src, 24 int count, U8CPU alpha) { 25 SkASSERT(alpha <= 255); 26 if (count > 0) { 27 unsigned src_scale = SkAlpha255To256(alpha); 28 unsigned dst_scale = 256 - src_scale; 29 30#ifdef UNROLL 31 if (count & 1) { 32 *dst = SkAlphaMulQ(*(src++), src_scale) + SkAlphaMulQ(*dst, dst_scale); 33 dst += 1; 34 count -= 1; 35 } 36 37 const SkPMColor* SK_RESTRICT srcEnd = src + count; 38 while (src != srcEnd) { 39 *dst = SkAlphaMulQ(*(src++), src_scale) + SkAlphaMulQ(*dst, dst_scale); 40 dst += 1; 41 *dst = SkAlphaMulQ(*(src++), src_scale) + SkAlphaMulQ(*dst, dst_scale); 42 dst += 1; 43 } 44#else 45 do { 46 *dst = SkAlphaMulQ(*src, src_scale) + SkAlphaMulQ(*dst, dst_scale); 47 src += 1; 48 dst += 1; 49 } while (--count > 0); 50#endif 51 } 52} 53 54static void S32A_Opaque_BlitRow32(SkPMColor* SK_RESTRICT dst, 55 const SkPMColor* SK_RESTRICT src, 56 int count, U8CPU alpha) { 57 SkASSERT(255 == alpha); 58 if (count > 0) { 59#ifdef UNROLL 60 if (count & 1) { 61 *dst = SkPMSrcOver(*(src++), *dst); 62 dst += 1; 63 count -= 1; 64 } 65 66 const SkPMColor* SK_RESTRICT srcEnd = src + count; 67 while (src != srcEnd) { 68 *dst = SkPMSrcOver(*(src++), *dst); 69 dst += 1; 70 *dst = SkPMSrcOver(*(src++), *dst); 71 dst += 1; 72 } 73#else 74 do { 75 *dst = SkPMSrcOver(*src, *dst); 76 src += 1; 77 dst += 1; 78 } while (--count > 0); 79#endif 80 } 81} 82 83static void S32A_Blend_BlitRow32(SkPMColor* SK_RESTRICT dst, 84 const SkPMColor* SK_RESTRICT src, 85 int count, U8CPU alpha) { 86 SkASSERT(alpha <= 255); 87 if (count > 0) { 88#ifdef UNROLL 89 if (count & 1) { 90 *dst = SkBlendARGB32(*(src++), *dst, alpha); 91 dst += 1; 92 count -= 1; 93 } 94 95 const SkPMColor* SK_RESTRICT srcEnd = src + count; 96 while (src != srcEnd) { 97 *dst = SkBlendARGB32(*(src++), *dst, alpha); 98 dst += 1; 99 *dst = SkBlendARGB32(*(src++), *dst, alpha); 100 dst += 1; 101 } 102#else 103 do { 104 *dst = SkBlendARGB32(*src, *dst, alpha); 105 src += 1; 106 dst += 1; 107 } while (--count > 0); 108#endif 109 } 110} 111 112/////////////////////////////////////////////////////////////////////////////// 113 114static const SkBlitRow::Proc32 gDefault_Procs32[] = { 115 S32_Opaque_BlitRow32, 116 S32_Blend_BlitRow32, 117 S32A_Opaque_BlitRow32, 118 S32A_Blend_BlitRow32 119}; 120 121SkBlitRow::Proc32 SkBlitRow::Factory32(unsigned flags) { 122 SkASSERT(flags < SK_ARRAY_COUNT(gDefault_Procs32)); 123 // just so we don't crash 124 flags &= kFlags32_Mask; 125 126 SkBlitRow::Proc32 proc = PlatformProcs32(flags); 127 if (NULL == proc) { 128 proc = gDefault_Procs32[flags]; 129 } 130 SkASSERT(proc); 131 return proc; 132} 133 134#include "Sk4px.h" 135 136// Color32 uses the blend_256_round_alt algorithm from tests/BlendTest.cpp. 137// It's not quite perfect, but it's never wrong in the interesting edge cases, 138// and it's quite a bit faster than blend_perfect. 139// 140// blend_256_round_alt is our currently blessed algorithm. Please use it or an analogous one. 141void SkBlitRow::Color32(SkPMColor dst[], const SkPMColor src[], int count, SkPMColor color) { 142 switch (SkGetPackedA32(color)) { 143 case 0: memmove(dst, src, count * sizeof(SkPMColor)); return; 144 case 255: sk_memset32(dst, color, count); return; 145 } 146 147 unsigned invA = 255 - SkGetPackedA32(color); 148 invA += invA >> 7; 149 SkASSERT(invA < 256); // We've already handled alpha == 0 above. 150 151 Sk16h colorHighAndRound = Sk4px(color).widenHi() + Sk16h(128); 152 Sk16b invA_16x(invA); 153 154 Sk4px::MapSrc(count, dst, src, [&](const Sk4px& src4) -> Sk4px { 155 return src4.mulWiden(invA_16x).addNarrowHi(colorHighAndRound); 156 }); 157} 158