Line data Source code
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 : */
30 680 : static inline int sk_int_mod(int x, int n) {
31 680 : SkASSERT(n > 0);
32 680 : if ((unsigned)x >= (unsigned)n) {
33 306 : if (x < 0) {
34 0 : x = n + ~(~x % n);
35 : } else {
36 306 : x = x % n;
37 : }
38 : }
39 680 : 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 {
68 0 : static unsigned X(const SkBitmapProcState&, SkFixed fx, int max) {
69 0 : return SkClampMax(fx >> 16, max);
70 : }
71 0 : static unsigned Y(const SkBitmapProcState&, SkFixed fy, int max) {
72 0 : return SkClampMax(fy >> 16, max);
73 : }
74 : };
75 :
76 : // Referenced in opts_check_x86.cpp
77 0 : void ClampX_ClampY_nofilter_scale(const SkBitmapProcState& s, uint32_t xy[],
78 : int count, int x, int y) {
79 0 : return NoFilterProc_Scale<ClampTileProcs, true>(s, xy, count, x, y);
80 : }
81 0 : void ClampX_ClampY_nofilter_affine(const SkBitmapProcState& s, uint32_t xy[],
82 : int count, int x, int y) {
83 0 : 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 {
103 0 : static unsigned X(const SkBitmapProcState&, SkFixed fx, int max) {
104 0 : SkASSERT(max < 65535);
105 0 : return SK_USHIFT16((unsigned)((fx) & 0xFFFF) * ((max) + 1));
106 : }
107 0 : static unsigned Y(const SkBitmapProcState&, SkFixed fy, int max) {
108 0 : SkASSERT(max < 65535);
109 0 : 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 {
136 0 : static unsigned X(const SkBitmapProcState& s, SkFixed fx, int max) {
137 0 : return SK_USHIFT16(s.fTileProcX(fx) * ((max) + 1));
138 : }
139 0 : static unsigned Y(const SkBitmapProcState& s, SkFixed fy, int max) {
140 0 : 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 :
155 0 : static inline U16CPU fixed_clamp(SkFixed x) {
156 0 : if (x < 0) {
157 0 : x = 0;
158 : }
159 0 : if (x >> 16) {
160 0 : x = 0xFFFF;
161 : }
162 0 : return x;
163 : }
164 :
165 0 : static inline U16CPU fixed_repeat(SkFixed x) {
166 0 : return x & 0xFFFF;
167 : }
168 :
169 0 : static inline U16CPU fixed_mirror(SkFixed x) {
170 0 : SkFixed s = SkLeftShift(x, 15) >> 31;
171 : // s is FFFFFFFF if we're on an odd interval, or 0 if an even interval
172 0 : return (x ^ s) & 0xFFFF;
173 : }
174 :
175 0 : static SkBitmapProcState::FixedTileProc choose_tile_proc(unsigned m) {
176 0 : if (SkShader::kClamp_TileMode == m) {
177 0 : return fixed_clamp;
178 : }
179 0 : if (SkShader::kRepeat_TileMode == m) {
180 0 : return fixed_repeat;
181 : }
182 0 : SkASSERT(SkShader::kMirror_TileMode == m);
183 0 : return fixed_mirror;
184 : }
185 :
186 1104 : static inline U16CPU int_clamp(int x, int n) {
187 1104 : if (x >= n) {
188 0 : x = n - 1;
189 : }
190 1104 : if (x < 0) {
191 0 : x = 0;
192 : }
193 1104 : return x;
194 : }
195 :
196 0 : static inline U16CPU int_repeat(int x, int n) {
197 0 : return sk_int_mod(x, n);
198 : }
199 :
200 0 : static inline U16CPU int_mirror(int x, int n) {
201 0 : x = sk_int_mod(x, 2 * n);
202 0 : if (x >= n) {
203 0 : x = n + ~(x - n);
204 : }
205 0 : 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 :
216 99 : static SkBitmapProcState::IntTileProc choose_int_tile_proc(unsigned tm) {
217 99 : if (SkShader::kClamp_TileMode == tm)
218 81 : return int_clamp;
219 18 : if (SkShader::kRepeat_TileMode == tm)
220 18 : return int_repeat;
221 0 : SkASSERT(SkShader::kMirror_TileMode == tm);
222 0 : return int_mirror;
223 : }
224 :
225 : //////////////////////////////////////////////////////////////////////////////
226 :
227 0 : void decal_nofilter_scale(uint32_t dst[], SkFixed fx, SkFixed dx, int count) {
228 : int i;
229 :
230 0 : for (i = (count >> 2); i > 0; --i) {
231 0 : *dst++ = pack_two_shorts(fx >> 16, (fx + dx) >> 16);
232 0 : fx += dx+dx;
233 0 : *dst++ = pack_two_shorts(fx >> 16, (fx + dx) >> 16);
234 0 : fx += dx+dx;
235 : }
236 0 : count &= 3;
237 :
238 0 : uint16_t* xx = (uint16_t*)dst;
239 0 : for (i = count; i > 0; --i) {
240 0 : *xx++ = SkToU16(fx >> 16); fx += dx;
241 : }
242 0 : }
243 :
244 0 : void decal_filter_scale(uint32_t dst[], SkFixed fx, SkFixed dx, int count) {
245 0 : if (count & 1) {
246 0 : SkASSERT((fx >> (16 + 14)) == 0);
247 0 : *dst++ = (fx >> 12 << 14) | ((fx >> 16) + 1);
248 0 : fx += dx;
249 : }
250 0 : while ((count -= 2) >= 0) {
251 0 : SkASSERT((fx >> (16 + 14)) == 0);
252 0 : *dst++ = (fx >> 12 << 14) | ((fx >> 16) + 1);
253 0 : fx += dx;
254 :
255 0 : *dst++ = (fx >> 12 << 14) | ((fx >> 16) + 1);
256 0 : fx += dx;
257 : }
258 0 : }
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 :
264 9222 : static void fill_sequential(uint16_t xptr[], int start, int count) {
265 : #if 1
266 9222 : if (reinterpret_cast<intptr_t>(xptr) & 0x2) {
267 1018 : *xptr++ = start++;
268 1018 : count -= 1;
269 : }
270 9222 : if (count > 3) {
271 8912 : uint32_t* xxptr = reinterpret_cast<uint32_t*>(xptr);
272 8912 : uint32_t pattern0 = PACK_TWO_SHORTS(start + 0, start + 1);
273 8912 : uint32_t pattern1 = PACK_TWO_SHORTS(start + 2, start + 3);
274 8912 : start += count & ~3;
275 8912 : int qcount = count >> 2;
276 28968 : do {
277 28968 : *xxptr++ = pattern0;
278 28968 : pattern0 += 0x40004;
279 28968 : *xxptr++ = pattern1;
280 28968 : pattern1 += 0x40004;
281 : } while (--qcount != 0);
282 8912 : xptr = reinterpret_cast<uint16_t*>(xxptr);
283 8912 : count &= 3;
284 : }
285 17746 : while (--count >= 0) {
286 4262 : *xptr++ = start++;
287 : }
288 : #else
289 : for (int i = 0; i < count; i++) {
290 : *xptr++ = start++;
291 : }
292 : #endif
293 9222 : }
294 :
295 1104 : static int nofilter_trans_preamble(const SkBitmapProcState& s, uint32_t** xy,
296 : int x, int y) {
297 1104 : const SkBitmapProcStateAutoMapper mapper(s, x, y);
298 1104 : **xy = s.fIntTileProcY(mapper.intY(), s.fPixmap.height());
299 1104 : *xy += 1; // bump the ptr
300 : // return our starting X position
301 1104 : return mapper.intX();
302 : }
303 :
304 424 : static void clampx_nofilter_trans(const SkBitmapProcState& s,
305 : uint32_t xy[], int count, int x, int y) {
306 424 : SkASSERT((s.fInvType & ~SkMatrix::kTranslate_Mask) == 0);
307 :
308 424 : int xpos = nofilter_trans_preamble(s, &xy, x, y);
309 424 : const int width = s.fPixmap.width();
310 424 : if (1 == width) {
311 : // all of the following X values must be 0
312 0 : memset(xy, 0, count * sizeof(uint16_t));
313 0 : return;
314 : }
315 :
316 424 : uint16_t* xptr = reinterpret_cast<uint16_t*>(xy);
317 : int n;
318 :
319 : // fill before 0 as needed
320 424 : if (xpos < 0) {
321 0 : n = -xpos;
322 0 : if (n > count) {
323 0 : n = count;
324 : }
325 0 : memset(xptr, 0, n * sizeof(uint16_t));
326 0 : count -= n;
327 0 : if (0 == count) {
328 0 : return;
329 : }
330 0 : xptr += n;
331 0 : xpos = 0;
332 : }
333 :
334 : // fill in 0..width-1 if needed
335 424 : if (xpos < width) {
336 424 : n = width - xpos;
337 424 : if (n > count) {
338 32 : n = count;
339 : }
340 424 : fill_sequential(xptr, xpos, n);
341 424 : count -= n;
342 424 : if (0 == count) {
343 424 : return;
344 : }
345 0 : xptr += n;
346 : }
347 :
348 : // fill the remaining with the max value
349 0 : sk_memset16(xptr, width - 1, count);
350 : }
351 :
352 680 : static void repeatx_nofilter_trans(const SkBitmapProcState& s,
353 : uint32_t xy[], int count, int x, int y) {
354 680 : SkASSERT((s.fInvType & ~SkMatrix::kTranslate_Mask) == 0);
355 :
356 680 : int xpos = nofilter_trans_preamble(s, &xy, x, y);
357 680 : const int width = s.fPixmap.width();
358 680 : if (1 == width) {
359 : // all of the following X values must be 0
360 0 : memset(xy, 0, count * sizeof(uint16_t));
361 0 : return;
362 : }
363 :
364 680 : uint16_t* xptr = reinterpret_cast<uint16_t*>(xy);
365 680 : int start = sk_int_mod(xpos, width);
366 680 : int n = width - start;
367 680 : if (n > count) {
368 30 : n = count;
369 : }
370 680 : fill_sequential(xptr, start, n);
371 680 : xptr += n;
372 680 : count -= n;
373 :
374 16052 : while (count >= width) {
375 7686 : fill_sequential(xptr, 0, width);
376 7686 : xptr += width;
377 7686 : count -= width;
378 : }
379 :
380 680 : if (count > 0) {
381 432 : fill_sequential(xptr, 0, count);
382 : }
383 : }
384 :
385 0 : static void fill_backwards(uint16_t xptr[], int pos, int count) {
386 0 : for (int i = 0; i < count; i++) {
387 0 : SkASSERT(pos >= 0);
388 0 : xptr[i] = pos--;
389 : }
390 0 : }
391 :
392 0 : static void mirrorx_nofilter_trans(const SkBitmapProcState& s,
393 : uint32_t xy[], int count, int x, int y) {
394 0 : SkASSERT((s.fInvType & ~SkMatrix::kTranslate_Mask) == 0);
395 :
396 0 : int xpos = nofilter_trans_preamble(s, &xy, x, y);
397 0 : const int width = s.fPixmap.width();
398 0 : if (1 == width) {
399 : // all of the following X values must be 0
400 0 : memset(xy, 0, count * sizeof(uint16_t));
401 0 : return;
402 : }
403 :
404 0 : 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 0 : int start = sk_int_mod(xpos, 2 * width);
409 0 : if (start >= width) {
410 0 : start = width + ~(start - width);
411 0 : forward = false;
412 0 : n = start + 1; // [start .. 0]
413 : } else {
414 0 : forward = true;
415 0 : n = width - start; // [start .. width)
416 : }
417 0 : if (n > count) {
418 0 : n = count;
419 : }
420 0 : if (forward) {
421 0 : fill_sequential(xptr, start, n);
422 : } else {
423 0 : fill_backwards(xptr, start, n);
424 : }
425 0 : forward = !forward;
426 0 : xptr += n;
427 0 : count -= n;
428 :
429 0 : while (count >= width) {
430 0 : if (forward) {
431 0 : fill_sequential(xptr, 0, width);
432 : } else {
433 0 : fill_backwards(xptr, width - 1, width);
434 : }
435 0 : forward = !forward;
436 0 : xptr += width;
437 0 : count -= width;
438 : }
439 :
440 0 : if (count > 0) {
441 0 : if (forward) {
442 0 : fill_sequential(xptr, 0, count);
443 : } else {
444 0 : fill_backwards(xptr, width - 1, count);
445 : }
446 : }
447 : }
448 :
449 : ///////////////////////////////////////////////////////////////////////////////
450 :
451 141 : 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 141 : if (trivial_matrix && kNone_SkFilterQuality == fFilterQuality) {
455 99 : fIntTileProcY = choose_int_tile_proc(fTileModeY);
456 99 : switch (fTileModeX) {
457 : case SkShader::kClamp_TileMode:
458 73 : return clampx_nofilter_trans;
459 : case SkShader::kRepeat_TileMode:
460 26 : return repeatx_nofilter_trans;
461 : case SkShader::kMirror_TileMode:
462 0 : return mirrorx_nofilter_trans;
463 : }
464 : }
465 :
466 42 : int index = 0;
467 42 : if (fFilterQuality != kNone_SkFilterQuality) {
468 42 : index = 1;
469 : }
470 42 : if (fInvType & SkMatrix::kPerspective_Mask) {
471 0 : index += 4;
472 42 : } else if (fInvType & SkMatrix::kAffine_Mask) {
473 0 : index += 2;
474 : }
475 :
476 42 : if (SkShader::kClamp_TileMode == fTileModeX && SkShader::kClamp_TileMode == fTileModeY) {
477 : // clamp gets special version of filterOne
478 25 : fFilterOneX = SK_Fixed1;
479 25 : fFilterOneY = SK_Fixed1;
480 25 : return SK_ARM_NEON_WRAP(ClampX_ClampY_Procs)[index];
481 : }
482 :
483 : // all remaining procs use this form for filterOne
484 17 : fFilterOneX = SK_Fixed1 / fPixmap.width();
485 17 : fFilterOneY = SK_Fixed1 / fPixmap.height();
486 :
487 17 : if (SkShader::kRepeat_TileMode == fTileModeX && SkShader::kRepeat_TileMode == fTileModeY) {
488 17 : return SK_ARM_NEON_WRAP(RepeatX_RepeatY_Procs)[index];
489 : }
490 :
491 0 : fTileProcX = choose_tile_proc(fTileModeX);
492 0 : fTileProcY = choose_tile_proc(fTileModeY);
493 0 : return GeneralXY_Procs[index];
494 : }
|