blob: 0f8cbe810479ebd4ee0d40ce0a268f15a90620cc [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001/*
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 */
reed@google.com58af9a62011-10-12 13:43:52 +00007
reed@android.comc4cae852009-09-23 15:06:10 +00008#include "SkBlitRow.h"
reed@google.com58af9a62011-10-12 13:43:52 +00009#include "SkBlitMask.h"
reed@android.comc4cae852009-09-23 15:06:10 +000010#include "SkColorPriv.h"
11#include "SkUtils.h"
12
djsollen@google.com57f49692011-02-23 20:46:31 +000013#define UNROLL
14
reed@android.comc4cae852009-09-23 15:06:10 +000015static void S32_Opaque_BlitRow32(SkPMColor* SK_RESTRICT dst,
16 const SkPMColor* SK_RESTRICT src,
17 int count, U8CPU alpha) {
18 SkASSERT(255 == alpha);
mtklein58fd2c82015-07-27 11:08:28 -070019 memcpy(dst, src, count * 4);
reed@android.comc4cae852009-09-23 15:06:10 +000020}
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;
djsollen@google.com57f49692011-02-23 20:46:31 +000029
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
reed@android.comc4cae852009-09-23 15:06:10 +000045 do {
46 *dst = SkAlphaMulQ(*src, src_scale) + SkAlphaMulQ(*dst, dst_scale);
47 src += 1;
48 dst += 1;
49 } while (--count > 0);
djsollen@google.com57f49692011-02-23 20:46:31 +000050#endif
reed@android.comc4cae852009-09-23 15:06:10 +000051 }
52}
53
reed@android.comc4cae852009-09-23 15:06:10 +000054static 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) {
djsollen@google.com57f49692011-02-23 20:46:31 +000059#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
reed@android.comc4cae852009-09-23 15:06:10 +000074 do {
reed@android.comc4cae852009-09-23 15:06:10 +000075 *dst = SkPMSrcOver(*src, *dst);
reed@android.comc4cae852009-09-23 15:06:10 +000076 src += 1;
77 dst += 1;
78 } while (--count > 0);
djsollen@google.com57f49692011-02-23 20:46:31 +000079#endif
reed@android.comc4cae852009-09-23 15:06:10 +000080 }
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) {
djsollen@google.com57f49692011-02-23 20:46:31 +000088#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
reed@android.comc4cae852009-09-23 15:06:10 +0000103 do {
104 *dst = SkBlendARGB32(*src, *dst, alpha);
105 src += 1;
106 dst += 1;
107 } while (--count > 0);
djsollen@google.com57f49692011-02-23 20:46:31 +0000108#endif
reed@android.comc4cae852009-09-23 15:06:10 +0000109 }
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;
reed@google.com981d4792011-03-09 12:55:47 +0000125
senorblanco@chromium.org92727612009-11-04 20:51:06 +0000126 SkBlitRow::Proc32 proc = PlatformProcs32(flags);
halcanary96fcdcc2015-08-27 07:41:13 -0700127 if (nullptr == proc) {
reed@android.comc4cae852009-09-23 15:06:10 +0000128 proc = gDefault_Procs32[flags];
129 }
130 SkASSERT(proc);
131 return proc;
132}
133
mtkleind2ffd362015-05-12 06:11:21 -0700134#include "Sk4px.h"
135
mtklein95cc0122015-04-27 15:11:01 -0700136// 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.
mtkleina4a0aeb2015-04-21 08:09:30 -0700139//
140// blend_256_round_alt is our currently blessed algorithm. Please use it or an analogous one.
mtklein95cc0122015-04-27 15:11:01 -0700141void SkBlitRow::Color32(SkPMColor dst[], const SkPMColor src[], int count, SkPMColor color) {
mtkleinafe2ffb2015-04-17 11:00:54 -0700142 switch (SkGetPackedA32(color)) {
143 case 0: memmove(dst, src, count * sizeof(SkPMColor)); return;
144 case 255: sk_memset32(dst, color, count); return;
145 }
146
mtklein051a51e2015-05-22 06:08:29 -0700147 // This Sk4px impl works great on other platforms or when we have NEON.
148#if defined(SK_CPU_ARM32) && !defined(SK_ARM_HAS_NEON)
149 if (auto proc = PlatformColor32Proc()) { return proc(dst, src, count, color); }
150#endif
151
mtkleinafe2ffb2015-04-17 11:00:54 -0700152 unsigned invA = 255 - SkGetPackedA32(color);
mtkleina4a0aeb2015-04-21 08:09:30 -0700153 invA += invA >> 7;
mtklein95cc0122015-04-27 15:11:01 -0700154 SkASSERT(invA < 256); // We've already handled alpha == 0 above.
155
mtklein059ac002015-06-22 10:39:38 -0700156 Sk16h colorHighAndRound = Sk4px::DupPMColor(color).widenHi() + Sk16h(128);
mtkleind2ffd362015-05-12 06:11:21 -0700157 Sk16b invA_16x(invA);
mtklein95cc0122015-04-27 15:11:01 -0700158
mtkleind2ffd362015-05-12 06:11:21 -0700159 Sk4px::MapSrc(count, dst, src, [&](const Sk4px& src4) -> Sk4px {
mtklein059ac002015-06-22 10:39:38 -0700160 return (src4 * invA_16x).addNarrowHi(colorHighAndRound);
mtkleind2ffd362015-05-12 06:11:21 -0700161 });
reed@android.comc4cae852009-09-23 15:06:10 +0000162}