blob: ac01e427bfb760a8fc3d6d77244604fb988ba921 [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);
commit-bot@chromium.orgf0ea77a2014-05-21 12:43:07 +000019 sk_memcpy32(dst, src, count);
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);
reed@android.comc4cae852009-09-23 15:06:10 +0000127 if (NULL == proc) {
128 proc = gDefault_Procs32[flags];
129 }
130 SkASSERT(proc);
131 return proc;
132}
133
senorblanco@chromium.org29e50542010-12-16 19:07:45 +0000134SkBlitRow::Proc32 SkBlitRow::ColorProcFactory() {
senorblanco@chromium.orgc3856382010-12-13 15:27:20 +0000135 SkBlitRow::ColorProc proc = PlatformColorProc();
136 if (NULL == proc) {
senorblanco@chromium.org29e50542010-12-16 19:07:45 +0000137 proc = Color32;
senorblanco@chromium.orgc3856382010-12-13 15:27:20 +0000138 }
senorblanco@chromium.org29e50542010-12-16 19:07:45 +0000139 SkASSERT(proc);
140 return proc;
senorblanco@chromium.orgc3856382010-12-13 15:27:20 +0000141}
142
mtkleinafe2ffb2015-04-17 11:00:54 -0700143#define SK_SUPPORT_LEGACY_COLOR32_MATHx
144
145// Color32 and its SIMD specializations use the blend_256_round_alt algorithm
146// from tests/BlendTest.cpp. It's not quite perfect, but it's never wrong in the
147// interesting edge cases, and it's quite a bit faster than blend_perfect.
148//
149// blend_256_round_alt is our currently blessed algorithm. Please use it or an analogous one.
reed@google.comf2068ad2011-09-13 13:56:57 +0000150void SkBlitRow::Color32(SkPMColor* SK_RESTRICT dst,
151 const SkPMColor* SK_RESTRICT src,
senorblanco@chromium.org29e50542010-12-16 19:07:45 +0000152 int count, SkPMColor color) {
mtkleinafe2ffb2015-04-17 11:00:54 -0700153 switch (SkGetPackedA32(color)) {
154 case 0: memmove(dst, src, count * sizeof(SkPMColor)); return;
155 case 255: sk_memset32(dst, color, count); return;
156 }
157
158 unsigned invA = 255 - SkGetPackedA32(color);
159#ifdef SK_SUPPORT_LEGACY_COLOR32_MATH // blend_256_plus1_trunc, busted
160 unsigned round = 0;
161#else // blend_256_round_alt, good
162 invA += invA >> 7;
163 unsigned round = (128 << 16) + (128 << 0);
164#endif
165
166 while (count --> 0) {
167 // Our math is 16-bit, so we can do a little bit of SIMD in 32-bit registers.
168 const uint32_t mask = 0x00FF00FF;
169 uint32_t rb = (((*src >> 0) & mask) * invA + round) >> 8, // _r_b
170 ag = (((*src >> 8) & mask) * invA + round) >> 0; // a_g_
171 *dst = color + ((rb & mask) | (ag & ~mask));
172 src++;
173 dst++;
reed@android.comc4cae852009-09-23 15:06:10 +0000174 }
175}
176