1 /*
2 * Copyright 2008 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 // The copyright below was added in 2009, but I see no record of moto contributions...?
9
10 /* NEON optimized code (C) COPYRIGHT 2009 Motorola
11 *
12 * Use of this source code is governed by a BSD-style license that can be
13 * found in the LICENSE file.
14 */
15
16 #include "SkBitmapProcState.h"
17 #include "SkPerspIter.h"
18 #include "SkShader.h"
19 #include "SkUtils.h"
20 #include "SkUtilsArm.h"
21 #include "SkBitmapProcState_utils.h"
22
23 /* returns 0...(n-1) given any x (positive or negative).
24
25 As an example, if n (which is always positive) is 5...
26
27 x: -8 -7 -6 -5 -4 -3 -2 -1 0 1 2 3 4 5 6 7 8
28 returns: 2 3 4 0 1 2 3 4 0 1 2 3 4 0 1 2 3
29 */
sk_int_mod(int x,int n)30 static inline int sk_int_mod(int x, int n) {
31 SkASSERT(n > 0);
32 if ((unsigned)x >= (unsigned)n) {
33 if (x < 0) {
34 x = n + ~(~x % n);
35 } else {
36 x = x % n;
37 }
38 }
39 return x;
40 }
41
42 void decal_nofilter_scale(uint32_t dst[], SkFixed fx, SkFixed dx, int count);
43 void decal_filter_scale(uint32_t dst[], SkFixed fx, SkFixed dx, int count);
44
45 #include "SkBitmapProcState_matrix_template.h"
46
47 ///////////////////////////////////////////////////////////////////////////////
48
49 // Compile neon code paths if needed
50 #if defined(SK_ARM_HAS_NEON)
51
52 // These are defined in src/opts/SkBitmapProcState_matrixProcs_neon.cpp
53 extern const SkBitmapProcState::MatrixProc ClampX_ClampY_Procs_neon[];
54 extern const SkBitmapProcState::MatrixProc RepeatX_RepeatY_Procs_neon[];
55
56 #endif // defined(SK_ARM_HAS_NEON)
57
58 // Compile non-neon code path if needed
59 #if !defined(SK_ARM_HAS_NEON)
60 #define MAKENAME(suffix) ClampX_ClampY ## suffix
61 #define TILEX_PROCF(fx, max) SkClampMax((fx) >> 16, max)
62 #define TILEY_PROCF(fy, max) SkClampMax((fy) >> 16, max)
63 #define EXTRACT_LOW_BITS(v, max) (((v) >> 12) & 0xF)
64 #define CHECK_FOR_DECAL
65 #include "SkBitmapProcState_matrix.h"
66
67 struct ClampTileProcs {
XClampTileProcs68 static unsigned X(const SkBitmapProcState&, SkFixed fx, int max) {
69 return SkClampMax(fx >> 16, max);
70 }
YClampTileProcs71 static unsigned Y(const SkBitmapProcState&, SkFixed fy, int max) {
72 return SkClampMax(fy >> 16, max);
73 }
74 };
75
76 // Referenced in opts_check_x86.cpp
ClampX_ClampY_nofilter_scale(const SkBitmapProcState & s,uint32_t xy[],int count,int x,int y)77 void ClampX_ClampY_nofilter_scale(const SkBitmapProcState& s, uint32_t xy[],
78 int count, int x, int y) {
79 return NoFilterProc_Scale<ClampTileProcs, true>(s, xy, count, x, y);
80 }
ClampX_ClampY_nofilter_affine(const SkBitmapProcState & s,uint32_t xy[],int count,int x,int y)81 void ClampX_ClampY_nofilter_affine(const SkBitmapProcState& s, uint32_t xy[],
82 int count, int x, int y) {
83 return NoFilterProc_Affine<ClampTileProcs>(s, xy, count, x, y);
84 }
85
86 static SkBitmapProcState::MatrixProc ClampX_ClampY_Procs[] = {
87 // only clamp lives in the right coord space to check for decal
88 ClampX_ClampY_nofilter_scale,
89 ClampX_ClampY_filter_scale,
90 ClampX_ClampY_nofilter_affine,
91 ClampX_ClampY_filter_affine,
92 NoFilterProc_Persp<ClampTileProcs>,
93 ClampX_ClampY_filter_persp
94 };
95
96 #define MAKENAME(suffix) RepeatX_RepeatY ## suffix
97 #define TILEX_PROCF(fx, max) SK_USHIFT16((unsigned)((fx) & 0xFFFF) * ((max) + 1))
98 #define TILEY_PROCF(fy, max) SK_USHIFT16((unsigned)((fy) & 0xFFFF) * ((max) + 1))
99 #define EXTRACT_LOW_BITS(v, max) (((unsigned)((v) & 0xFFFF) * ((max) + 1) >> 12) & 0xF)
100 #include "SkBitmapProcState_matrix.h"
101
102 struct RepeatTileProcs {
XRepeatTileProcs103 static unsigned X(const SkBitmapProcState&, SkFixed fx, int max) {
104 SkASSERT(max < 65535);
105 return SK_USHIFT16((unsigned)((fx) & 0xFFFF) * ((max) + 1));
106 }
YRepeatTileProcs107 static unsigned Y(const SkBitmapProcState&, SkFixed fy, int max) {
108 SkASSERT(max < 65535);
109 return SK_USHIFT16((unsigned)((fy) & 0xFFFF) * ((max) + 1));
110 }
111 };
112
113 static SkBitmapProcState::MatrixProc RepeatX_RepeatY_Procs[] = {
114 NoFilterProc_Scale<RepeatTileProcs, false>,
115 RepeatX_RepeatY_filter_scale,
116 NoFilterProc_Affine<RepeatTileProcs>,
117 RepeatX_RepeatY_filter_affine,
118 NoFilterProc_Persp<RepeatTileProcs>,
119 RepeatX_RepeatY_filter_persp
120 };
121 #endif
122
123 #define MAKENAME(suffix) GeneralXY ## suffix
124 #define PREAMBLE(state) SkBitmapProcState::FixedTileProc tileProcX = (state).fTileProcX; (void) tileProcX; \
125 SkBitmapProcState::FixedTileProc tileProcY = (state).fTileProcY; (void) tileProcY;
126 #define PREAMBLE_PARAM_X , SkBitmapProcState::FixedTileProc tileProcX
127 #define PREAMBLE_PARAM_Y , SkBitmapProcState::FixedTileProc tileProcY
128 #define PREAMBLE_ARG_X , tileProcX
129 #define PREAMBLE_ARG_Y , tileProcY
130 #define TILEX_PROCF(fx, max) SK_USHIFT16(tileProcX(fx) * ((max) + 1))
131 #define TILEY_PROCF(fy, max) SK_USHIFT16(tileProcY(fy) * ((max) + 1))
132 #define EXTRACT_LOW_BITS(v, max) (((v * (max + 1)) >> 12) & 0xF)
133 #include "SkBitmapProcState_matrix.h"
134
135 struct GeneralTileProcs {
XGeneralTileProcs136 static unsigned X(const SkBitmapProcState& s, SkFixed fx, int max) {
137 return SK_USHIFT16(s.fTileProcX(fx) * ((max) + 1));
138 }
YGeneralTileProcs139 static unsigned Y(const SkBitmapProcState& s, SkFixed fy, int max) {
140 return SK_USHIFT16(s.fTileProcY(fy) * ((max) + 1));
141 }
142 };
143
144 static SkBitmapProcState::MatrixProc GeneralXY_Procs[] = {
145 NoFilterProc_Scale<GeneralTileProcs, false>,
146 GeneralXY_filter_scale,
147 NoFilterProc_Affine<GeneralTileProcs>,
148 GeneralXY_filter_affine,
149 NoFilterProc_Persp<GeneralTileProcs>,
150 GeneralXY_filter_persp
151 };
152
153 ///////////////////////////////////////////////////////////////////////////////
154
fixed_clamp(SkFixed x)155 static inline U16CPU fixed_clamp(SkFixed x) {
156 if (x < 0) {
157 x = 0;
158 }
159 if (x >> 16) {
160 x = 0xFFFF;
161 }
162 return x;
163 }
164
fixed_repeat(SkFixed x)165 static inline U16CPU fixed_repeat(SkFixed x) {
166 return x & 0xFFFF;
167 }
168
fixed_mirror(SkFixed x)169 static inline U16CPU fixed_mirror(SkFixed x) {
170 SkFixed s = SkLeftShift(x, 15) >> 31;
171 // s is FFFFFFFF if we're on an odd interval, or 0 if an even interval
172 return (x ^ s) & 0xFFFF;
173 }
174
choose_tile_proc(unsigned m)175 static SkBitmapProcState::FixedTileProc choose_tile_proc(unsigned m) {
176 if (SkShader::kClamp_TileMode == m) {
177 return fixed_clamp;
178 }
179 if (SkShader::kRepeat_TileMode == m) {
180 return fixed_repeat;
181 }
182 SkASSERT(SkShader::kMirror_TileMode == m);
183 return fixed_mirror;
184 }
185
int_clamp(int x,int n)186 static inline U16CPU int_clamp(int x, int n) {
187 if (x >= n) {
188 x = n - 1;
189 }
190 if (x < 0) {
191 x = 0;
192 }
193 return x;
194 }
195
int_repeat(int x,int n)196 static inline U16CPU int_repeat(int x, int n) {
197 return sk_int_mod(x, n);
198 }
199
int_mirror(int x,int n)200 static inline U16CPU int_mirror(int x, int n) {
201 x = sk_int_mod(x, 2 * n);
202 if (x >= n) {
203 x = n + ~(x - n);
204 }
205 return x;
206 }
207
208 #if 0
209 static void test_int_tileprocs() {
210 for (int i = -8; i <= 8; i++) {
211 SkDebugf(" int_mirror(%2d, 3) = %d\n", i, int_mirror(i, 3));
212 }
213 }
214 #endif
215
choose_int_tile_proc(unsigned tm)216 static SkBitmapProcState::IntTileProc choose_int_tile_proc(unsigned tm) {
217 if (SkShader::kClamp_TileMode == tm)
218 return int_clamp;
219 if (SkShader::kRepeat_TileMode == tm)
220 return int_repeat;
221 SkASSERT(SkShader::kMirror_TileMode == tm);
222 return int_mirror;
223 }
224
225 //////////////////////////////////////////////////////////////////////////////
226
decal_nofilter_scale(uint32_t dst[],SkFixed fx,SkFixed dx,int count)227 void decal_nofilter_scale(uint32_t dst[], SkFixed fx, SkFixed dx, int count) {
228 int i;
229
230 for (i = (count >> 2); i > 0; --i) {
231 *dst++ = pack_two_shorts(fx >> 16, (fx + dx) >> 16);
232 fx += dx+dx;
233 *dst++ = pack_two_shorts(fx >> 16, (fx + dx) >> 16);
234 fx += dx+dx;
235 }
236 count &= 3;
237
238 uint16_t* xx = (uint16_t*)dst;
239 for (i = count; i > 0; --i) {
240 *xx++ = SkToU16(fx >> 16); fx += dx;
241 }
242 }
243
decal_filter_scale(uint32_t dst[],SkFixed fx,SkFixed dx,int count)244 void decal_filter_scale(uint32_t dst[], SkFixed fx, SkFixed dx, int count) {
245 if (count & 1) {
246 SkASSERT((fx >> (16 + 14)) == 0);
247 *dst++ = (fx >> 12 << 14) | ((fx >> 16) + 1);
248 fx += dx;
249 }
250 while ((count -= 2) >= 0) {
251 SkASSERT((fx >> (16 + 14)) == 0);
252 *dst++ = (fx >> 12 << 14) | ((fx >> 16) + 1);
253 fx += dx;
254
255 *dst++ = (fx >> 12 << 14) | ((fx >> 16) + 1);
256 fx += dx;
257 }
258 }
259
260 ///////////////////////////////////////////////////////////////////////////////
261 // stores the same as SCALE, but is cheaper to compute. Also since there is no
262 // scale, we don't need/have a FILTER version
263
fill_sequential(uint16_t xptr[],int start,int count)264 static void fill_sequential(uint16_t xptr[], int start, int count) {
265 #if 1
266 if (reinterpret_cast<intptr_t>(xptr) & 0x2) {
267 *xptr++ = start++;
268 count -= 1;
269 }
270 if (count > 3) {
271 uint32_t* xxptr = reinterpret_cast<uint32_t*>(xptr);
272 uint32_t pattern0 = PACK_TWO_SHORTS(start + 0, start + 1);
273 uint32_t pattern1 = PACK_TWO_SHORTS(start + 2, start + 3);
274 start += count & ~3;
275 int qcount = count >> 2;
276 do {
277 *xxptr++ = pattern0;
278 pattern0 += 0x40004;
279 *xxptr++ = pattern1;
280 pattern1 += 0x40004;
281 } while (--qcount != 0);
282 xptr = reinterpret_cast<uint16_t*>(xxptr);
283 count &= 3;
284 }
285 while (--count >= 0) {
286 *xptr++ = start++;
287 }
288 #else
289 for (int i = 0; i < count; i++) {
290 *xptr++ = start++;
291 }
292 #endif
293 }
294
nofilter_trans_preamble(const SkBitmapProcState & s,uint32_t ** xy,int x,int y)295 static int nofilter_trans_preamble(const SkBitmapProcState& s, uint32_t** xy,
296 int x, int y) {
297 const SkBitmapProcStateAutoMapper mapper(s, x, y);
298 **xy = s.fIntTileProcY(mapper.intY(), s.fPixmap.height());
299 *xy += 1; // bump the ptr
300 // return our starting X position
301 return mapper.intX();
302 }
303
clampx_nofilter_trans(const SkBitmapProcState & s,uint32_t xy[],int count,int x,int y)304 static void clampx_nofilter_trans(const SkBitmapProcState& s,
305 uint32_t xy[], int count, int x, int y) {
306 SkASSERT((s.fInvType & ~SkMatrix::kTranslate_Mask) == 0);
307
308 int xpos = nofilter_trans_preamble(s, &xy, x, y);
309 const int width = s.fPixmap.width();
310 if (1 == width) {
311 // all of the following X values must be 0
312 memset(xy, 0, count * sizeof(uint16_t));
313 return;
314 }
315
316 uint16_t* xptr = reinterpret_cast<uint16_t*>(xy);
317 int n;
318
319 // fill before 0 as needed
320 if (xpos < 0) {
321 n = -xpos;
322 if (n > count) {
323 n = count;
324 }
325 memset(xptr, 0, n * sizeof(uint16_t));
326 count -= n;
327 if (0 == count) {
328 return;
329 }
330 xptr += n;
331 xpos = 0;
332 }
333
334 // fill in 0..width-1 if needed
335 if (xpos < width) {
336 n = width - xpos;
337 if (n > count) {
338 n = count;
339 }
340 fill_sequential(xptr, xpos, n);
341 count -= n;
342 if (0 == count) {
343 return;
344 }
345 xptr += n;
346 }
347
348 // fill the remaining with the max value
349 sk_memset16(xptr, width - 1, count);
350 }
351
repeatx_nofilter_trans(const SkBitmapProcState & s,uint32_t xy[],int count,int x,int y)352 static void repeatx_nofilter_trans(const SkBitmapProcState& s,
353 uint32_t xy[], int count, int x, int y) {
354 SkASSERT((s.fInvType & ~SkMatrix::kTranslate_Mask) == 0);
355
356 int xpos = nofilter_trans_preamble(s, &xy, x, y);
357 const int width = s.fPixmap.width();
358 if (1 == width) {
359 // all of the following X values must be 0
360 memset(xy, 0, count * sizeof(uint16_t));
361 return;
362 }
363
364 uint16_t* xptr = reinterpret_cast<uint16_t*>(xy);
365 int start = sk_int_mod(xpos, width);
366 int n = width - start;
367 if (n > count) {
368 n = count;
369 }
370 fill_sequential(xptr, start, n);
371 xptr += n;
372 count -= n;
373
374 while (count >= width) {
375 fill_sequential(xptr, 0, width);
376 xptr += width;
377 count -= width;
378 }
379
380 if (count > 0) {
381 fill_sequential(xptr, 0, count);
382 }
383 }
384
fill_backwards(uint16_t xptr[],int pos,int count)385 static void fill_backwards(uint16_t xptr[], int pos, int count) {
386 for (int i = 0; i < count; i++) {
387 SkASSERT(pos >= 0);
388 xptr[i] = pos--;
389 }
390 }
391
mirrorx_nofilter_trans(const SkBitmapProcState & s,uint32_t xy[],int count,int x,int y)392 static void mirrorx_nofilter_trans(const SkBitmapProcState& s,
393 uint32_t xy[], int count, int x, int y) {
394 SkASSERT((s.fInvType & ~SkMatrix::kTranslate_Mask) == 0);
395
396 int xpos = nofilter_trans_preamble(s, &xy, x, y);
397 const int width = s.fPixmap.width();
398 if (1 == width) {
399 // all of the following X values must be 0
400 memset(xy, 0, count * sizeof(uint16_t));
401 return;
402 }
403
404 uint16_t* xptr = reinterpret_cast<uint16_t*>(xy);
405 // need to know our start, and our initial phase (forward or backward)
406 bool forward;
407 int n;
408 int start = sk_int_mod(xpos, 2 * width);
409 if (start >= width) {
410 start = width + ~(start - width);
411 forward = false;
412 n = start + 1; // [start .. 0]
413 } else {
414 forward = true;
415 n = width - start; // [start .. width)
416 }
417 if (n > count) {
418 n = count;
419 }
420 if (forward) {
421 fill_sequential(xptr, start, n);
422 } else {
423 fill_backwards(xptr, start, n);
424 }
425 forward = !forward;
426 xptr += n;
427 count -= n;
428
429 while (count >= width) {
430 if (forward) {
431 fill_sequential(xptr, 0, width);
432 } else {
433 fill_backwards(xptr, width - 1, width);
434 }
435 forward = !forward;
436 xptr += width;
437 count -= width;
438 }
439
440 if (count > 0) {
441 if (forward) {
442 fill_sequential(xptr, 0, count);
443 } else {
444 fill_backwards(xptr, width - 1, count);
445 }
446 }
447 }
448
449 ///////////////////////////////////////////////////////////////////////////////
450
chooseMatrixProc(bool trivial_matrix)451 SkBitmapProcState::MatrixProc SkBitmapProcState::chooseMatrixProc(bool trivial_matrix) {
452 // test_int_tileprocs();
453 // check for our special case when there is no scale/affine/perspective
454 if (trivial_matrix && kNone_SkFilterQuality == fFilterQuality) {
455 fIntTileProcY = choose_int_tile_proc(fTileModeY);
456 switch (fTileModeX) {
457 case SkShader::kClamp_TileMode:
458 return clampx_nofilter_trans;
459 case SkShader::kRepeat_TileMode:
460 return repeatx_nofilter_trans;
461 case SkShader::kMirror_TileMode:
462 return mirrorx_nofilter_trans;
463 }
464 }
465
466 int index = 0;
467 if (fFilterQuality != kNone_SkFilterQuality) {
468 index = 1;
469 }
470 if (fInvType & SkMatrix::kPerspective_Mask) {
471 index += 4;
472 } else if (fInvType & SkMatrix::kAffine_Mask) {
473 index += 2;
474 }
475
476 if (SkShader::kClamp_TileMode == fTileModeX && SkShader::kClamp_TileMode == fTileModeY) {
477 // clamp gets special version of filterOne
478 fFilterOneX = SK_Fixed1;
479 fFilterOneY = SK_Fixed1;
480 return SK_ARM_NEON_WRAP(ClampX_ClampY_Procs)[index];
481 }
482
483 // all remaining procs use this form for filterOne
484 fFilterOneX = SK_Fixed1 / fPixmap.width();
485 fFilterOneY = SK_Fixed1 / fPixmap.height();
486
487 if (SkShader::kRepeat_TileMode == fTileModeX && SkShader::kRepeat_TileMode == fTileModeY) {
488 return SK_ARM_NEON_WRAP(RepeatX_RepeatY_Procs)[index];
489 }
490
491 fTileProcX = choose_tile_proc(fTileModeX);
492 fTileProcY = choose_tile_proc(fTileModeY);
493 return GeneralXY_Procs[index];
494 }
495