blob: 5ea780e9b7577758850740c0bb04b5ee6cb57eac [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
reed@google.com69d05552011-05-24 12:14:28 +00002/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00003 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
reed@google.com69d05552011-05-24 12:14:28 +00007 */
8
tomhudson@google.com889bd8b2011-09-27 17:38:17 +00009#include "SkMath.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000010
11#define SCALE_NOFILTER_NAME MAKENAME(_nofilter_scale)
12#define SCALE_FILTER_NAME MAKENAME(_filter_scale)
13#define AFFINE_NOFILTER_NAME MAKENAME(_nofilter_affine)
14#define AFFINE_FILTER_NAME MAKENAME(_filter_affine)
15#define PERSP_NOFILTER_NAME MAKENAME(_nofilter_persp)
16#define PERSP_FILTER_NAME MAKENAME(_filter_persp)
17
18#define PACK_FILTER_X_NAME MAKENAME(_pack_filter_x)
19#define PACK_FILTER_Y_NAME MAKENAME(_pack_filter_y)
20
21#ifndef PREAMBLE
22 #define PREAMBLE(state)
23 #define PREAMBLE_PARAM_X
24 #define PREAMBLE_PARAM_Y
25 #define PREAMBLE_ARG_X
26 #define PREAMBLE_ARG_Y
27#endif
28
caryclark@google.com803eceb2012-06-06 12:09:34 +000029// declare functions externally to suppress warnings.
30void SCALE_NOFILTER_NAME(const SkBitmapProcState& s,
31 uint32_t xy[], int count, int x, int y);
32void AFFINE_NOFILTER_NAME(const SkBitmapProcState& s,
33 uint32_t xy[], int count, int x, int y);
34void PERSP_NOFILTER_NAME(const SkBitmapProcState& s,
35 uint32_t* SK_RESTRICT xy,
36 int count, int x, int y);
37void SCALE_FILTER_NAME(const SkBitmapProcState& s,
38 uint32_t xy[], int count, int x, int y);
39void AFFINE_FILTER_NAME(const SkBitmapProcState& s,
40 uint32_t xy[], int count, int x, int y);
41void PERSP_FILTER_NAME(const SkBitmapProcState& s,
42 uint32_t* SK_RESTRICT xy, int count,
43 int x, int y);
44
senorblanco@chromium.orgdc7de742009-11-30 20:00:29 +000045void SCALE_NOFILTER_NAME(const SkBitmapProcState& s,
reed@android.com8a1c16f2008-12-17 15:59:43 +000046 uint32_t xy[], int count, int x, int y) {
47 SkASSERT((s.fInvType & ~(SkMatrix::kTranslate_Mask |
48 SkMatrix::kScale_Mask)) == 0);
49
50 PREAMBLE(s);
51 // we store y, x, x, x, x, x
52
53 const unsigned maxX = s.fBitmap->width() - 1;
reed@google.com4bc0a9d2012-03-07 21:47:41 +000054 SkFractionalInt fx;
reed@android.com8a1c16f2008-12-17 15:59:43 +000055 {
56 SkPoint pt;
57 s.fInvProc(*s.fInvMatrix, SkIntToScalar(x) + SK_ScalarHalf,
58 SkIntToScalar(y) + SK_ScalarHalf, &pt);
reed@google.com4bc0a9d2012-03-07 21:47:41 +000059 fx = SkScalarToFractionalInt(pt.fY);
reed@android.com8a1c16f2008-12-17 15:59:43 +000060 const unsigned maxY = s.fBitmap->height() - 1;
reed@google.com4bc0a9d2012-03-07 21:47:41 +000061 *xy++ = TILEY_PROCF(SkFractionalIntToFixed(fx), maxY);
62 fx = SkScalarToFractionalInt(pt.fX);
reed@android.com8a1c16f2008-12-17 15:59:43 +000063 }
reed@android.com0becfc5b2009-01-13 13:26:44 +000064
65 if (0 == maxX) {
66 // all of the following X values must be 0
67 memset(xy, 0, count * sizeof(uint16_t));
68 return;
69 }
70
reed@google.com4bc0a9d2012-03-07 21:47:41 +000071 const SkFractionalInt dx = s.fInvSxFractionalInt;
reed@android.com8a1c16f2008-12-17 15:59:43 +000072
73#ifdef CHECK_FOR_DECAL
74 // test if we don't need to apply the tile proc
reed@google.com4bc0a9d2012-03-07 21:47:41 +000075 SkFixed tmpFx = SkFractionalIntToFixed(fx);
76 SkFixed tmpDx = SkFractionalIntToFixed(dx);
77 if ((unsigned)(tmpFx >> 16) <= maxX &&
78 (unsigned)((tmpFx + tmpDx * (count - 1)) >> 16) <= maxX) {
79 decal_nofilter_scale(xy, tmpFx, tmpDx, count);
reed@android.com8a1c16f2008-12-17 15:59:43 +000080 } else
81#endif
82 {
83 int i;
84 for (i = (count >> 2); i > 0; --i) {
85 unsigned a, b;
reed@google.com4bc0a9d2012-03-07 21:47:41 +000086 a = TILEX_PROCF(SkFractionalIntToFixed(fx), maxX); fx += dx;
87 b = TILEX_PROCF(SkFractionalIntToFixed(fx), maxX); fx += dx;
reed@android.com8a1c16f2008-12-17 15:59:43 +000088#ifdef SK_CPU_BENDIAN
89 *xy++ = (a << 16) | b;
90#else
91 *xy++ = (b << 16) | a;
92#endif
reed@google.com4bc0a9d2012-03-07 21:47:41 +000093 a = TILEX_PROCF(SkFractionalIntToFixed(fx), maxX); fx += dx;
94 b = TILEX_PROCF(SkFractionalIntToFixed(fx), maxX); fx += dx;
reed@android.com8a1c16f2008-12-17 15:59:43 +000095#ifdef SK_CPU_BENDIAN
96 *xy++ = (a << 16) | b;
97#else
98 *xy++ = (b << 16) | a;
99#endif
100 }
101 uint16_t* xx = (uint16_t*)xy;
102 for (i = (count & 3); i > 0; --i) {
reed@google.com4bc0a9d2012-03-07 21:47:41 +0000103 *xx++ = TILEX_PROCF(SkFractionalIntToFixed(fx), maxX); fx += dx;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000104 }
105 }
106}
107
108// note: we could special-case on a matrix which is skewed in X but not Y.
109// this would require a more general setup thatn SCALE does, but could use
110// SCALE's inner loop that only looks at dx
111
senorblanco@chromium.orgdc7de742009-11-30 20:00:29 +0000112void AFFINE_NOFILTER_NAME(const SkBitmapProcState& s,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000113 uint32_t xy[], int count, int x, int y) {
114 SkASSERT(s.fInvType & SkMatrix::kAffine_Mask);
115 SkASSERT((s.fInvType & ~(SkMatrix::kTranslate_Mask |
116 SkMatrix::kScale_Mask |
117 SkMatrix::kAffine_Mask)) == 0);
118
119 PREAMBLE(s);
120 SkPoint srcPt;
121 s.fInvProc(*s.fInvMatrix,
122 SkIntToScalar(x) + SK_ScalarHalf,
123 SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
reed@google.com4bc0a9d2012-03-07 21:47:41 +0000124
125 SkFractionalInt fx = SkScalarToFractionalInt(srcPt.fX);
126 SkFractionalInt fy = SkScalarToFractionalInt(srcPt.fY);
reed@google.com411215a2012-03-08 20:13:46 +0000127 SkFractionalInt dx = s.fInvSxFractionalInt;
128 SkFractionalInt dy = s.fInvKyFractionalInt;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000129 int maxX = s.fBitmap->width() - 1;
130 int maxY = s.fBitmap->height() - 1;
131
132 for (int i = count; i > 0; --i) {
reed@google.com411215a2012-03-08 20:13:46 +0000133 *xy++ = (TILEY_PROCF(SkFractionalIntToFixed(fy), maxY) << 16) |
reed@google.com4bc0a9d2012-03-07 21:47:41 +0000134 TILEX_PROCF(SkFractionalIntToFixed(fx), maxX);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000135 fx += dx; fy += dy;
136 }
137}
138
senorblanco@chromium.orgdc7de742009-11-30 20:00:29 +0000139void PERSP_NOFILTER_NAME(const SkBitmapProcState& s,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000140 uint32_t* SK_RESTRICT xy,
141 int count, int x, int y) {
142 SkASSERT(s.fInvType & SkMatrix::kPerspective_Mask);
143
144 PREAMBLE(s);
145 int maxX = s.fBitmap->width() - 1;
146 int maxY = s.fBitmap->height() - 1;
147
148 SkPerspIter iter(*s.fInvMatrix,
149 SkIntToScalar(x) + SK_ScalarHalf,
150 SkIntToScalar(y) + SK_ScalarHalf, count);
151
152 while ((count = iter.next()) != 0) {
153 const SkFixed* SK_RESTRICT srcXY = iter.getXY();
154 while (--count >= 0) {
155 *xy++ = (TILEY_PROCF(srcXY[1], maxY) << 16) |
156 TILEX_PROCF(srcXY[0], maxX);
157 srcXY += 2;
158 }
159 }
160}
161
162//////////////////////////////////////////////////////////////////////////////
163
164static inline uint32_t PACK_FILTER_Y_NAME(SkFixed f, unsigned max,
165 SkFixed one PREAMBLE_PARAM_Y) {
166 unsigned i = TILEY_PROCF(f, max);
167 i = (i << 4) | TILEY_LOW_BITS(f, max);
168 return (i << 14) | (TILEY_PROCF((f + one), max));
169}
170
171static inline uint32_t PACK_FILTER_X_NAME(SkFixed f, unsigned max,
172 SkFixed one PREAMBLE_PARAM_X) {
173 unsigned i = TILEX_PROCF(f, max);
174 i = (i << 4) | TILEX_LOW_BITS(f, max);
175 return (i << 14) | (TILEX_PROCF((f + one), max));
176}
177
senorblanco@chromium.orgdc7de742009-11-30 20:00:29 +0000178void SCALE_FILTER_NAME(const SkBitmapProcState& s,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000179 uint32_t xy[], int count, int x, int y) {
180 SkASSERT((s.fInvType & ~(SkMatrix::kTranslate_Mask |
181 SkMatrix::kScale_Mask)) == 0);
182 SkASSERT(s.fInvKy == 0);
183
184 PREAMBLE(s);
185
186 const unsigned maxX = s.fBitmap->width() - 1;
187 const SkFixed one = s.fFilterOneX;
reed@google.com411215a2012-03-08 20:13:46 +0000188 const SkFractionalInt dx = s.fInvSxFractionalInt;
189 SkFractionalInt fx;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000190
191 {
192 SkPoint pt;
193 s.fInvProc(*s.fInvMatrix, SkIntToScalar(x) + SK_ScalarHalf,
194 SkIntToScalar(y) + SK_ScalarHalf, &pt);
195 const SkFixed fy = SkScalarToFixed(pt.fY) - (s.fFilterOneY >> 1);
196 const unsigned maxY = s.fBitmap->height() - 1;
197 // compute our two Y values up front
198 *xy++ = PACK_FILTER_Y_NAME(fy, maxY, s.fFilterOneY PREAMBLE_ARG_Y);
199 // now initialize fx
reed@google.com411215a2012-03-08 20:13:46 +0000200 fx = SkScalarToFractionalInt(pt.fX) - (SkFixedToFractionalInt(one) >> 1);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000201 }
202
203#ifdef CHECK_FOR_DECAL
204 // test if we don't need to apply the tile proc
205 if (dx > 0 &&
206 (unsigned)(fx >> 16) <= maxX &&
207 (unsigned)((fx + dx * (count - 1)) >> 16) < maxX) {
caryclark@google.com803eceb2012-06-06 12:09:34 +0000208 decal_filter_scale(xy, (SkFixed) fx, (SkFixed) dx, count);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000209 } else
210#endif
211 {
212 do {
reed@google.com411215a2012-03-08 20:13:46 +0000213 SkFixed fixedFx = SkFractionalIntToFixed(fx);
214 *xy++ = PACK_FILTER_X_NAME(fixedFx, maxX, one PREAMBLE_ARG_X);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000215 fx += dx;
216 } while (--count != 0);
217 }
218}
219
senorblanco@chromium.orgdc7de742009-11-30 20:00:29 +0000220void AFFINE_FILTER_NAME(const SkBitmapProcState& s,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000221 uint32_t xy[], int count, int x, int y) {
222 SkASSERT(s.fInvType & SkMatrix::kAffine_Mask);
223 SkASSERT((s.fInvType & ~(SkMatrix::kTranslate_Mask |
224 SkMatrix::kScale_Mask |
225 SkMatrix::kAffine_Mask)) == 0);
226
227 PREAMBLE(s);
228 SkPoint srcPt;
229 s.fInvProc(*s.fInvMatrix,
230 SkIntToScalar(x) + SK_ScalarHalf,
231 SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
232
233 SkFixed oneX = s.fFilterOneX;
234 SkFixed oneY = s.fFilterOneY;
235 SkFixed fx = SkScalarToFixed(srcPt.fX) - (oneX >> 1);
236 SkFixed fy = SkScalarToFixed(srcPt.fY) - (oneY >> 1);
237 SkFixed dx = s.fInvSx;
238 SkFixed dy = s.fInvKy;
239 unsigned maxX = s.fBitmap->width() - 1;
240 unsigned maxY = s.fBitmap->height() - 1;
241
242 do {
243 *xy++ = PACK_FILTER_Y_NAME(fy, maxY, oneY PREAMBLE_ARG_Y);
244 fy += dy;
245 *xy++ = PACK_FILTER_X_NAME(fx, maxX, oneX PREAMBLE_ARG_X);
246 fx += dx;
247 } while (--count != 0);
248}
249
senorblanco@chromium.orgdc7de742009-11-30 20:00:29 +0000250void PERSP_FILTER_NAME(const SkBitmapProcState& s,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000251 uint32_t* SK_RESTRICT xy, int count,
252 int x, int y) {
253 SkASSERT(s.fInvType & SkMatrix::kPerspective_Mask);
254
255 PREAMBLE(s);
256 unsigned maxX = s.fBitmap->width() - 1;
257 unsigned maxY = s.fBitmap->height() - 1;
258 SkFixed oneX = s.fFilterOneX;
259 SkFixed oneY = s.fFilterOneY;
260
261 SkPerspIter iter(*s.fInvMatrix,
262 SkIntToScalar(x) + SK_ScalarHalf,
263 SkIntToScalar(y) + SK_ScalarHalf, count);
264
265 while ((count = iter.next()) != 0) {
266 const SkFixed* SK_RESTRICT srcXY = iter.getXY();
267 do {
268 *xy++ = PACK_FILTER_Y_NAME(srcXY[1] - (oneY >> 1), maxY,
269 oneY PREAMBLE_ARG_Y);
270 *xy++ = PACK_FILTER_X_NAME(srcXY[0] - (oneX >> 1), maxX,
271 oneX PREAMBLE_ARG_X);
272 srcXY += 2;
273 } while (--count != 0);
274 }
275}
276
277static SkBitmapProcState::MatrixProc MAKENAME(_Procs)[] = {
278 SCALE_NOFILTER_NAME,
279 SCALE_FILTER_NAME,
280 AFFINE_NOFILTER_NAME,
281 AFFINE_FILTER_NAME,
282 PERSP_NOFILTER_NAME,
283 PERSP_FILTER_NAME
284};
285
286#undef MAKENAME
287#undef TILEX_PROCF
288#undef TILEY_PROCF
289#ifdef CHECK_FOR_DECAL
290 #undef CHECK_FOR_DECAL
291#endif
292
293#undef SCALE_NOFILTER_NAME
294#undef SCALE_FILTER_NAME
295#undef AFFINE_NOFILTER_NAME
296#undef AFFINE_FILTER_NAME
297#undef PERSP_NOFILTER_NAME
298#undef PERSP_FILTER_NAME
299
300#undef PREAMBLE
301#undef PREAMBLE_PARAM_X
302#undef PREAMBLE_PARAM_Y
303#undef PREAMBLE_ARG_X
304#undef PREAMBLE_ARG_Y
305
306#undef TILEX_LOW_BITS
307#undef TILEY_LOW_BITS