blob: a0cfc33f8ab07f187913e353dfc08067dba8f05a [file] [log] [blame]
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001/* NEON optimized code (C) COPYRIGHT 2009 Motorola
caryclark@google.com6c5bf8d2012-02-17 14:08:18 +00002 *
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
5 */
reed@android.comed881c22009-09-15 14:10:42 +00006
reed@android.com8a1c16f2008-12-17 15:59:43 +00007#include "SkBitmapProcState.h"
8#include "SkPerspIter.h"
9#include "SkShader.h"
reed@android.com07d1f002009-08-13 19:35:48 +000010#include "SkUtils.h"
digit@google.comfce02ac2012-08-01 14:25:07 +000011#include "SkUtilsArm.h"
reed@android.com07d1f002009-08-13 19:35:48 +000012
reed@google.com99c114e2012-05-03 20:14:26 +000013// Helper to ensure that when we shift down, we do it w/o sign-extension
14// so the caller doesn't have to manually mask off the top 16 bits
15//
16static unsigned SK_USHIFT16(unsigned x) {
17 return x >> 16;
18}
19
reed@android.com07d1f002009-08-13 19:35:48 +000020/* returns 0...(n-1) given any x (positive or negative).
rmistry@google.comfbfcd562012-08-23 18:09:54 +000021
reed@android.com07d1f002009-08-13 19:35:48 +000022 As an example, if n (which is always positive) is 5...
rmistry@google.comfbfcd562012-08-23 18:09:54 +000023
reed@android.com07d1f002009-08-13 19:35:48 +000024 x: -8 -7 -6 -5 -4 -3 -2 -1 0 1 2 3 4 5 6 7 8
25 returns: 2 3 4 0 1 2 3 4 0 1 2 3 4 0 1 2 3
26 */
27static inline int sk_int_mod(int x, int n) {
28 SkASSERT(n > 0);
29 if ((unsigned)x >= (unsigned)n) {
30 if (x < 0) {
31 x = n + ~(~x % n);
32 } else {
33 x = x % n;
34 }
35 }
36 return x;
37}
reed@android.com8a1c16f2008-12-17 15:59:43 +000038
reed@google.com4d0078a2012-06-13 19:39:03 +000039/*
40 * The decal_ functions require that
41 * 1. dx > 0
42 * 2. [fx, fx+dx, fx+2dx, fx+3dx, ... fx+(count-1)dx] are all <= maxX
43 *
44 * In addition, we use SkFractionalInt to keep more fractional precision than
45 * just SkFixed, so we will abort the decal_ call if dx is very small, since
46 * the decal_ function just operates on SkFixed. If that were changed, we could
47 * skip the very_small test here.
48 */
49static inline bool can_truncate_to_fixed_for_decal(SkFractionalInt frX,
50 SkFractionalInt frDx,
51 int count, unsigned max) {
52 SkFixed dx = SkFractionalIntToFixed(frDx);
rmistry@google.comfbfcd562012-08-23 18:09:54 +000053
reed@google.com4d0078a2012-06-13 19:39:03 +000054 // if decal_ kept SkFractionalInt precision, this would just be dx <= 0
55 // I just made up the 1/256. Just don't want to perceive accumulated error
56 // if we truncate frDx and lose its low bits.
57 if (dx <= SK_Fixed1 / 256) {
58 return false;
59 }
60
61 // We cast to unsigned so we don't have to check for negative values, which
62 // will now appear as very large positive values, and thus fail our test!
63 SkFixed fx = SkFractionalIntToFixed(frX);
64 return (unsigned)SkFixedFloorToInt(fx) <= max &&
65 (unsigned)SkFixedFloorToInt(fx + dx * (count - 1)) < max;
66}
67
reed@android.com8a1c16f2008-12-17 15:59:43 +000068void decal_nofilter_scale(uint32_t dst[], SkFixed fx, SkFixed dx, int count);
69void decal_filter_scale(uint32_t dst[], SkFixed fx, SkFixed dx, int count);
70
digit@google.comfce02ac2012-08-01 14:25:07 +000071// Compile neon code paths if needed
72#if !SK_ARM_NEON_IS_NONE
73
74// These are defined in src/opts/SkBitmapProcState_matrixProcs_neon.cpp
75extern const SkBitmapProcState::MatrixProc ClampX_ClampY_Procs_neon[];
76extern const SkBitmapProcState::MatrixProc RepeatX_RepeatY_Procs_neon[];
77
78#endif // !SK_ARM_NEON_IS_NONE
79
80// Compile non-neon code path if needed
81#if !SK_ARM_NEON_IS_ALWAYS
reed@android.com8a1c16f2008-12-17 15:59:43 +000082#define MAKENAME(suffix) ClampX_ClampY ## suffix
reed@google.comc1992932012-05-04 12:54:20 +000083#define TILEX_PROCF(fx, max) SkClampMax((fx) >> 16, max)
84#define TILEY_PROCF(fy, max) SkClampMax((fy) >> 16, max)
reed@android.com8a1c16f2008-12-17 15:59:43 +000085#define TILEX_LOW_BITS(fx, max) (((fx) >> 12) & 0xF)
86#define TILEY_LOW_BITS(fy, max) (((fy) >> 12) & 0xF)
87#define CHECK_FOR_DECAL
digit@google.comfce02ac2012-08-01 14:25:07 +000088#include "SkBitmapProcState_matrix.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000089
90#define MAKENAME(suffix) RepeatX_RepeatY ## suffix
reed@google.com99c114e2012-05-03 20:14:26 +000091#define TILEX_PROCF(fx, max) SK_USHIFT16(((fx) & 0xFFFF) * ((max) + 1))
92#define TILEY_PROCF(fy, max) SK_USHIFT16(((fy) & 0xFFFF) * ((max) + 1))
reed@android.com8a1c16f2008-12-17 15:59:43 +000093#define TILEX_LOW_BITS(fx, max) ((((fx) & 0xFFFF) * ((max) + 1) >> 12) & 0xF)
94#define TILEY_LOW_BITS(fy, max) ((((fy) & 0xFFFF) * ((max) + 1) >> 12) & 0xF)
digit@google.comfce02ac2012-08-01 14:25:07 +000095#include "SkBitmapProcState_matrix.h"
reed@android.comed881c22009-09-15 14:10:42 +000096#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +000097
98#define MAKENAME(suffix) GeneralXY ## suffix
99#define PREAMBLE(state) SkBitmapProcState::FixedTileProc tileProcX = (state).fTileProcX; \
reed@google.comf444e8c2012-03-09 19:59:46 +0000100 SkBitmapProcState::FixedTileProc tileProcY = (state).fTileProcY; \
101 SkBitmapProcState::FixedTileLowBitsProc tileLowBitsProcX = (state).fTileLowBitsProcX; \
102 SkBitmapProcState::FixedTileLowBitsProc tileLowBitsProcY = (state).fTileLowBitsProcY
103#define PREAMBLE_PARAM_X , SkBitmapProcState::FixedTileProc tileProcX, SkBitmapProcState::FixedTileLowBitsProc tileLowBitsProcX
104#define PREAMBLE_PARAM_Y , SkBitmapProcState::FixedTileProc tileProcY, SkBitmapProcState::FixedTileLowBitsProc tileLowBitsProcY
105#define PREAMBLE_ARG_X , tileProcX, tileLowBitsProcX
106#define PREAMBLE_ARG_Y , tileProcY, tileLowBitsProcY
reed@google.com99c114e2012-05-03 20:14:26 +0000107#define TILEX_PROCF(fx, max) SK_USHIFT16(tileProcX(fx) * ((max) + 1))
108#define TILEY_PROCF(fy, max) SK_USHIFT16(tileProcY(fy) * ((max) + 1))
reed@google.comf444e8c2012-03-09 19:59:46 +0000109#define TILEX_LOW_BITS(fx, max) tileLowBitsProcX(fx, (max) + 1)
110#define TILEY_LOW_BITS(fy, max) tileLowBitsProcY(fy, (max) + 1)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000111#include "SkBitmapProcState_matrix.h"
112
113static inline U16CPU fixed_clamp(SkFixed x)
114{
115#ifdef SK_CPU_HAS_CONDITIONAL_INSTR
116 if (x >> 16)
117 x = 0xFFFF;
118 if (x < 0)
119 x = 0;
120#else
121 if (x >> 16)
122 {
123 if (x < 0)
124 x = 0;
125 else
126 x = 0xFFFF;
127 }
128#endif
129 return x;
130}
131
132static inline U16CPU fixed_repeat(SkFixed x)
133{
134 return x & 0xFFFF;
135}
136
reed@google.coma4b0d132012-04-18 20:16:18 +0000137// Visual Studio 2010 (MSC_VER=1600) optimizes bit-shift code incorrectly.
138// See http://code.google.com/p/skia/issues/detail?id=472
139#if defined(_MSC_VER) && (_MSC_VER >= 1600)
140#pragma optimize("", off)
141#endif
142
reed@android.com8a1c16f2008-12-17 15:59:43 +0000143static inline U16CPU fixed_mirror(SkFixed x)
144{
145 SkFixed s = x << 15 >> 31;
146 // s is FFFFFFFF if we're on an odd interval, or 0 if an even interval
147 return (x ^ s) & 0xFFFF;
148}
149
reed@google.coma4b0d132012-04-18 20:16:18 +0000150#if defined(_MSC_VER) && (_MSC_VER >= 1600)
151#pragma optimize("", on)
152#endif
153
reed@android.com8a1c16f2008-12-17 15:59:43 +0000154static SkBitmapProcState::FixedTileProc choose_tile_proc(unsigned m)
155{
156 if (SkShader::kClamp_TileMode == m)
157 return fixed_clamp;
158 if (SkShader::kRepeat_TileMode == m)
159 return fixed_repeat;
160 SkASSERT(SkShader::kMirror_TileMode == m);
161 return fixed_mirror;
162}
163
reed@google.comf444e8c2012-03-09 19:59:46 +0000164static inline U16CPU fixed_clamp_lowbits(SkFixed x, int) {
165 return (x >> 12) & 0xF;
166}
167
168static inline U16CPU fixed_repeat_or_mirrow_lowbits(SkFixed x, int scale) {
169 return ((x * scale) >> 12) & 0xF;
170}
171
172static SkBitmapProcState::FixedTileLowBitsProc choose_tile_lowbits_proc(unsigned m) {
173 if (SkShader::kClamp_TileMode == m) {
174 return fixed_clamp_lowbits;
175 } else {
176 SkASSERT(SkShader::kMirror_TileMode == m ||
177 SkShader::kRepeat_TileMode == m);
178 // mirror and repeat have the same behavior for the low bits.
179 return fixed_repeat_or_mirrow_lowbits;
180 }
181}
182
reed@android.com07d1f002009-08-13 19:35:48 +0000183static inline U16CPU int_clamp(int x, int n) {
184#ifdef SK_CPU_HAS_CONDITIONAL_INSTR
185 if (x >= n)
186 x = n - 1;
187 if (x < 0)
188 x = 0;
189#else
190 if ((unsigned)x >= (unsigned)n) {
191 if (x < 0) {
192 x = 0;
193 } else {
194 x = n - 1;
195 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000196 }
reed@android.com07d1f002009-08-13 19:35:48 +0000197#endif
198 return x;
199}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000200
reed@android.com07d1f002009-08-13 19:35:48 +0000201static inline U16CPU int_repeat(int x, int n) {
202 return sk_int_mod(x, n);
203}
204
205static inline U16CPU int_mirror(int x, int n) {
206 x = sk_int_mod(x, 2 * n);
207 if (x >= n) {
208 x = n + ~(x - n);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000209 }
reed@android.com07d1f002009-08-13 19:35:48 +0000210 return x;
211}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000212
reed@android.com07d1f002009-08-13 19:35:48 +0000213#if 0
214static void test_int_tileprocs() {
215 for (int i = -8; i <= 8; i++) {
216 SkDebugf(" int_mirror(%2d, 3) = %d\n", i, int_mirror(i, 3));
217 }
218}
219#endif
220
221static SkBitmapProcState::IntTileProc choose_int_tile_proc(unsigned tm) {
222 if (SkShader::kClamp_TileMode == tm)
223 return int_clamp;
224 if (SkShader::kRepeat_TileMode == tm)
225 return int_repeat;
226 SkASSERT(SkShader::kMirror_TileMode == tm);
227 return int_mirror;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000228}
229
230//////////////////////////////////////////////////////////////////////////////
231
232void decal_nofilter_scale(uint32_t dst[], SkFixed fx, SkFixed dx, int count)
233{
234 int i;
235
236 for (i = (count >> 2); i > 0; --i)
237 {
238 *dst++ = pack_two_shorts(fx >> 16, (fx + dx) >> 16);
239 fx += dx+dx;
240 *dst++ = pack_two_shorts(fx >> 16, (fx + dx) >> 16);
241 fx += dx+dx;
242 }
reed@android.comed881c22009-09-15 14:10:42 +0000243 count &= 3;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000244
reed@android.comed881c22009-09-15 14:10:42 +0000245 uint16_t* xx = (uint16_t*)dst;
246 for (i = count; i > 0; --i) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000247 *xx++ = SkToU16(fx >> 16); fx += dx;
248 }
249}
250
251void decal_filter_scale(uint32_t dst[], SkFixed fx, SkFixed dx, int count)
252{
reed@android.comed881c22009-09-15 14:10:42 +0000253
reed@android.comed881c22009-09-15 14:10:42 +0000254
reed@android.com8a1c16f2008-12-17 15:59:43 +0000255 if (count & 1)
256 {
257 SkASSERT((fx >> (16 + 14)) == 0);
258 *dst++ = (fx >> 12 << 14) | ((fx >> 16) + 1);
259 fx += dx;
260 }
261 while ((count -= 2) >= 0)
262 {
263 SkASSERT((fx >> (16 + 14)) == 0);
264 *dst++ = (fx >> 12 << 14) | ((fx >> 16) + 1);
265 fx += dx;
266
267 *dst++ = (fx >> 12 << 14) | ((fx >> 16) + 1);
268 fx += dx;
269 }
270}
271
reed@android.com07d1f002009-08-13 19:35:48 +0000272///////////////////////////////////////////////////////////////////////////////
273// stores the same as SCALE, but is cheaper to compute. Also since there is no
274// scale, we don't need/have a FILTER version
reed@android.com8a1c16f2008-12-17 15:59:43 +0000275
reed@android.com07d1f002009-08-13 19:35:48 +0000276static void fill_sequential(uint16_t xptr[], int start, int count) {
277#if 1
278 if (reinterpret_cast<intptr_t>(xptr) & 0x2) {
279 *xptr++ = start++;
280 count -= 1;
281 }
282 if (count > 3) {
283 uint32_t* xxptr = reinterpret_cast<uint32_t*>(xptr);
284 uint32_t pattern0 = PACK_TWO_SHORTS(start + 0, start + 1);
285 uint32_t pattern1 = PACK_TWO_SHORTS(start + 2, start + 3);
286 start += count & ~3;
287 int qcount = count >> 2;
288 do {
289 *xxptr++ = pattern0;
290 pattern0 += 0x40004;
291 *xxptr++ = pattern1;
292 pattern1 += 0x40004;
reed@android.com4c128c42009-08-14 13:54:37 +0000293 } while (--qcount != 0);
reed@android.com07d1f002009-08-13 19:35:48 +0000294 xptr = reinterpret_cast<uint16_t*>(xxptr);
295 count &= 3;
296 }
297 while (--count >= 0) {
298 *xptr++ = start++;
299 }
300#else
301 for (int i = 0; i < count; i++) {
302 *xptr++ = start++;
303 }
304#endif
305}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000306
reed@android.com07d1f002009-08-13 19:35:48 +0000307static int nofilter_trans_preamble(const SkBitmapProcState& s, uint32_t** xy,
308 int x, int y) {
309 SkPoint pt;
310 s.fInvProc(*s.fInvMatrix, SkIntToScalar(x) + SK_ScalarHalf,
311 SkIntToScalar(y) + SK_ScalarHalf, &pt);
312 **xy = s.fIntTileProcY(SkScalarToFixed(pt.fY) >> 16,
313 s.fBitmap->height());
314 *xy += 1; // bump the ptr
315 // return our starting X position
316 return SkScalarToFixed(pt.fX) >> 16;
317}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000318
reed@android.com07d1f002009-08-13 19:35:48 +0000319static void clampx_nofilter_trans(const SkBitmapProcState& s,
320 uint32_t xy[], int count, int x, int y) {
321 SkASSERT((s.fInvType & ~SkMatrix::kTranslate_Mask) == 0);
322
323 int xpos = nofilter_trans_preamble(s, &xy, x, y);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000324 const int width = s.fBitmap->width();
reed@android.com07d1f002009-08-13 19:35:48 +0000325 if (1 == width) {
326 // all of the following X values must be 0
327 memset(xy, 0, count * sizeof(uint16_t));
328 return;
329 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000330
reed@android.com07d1f002009-08-13 19:35:48 +0000331 uint16_t* xptr = reinterpret_cast<uint16_t*>(xy);
332 int n;
333
334 // fill before 0 as needed
335 if (xpos < 0) {
336 n = -xpos;
337 if (n > count) {
338 n = count;
339 }
340 memset(xptr, 0, n * sizeof(uint16_t));
341 count -= n;
342 if (0 == count) {
343 return;
344 }
345 xptr += n;
346 xpos = 0;
347 }
348
349 // fill in 0..width-1 if needed
350 if (xpos < width) {
351 n = width - xpos;
352 if (n > count) {
353 n = count;
354 }
355 fill_sequential(xptr, xpos, n);
356 count -= n;
357 if (0 == count) {
358 return;
359 }
360 xptr += n;
361 }
362
363 // fill the remaining with the max value
reed@android.com258cb222010-04-14 13:36:33 +0000364 sk_memset16(xptr, width - 1, count);
reed@android.com07d1f002009-08-13 19:35:48 +0000365}
366
367static void repeatx_nofilter_trans(const SkBitmapProcState& s,
368 uint32_t xy[], int count, int x, int y) {
369 SkASSERT((s.fInvType & ~SkMatrix::kTranslate_Mask) == 0);
370
371 int xpos = nofilter_trans_preamble(s, &xy, x, y);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000372 const int width = s.fBitmap->width();
reed@android.com07d1f002009-08-13 19:35:48 +0000373 if (1 == width) {
374 // all of the following X values must be 0
375 memset(xy, 0, count * sizeof(uint16_t));
376 return;
377 }
378
379 uint16_t* xptr = reinterpret_cast<uint16_t*>(xy);
380 int start = sk_int_mod(xpos, width);
381 int n = width - start;
382 if (n > count) {
383 n = count;
384 }
385 fill_sequential(xptr, start, n);
386 xptr += n;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000387 count -= n;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000388
reed@android.com07d1f002009-08-13 19:35:48 +0000389 while (count >= width) {
390 fill_sequential(xptr, 0, width);
391 xptr += width;
392 count -= width;
393 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000394
reed@android.com07d1f002009-08-13 19:35:48 +0000395 if (count > 0) {
396 fill_sequential(xptr, 0, count);
397 }
398}
399
400static void fill_backwards(uint16_t xptr[], int pos, int count) {
401 for (int i = 0; i < count; i++) {
402 SkASSERT(pos >= 0);
403 xptr[i] = pos--;
404 }
405}
406
407static void mirrorx_nofilter_trans(const SkBitmapProcState& s,
408 uint32_t xy[], int count, int x, int y) {
409 SkASSERT((s.fInvType & ~SkMatrix::kTranslate_Mask) == 0);
410
411 int xpos = nofilter_trans_preamble(s, &xy, x, y);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000412 const int width = s.fBitmap->width();
reed@android.com07d1f002009-08-13 19:35:48 +0000413 if (1 == width) {
414 // all of the following X values must be 0
415 memset(xy, 0, count * sizeof(uint16_t));
416 return;
417 }
418
419 uint16_t* xptr = reinterpret_cast<uint16_t*>(xy);
420 // need to know our start, and our initial phase (forward or backward)
421 bool forward;
422 int n;
423 int start = sk_int_mod(xpos, 2 * width);
424 if (start >= width) {
425 start = width + ~(start - width);
426 forward = false;
427 n = start + 1; // [start .. 0]
428 } else {
429 forward = true;
430 n = width - start; // [start .. width)
431 }
432 if (n > count) {
433 n = count;
434 }
435 if (forward) {
436 fill_sequential(xptr, start, n);
437 } else {
438 fill_backwards(xptr, start, n);
439 }
440 forward = !forward;
441 xptr += n;
442 count -= n;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000443
reed@android.com07d1f002009-08-13 19:35:48 +0000444 while (count >= width) {
445 if (forward) {
446 fill_sequential(xptr, 0, width);
447 } else {
448 fill_backwards(xptr, width - 1, width);
449 }
450 forward = !forward;
451 xptr += width;
452 count -= width;
453 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000454
reed@android.com07d1f002009-08-13 19:35:48 +0000455 if (count > 0) {
456 if (forward) {
457 fill_sequential(xptr, 0, count);
458 } else {
459 fill_backwards(xptr, width - 1, count);
460 }
461 }
462}
463
464///////////////////////////////////////////////////////////////////////////////
465
466SkBitmapProcState::MatrixProc
467SkBitmapProcState::chooseMatrixProc(bool trivial_matrix) {
468// test_int_tileprocs();
469 // check for our special case when there is no scale/affine/perspective
470 if (trivial_matrix) {
471 SkASSERT(!fDoFilter);
472 fIntTileProcY = choose_int_tile_proc(fTileModeY);
473 switch (fTileModeX) {
474 case SkShader::kClamp_TileMode:
475 return clampx_nofilter_trans;
476 case SkShader::kRepeat_TileMode:
477 return repeatx_nofilter_trans;
478 case SkShader::kMirror_TileMode:
479 return mirrorx_nofilter_trans;
480 }
481 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000482
reed@android.com07d1f002009-08-13 19:35:48 +0000483 int index = 0;
484 if (fDoFilter) {
485 index = 1;
486 }
487 if (fInvType & SkMatrix::kPerspective_Mask) {
488 index += 4;
489 } else if (fInvType & SkMatrix::kAffine_Mask) {
reed@android.coma2b2c4b2009-08-14 15:47:14 +0000490 index += 2;
reed@android.com07d1f002009-08-13 19:35:48 +0000491 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000492
reed@android.com07d1f002009-08-13 19:35:48 +0000493 if (SkShader::kClamp_TileMode == fTileModeX &&
494 SkShader::kClamp_TileMode == fTileModeY)
495 {
496 // clamp gets special version of filterOne
497 fFilterOneX = SK_Fixed1;
498 fFilterOneY = SK_Fixed1;
digit@google.com157d9442012-08-06 14:53:32 +0000499 return SK_ARM_NEON_WRAP(ClampX_ClampY_Procs)[index];
reed@android.com07d1f002009-08-13 19:35:48 +0000500 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000501
reed@android.com07d1f002009-08-13 19:35:48 +0000502 // all remaining procs use this form for filterOne
503 fFilterOneX = SK_Fixed1 / fBitmap->width();
504 fFilterOneY = SK_Fixed1 / fBitmap->height();
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000505
reed@android.com07d1f002009-08-13 19:35:48 +0000506 if (SkShader::kRepeat_TileMode == fTileModeX &&
507 SkShader::kRepeat_TileMode == fTileModeY)
508 {
digit@google.com157d9442012-08-06 14:53:32 +0000509 return SK_ARM_NEON_WRAP(RepeatX_RepeatY_Procs)[index];
reed@android.com07d1f002009-08-13 19:35:48 +0000510 }
digit@google.comfce02ac2012-08-01 14:25:07 +0000511
reed@android.com07d1f002009-08-13 19:35:48 +0000512 fTileProcX = choose_tile_proc(fTileModeX);
513 fTileProcY = choose_tile_proc(fTileModeY);
reed@google.comf444e8c2012-03-09 19:59:46 +0000514 fTileLowBitsProcX = choose_tile_lowbits_proc(fTileModeX);
515 fTileLowBitsProcY = choose_tile_lowbits_proc(fTileModeY);
reed@android.com07d1f002009-08-13 19:35:48 +0000516 return GeneralXY_Procs[index];
reed@android.com8a1c16f2008-12-17 15:59:43 +0000517}
518