blob: c858af6318acca8cf1c730d3214fcac8170f71a3 [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
tomhudson@google.com8dd90a92012-03-19 13:49:50 +000015SkBlitRow::ColorRectProc PlatformColorRectProcFactory();
16
reed@android.comc4cae852009-09-23 15:06:10 +000017static void S32_Opaque_BlitRow32(SkPMColor* SK_RESTRICT dst,
18 const SkPMColor* SK_RESTRICT src,
19 int count, U8CPU alpha) {
20 SkASSERT(255 == alpha);
21 memcpy(dst, src, count * sizeof(SkPMColor));
22}
23
24static void S32_Blend_BlitRow32(SkPMColor* SK_RESTRICT dst,
25 const SkPMColor* SK_RESTRICT src,
26 int count, U8CPU alpha) {
27 SkASSERT(alpha <= 255);
28 if (count > 0) {
29 unsigned src_scale = SkAlpha255To256(alpha);
30 unsigned dst_scale = 256 - src_scale;
djsollen@google.com57f49692011-02-23 20:46:31 +000031
32#ifdef UNROLL
33 if (count & 1) {
34 *dst = SkAlphaMulQ(*(src++), src_scale) + SkAlphaMulQ(*dst, dst_scale);
35 dst += 1;
36 count -= 1;
37 }
38
39 const SkPMColor* SK_RESTRICT srcEnd = src + count;
40 while (src != srcEnd) {
41 *dst = SkAlphaMulQ(*(src++), src_scale) + SkAlphaMulQ(*dst, dst_scale);
42 dst += 1;
43 *dst = SkAlphaMulQ(*(src++), src_scale) + SkAlphaMulQ(*dst, dst_scale);
44 dst += 1;
45 }
46#else
reed@android.comc4cae852009-09-23 15:06:10 +000047 do {
48 *dst = SkAlphaMulQ(*src, src_scale) + SkAlphaMulQ(*dst, dst_scale);
49 src += 1;
50 dst += 1;
51 } while (--count > 0);
djsollen@google.com57f49692011-02-23 20:46:31 +000052#endif
reed@android.comc4cae852009-09-23 15:06:10 +000053 }
54}
55
reed@android.comc4cae852009-09-23 15:06:10 +000056static void S32A_Opaque_BlitRow32(SkPMColor* SK_RESTRICT dst,
57 const SkPMColor* SK_RESTRICT src,
58 int count, U8CPU alpha) {
59 SkASSERT(255 == alpha);
60 if (count > 0) {
djsollen@google.com57f49692011-02-23 20:46:31 +000061#ifdef UNROLL
62 if (count & 1) {
63 *dst = SkPMSrcOver(*(src++), *dst);
64 dst += 1;
65 count -= 1;
66 }
67
68 const SkPMColor* SK_RESTRICT srcEnd = src + count;
69 while (src != srcEnd) {
70 *dst = SkPMSrcOver(*(src++), *dst);
71 dst += 1;
72 *dst = SkPMSrcOver(*(src++), *dst);
73 dst += 1;
74 }
75#else
reed@android.comc4cae852009-09-23 15:06:10 +000076 do {
reed@android.comc4cae852009-09-23 15:06:10 +000077 *dst = SkPMSrcOver(*src, *dst);
reed@android.comc4cae852009-09-23 15:06:10 +000078 src += 1;
79 dst += 1;
80 } while (--count > 0);
djsollen@google.com57f49692011-02-23 20:46:31 +000081#endif
reed@android.comc4cae852009-09-23 15:06:10 +000082 }
83}
84
85static void S32A_Blend_BlitRow32(SkPMColor* SK_RESTRICT dst,
86 const SkPMColor* SK_RESTRICT src,
87 int count, U8CPU alpha) {
88 SkASSERT(alpha <= 255);
89 if (count > 0) {
djsollen@google.com57f49692011-02-23 20:46:31 +000090#ifdef UNROLL
91 if (count & 1) {
92 *dst = SkBlendARGB32(*(src++), *dst, alpha);
93 dst += 1;
94 count -= 1;
95 }
96
97 const SkPMColor* SK_RESTRICT srcEnd = src + count;
98 while (src != srcEnd) {
99 *dst = SkBlendARGB32(*(src++), *dst, alpha);
100 dst += 1;
101 *dst = SkBlendARGB32(*(src++), *dst, alpha);
102 dst += 1;
103 }
104#else
reed@android.comc4cae852009-09-23 15:06:10 +0000105 do {
106 *dst = SkBlendARGB32(*src, *dst, alpha);
107 src += 1;
108 dst += 1;
109 } while (--count > 0);
djsollen@google.com57f49692011-02-23 20:46:31 +0000110#endif
reed@android.comc4cae852009-09-23 15:06:10 +0000111 }
112}
113
114///////////////////////////////////////////////////////////////////////////////
115
116static const SkBlitRow::Proc32 gDefault_Procs32[] = {
117 S32_Opaque_BlitRow32,
118 S32_Blend_BlitRow32,
119 S32A_Opaque_BlitRow32,
120 S32A_Blend_BlitRow32
121};
122
123SkBlitRow::Proc32 SkBlitRow::Factory32(unsigned flags) {
124 SkASSERT(flags < SK_ARRAY_COUNT(gDefault_Procs32));
125 // just so we don't crash
126 flags &= kFlags32_Mask;
reed@google.com981d4792011-03-09 12:55:47 +0000127
senorblanco@chromium.org92727612009-11-04 20:51:06 +0000128 SkBlitRow::Proc32 proc = PlatformProcs32(flags);
reed@android.comc4cae852009-09-23 15:06:10 +0000129 if (NULL == proc) {
130 proc = gDefault_Procs32[flags];
131 }
132 SkASSERT(proc);
133 return proc;
134}
135
senorblanco@chromium.org29e50542010-12-16 19:07:45 +0000136SkBlitRow::Proc32 SkBlitRow::ColorProcFactory() {
senorblanco@chromium.orgc3856382010-12-13 15:27:20 +0000137 SkBlitRow::ColorProc proc = PlatformColorProc();
138 if (NULL == proc) {
senorblanco@chromium.org29e50542010-12-16 19:07:45 +0000139 proc = Color32;
senorblanco@chromium.orgc3856382010-12-13 15:27:20 +0000140 }
senorblanco@chromium.org29e50542010-12-16 19:07:45 +0000141 SkASSERT(proc);
142 return proc;
senorblanco@chromium.orgc3856382010-12-13 15:27:20 +0000143}
144
reed@google.comf2068ad2011-09-13 13:56:57 +0000145void SkBlitRow::Color32(SkPMColor* SK_RESTRICT dst,
146 const SkPMColor* SK_RESTRICT src,
senorblanco@chromium.org29e50542010-12-16 19:07:45 +0000147 int count, SkPMColor color) {
reed@android.comc4cae852009-09-23 15:06:10 +0000148 if (count > 0) {
149 if (0 == color) {
150 if (src != dst) {
151 memcpy(dst, src, count * sizeof(SkPMColor));
152 }
reed@google.comc909a1e2011-10-25 19:07:23 +0000153 return;
reed@android.comc4cae852009-09-23 15:06:10 +0000154 }
155 unsigned colorA = SkGetPackedA32(color);
156 if (255 == colorA) {
157 sk_memset32(dst, color, count);
158 } else {
159 unsigned scale = 256 - SkAlpha255To256(colorA);
160 do {
161 *dst = color + SkAlphaMulQ(*src, scale);
162 src += 1;
163 dst += 1;
164 } while (--count);
165 }
166 }
167}
168
reed@google.com9f636672012-05-15 13:07:48 +0000169template <size_t N> void assignLoop(SkPMColor* dst, SkPMColor color) {
170 for (size_t i = 0; i < N; ++i) {
171 *dst++ = color;
172 }
173}
174
175static inline void assignLoop(SkPMColor dst[], SkPMColor color, int count) {
176 while (count >= 4) {
177 *dst++ = color;
178 *dst++ = color;
179 *dst++ = color;
180 *dst++ = color;
181 count -= 4;
182 }
183 if (count >= 2) {
184 *dst++ = color;
185 *dst++ = color;
186 count -= 2;
187 }
188 if (count > 0) {
189 *dst++ = color;
190 }
191}
192
tomhudson@google.com8dd90a92012-03-19 13:49:50 +0000193void SkBlitRow::ColorRect32(SkPMColor* dst, int width, int height,
194 size_t rowBytes, SkPMColor color) {
reed@google.com9f636672012-05-15 13:07:48 +0000195 if (width <= 0 || height <= 0 || 0 == color) {
196 return;
197 }
198
199 // Just made up this value, since I saw it once in a SSE2 file.
200 // We should consider writing some tests to find the optimimal break-point
201 // (or query the Platform proc?)
202 static const int MIN_WIDTH_FOR_SCANLINE_PROC = 32;
203
204 bool isOpaque = (0xFF == SkGetPackedA32(color));
205
206 if (!isOpaque || width >= MIN_WIDTH_FOR_SCANLINE_PROC) {
207 SkBlitRow::ColorProc proc = SkBlitRow::ColorProcFactory();
208 while (--height >= 0) {
209 (*proc)(dst, dst, width, color);
210 dst = (SkPMColor*) ((char*)dst + rowBytes);
211 }
212 } else {
213 switch (width) {
214 case 1:
215 while (--height >= 0) {
216 assignLoop<1>(dst, color);
217 dst = (SkPMColor*) ((char*)dst + rowBytes);
218 }
219 break;
220 case 2:
221 while (--height >= 0) {
222 assignLoop<2>(dst, color);
223 dst = (SkPMColor*) ((char*)dst + rowBytes);
224 }
225 break;
226 case 3:
227 while (--height >= 0) {
228 assignLoop<3>(dst, color);
229 dst = (SkPMColor*) ((char*)dst + rowBytes);
230 }
231 break;
232 default:
233 while (--height >= 0) {
234 assignLoop(dst, color, width);
235 dst = (SkPMColor*) ((char*)dst + rowBytes);
236 }
237 break;
238 }
tomhudson@google.com8dd90a92012-03-19 13:49:50 +0000239 }
240}
241
242SkBlitRow::ColorRectProc SkBlitRow::ColorRectProcFactory() {
243 SkBlitRow::ColorRectProc proc = PlatformColorRectProcFactory();
244 if (NULL == proc) {
245 proc = ColorRect32;
246 }
247 SkASSERT(proc);
248 return proc;
249}