• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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