• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2011 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 #include "SkBitmapCache.h"
9 #include "SkBitmapController.h"
10 #include "SkBitmapProcState.h"
11 #include "SkColorPriv.h"
12 #include "SkFilterProc.h"
13 #include "SkPaint.h"
14 #include "SkShader.h"   // for tilemodes
15 #include "SkUtilsArm.h"
16 #include "SkBitmapScaler.h"
17 #include "SkMipMap.h"
18 #include "SkPixelRef.h"
19 #include "SkImageEncoder.h"
20 #include "SkResourceCache.h"
21 
22 #if defined(SK_ARM_HAS_NEON)
23 // These are defined in src/opts/SkBitmapProcState_arm_neon.cpp
24 extern const SkBitmapProcState::SampleProc32 gSkBitmapProcStateSample32_neon[];
25 extern void  S16_D16_filter_DX_neon(const SkBitmapProcState&, const uint32_t*, int, uint16_t*);
26 extern void  Clamp_S16_D16_filter_DX_shaderproc_neon(const void *, int, int, uint16_t*, int);
27 extern void  Repeat_S16_D16_filter_DX_shaderproc_neon(const void *, int, int, uint16_t*, int);
28 extern void  SI8_opaque_D32_filter_DX_neon(const SkBitmapProcState&, const uint32_t*, int, SkPMColor*);
29 extern void  SI8_opaque_D32_filter_DX_shaderproc_neon(const void *, int, int, uint32_t*, int);
30 extern void  Clamp_SI8_opaque_D32_filter_DX_shaderproc_neon(const void*, int, int, uint32_t*, int);
31 #endif
32 
33 extern void Clamp_S32_opaque_D32_nofilter_DX_shaderproc(const void*, int, int, uint32_t*, int);
34 
35 #define   NAME_WRAP(x)  x
36 #include "SkBitmapProcState_filter.h"
37 #include "SkBitmapProcState_procs.h"
38 
SkBitmapProcInfo(const SkBitmapProvider & provider,SkShader::TileMode tmx,SkShader::TileMode tmy)39 SkBitmapProcInfo::SkBitmapProcInfo(const SkBitmapProvider& provider,
40                                    SkShader::TileMode tmx, SkShader::TileMode tmy)
41     : fProvider(provider)
42     , fTileModeX(tmx)
43     , fTileModeY(tmy)
44     , fBMState(nullptr)
45 {}
46 
~SkBitmapProcInfo()47 SkBitmapProcInfo::~SkBitmapProcInfo() {
48     SkInPlaceDeleteCheck(fBMState, fBMStateStorage.get());
49 }
50 
51 ///////////////////////////////////////////////////////////////////////////////
52 
53 // true iff the matrix has a scale and no more than an optional translate.
matrix_only_scale_translate(const SkMatrix & m)54 static bool matrix_only_scale_translate(const SkMatrix& m) {
55     return (m.getType() & ~SkMatrix::kTranslate_Mask) == SkMatrix::kScale_Mask;
56 }
57 
58 /**
59  *  For the purposes of drawing bitmaps, if a matrix is "almost" translate
60  *  go ahead and treat it as if it were, so that subsequent code can go fast.
61  */
just_trans_clamp(const SkMatrix & matrix,const SkPixmap & pixmap)62 static bool just_trans_clamp(const SkMatrix& matrix, const SkPixmap& pixmap) {
63     SkASSERT(matrix_only_scale_translate(matrix));
64 
65     SkRect dst;
66     SkRect src = SkRect::Make(pixmap.bounds());
67 
68     // Can't call mapRect(), since that will fix up inverted rectangles,
69     // e.g. when scale is negative, and we don't want to return true for
70     // those.
71     matrix.mapPoints(SkTCast<SkPoint*>(&dst),
72                      SkTCast<const SkPoint*>(&src),
73                      2);
74 
75     // Now round all 4 edges to device space, and then compare the device
76     // width/height to the original. Note: we must map all 4 and subtract
77     // rather than map the "width" and compare, since we care about the
78     // phase (in pixel space) that any translate in the matrix might impart.
79     SkIRect idst;
80     dst.round(&idst);
81     return idst.width() == pixmap.width() && idst.height() == pixmap.height();
82 }
83 
just_trans_general(const SkMatrix & matrix)84 static bool just_trans_general(const SkMatrix& matrix) {
85     SkASSERT(matrix_only_scale_translate(matrix));
86 
87     const SkScalar tol = SK_Scalar1 / 32768;
88 
89     return SkScalarNearlyZero(matrix[SkMatrix::kMScaleX] - SK_Scalar1, tol)
90         && SkScalarNearlyZero(matrix[SkMatrix::kMScaleY] - SK_Scalar1, tol);
91 }
92 
valid_for_filtering(unsigned dimension)93 static bool valid_for_filtering(unsigned dimension) {
94     // for filtering, width and height must fit in 14bits, since we use steal
95     // 2 bits from each to store our 4bit subpixel data
96     return (dimension & ~0x3FFF) == 0;
97 }
98 
init(const SkMatrix & inv,const SkPaint & paint)99 bool SkBitmapProcInfo::init(const SkMatrix& inv, const SkPaint& paint) {
100     const int origW = fProvider.info().width();
101     const int origH = fProvider.info().height();
102 
103     fPixmap.reset();
104     fInvMatrix = inv;
105     fFilterQuality = paint.getFilterQuality();
106 
107     bool allow_ignore_fractional_translate = true;  // historical default
108     if (kMedium_SkFilterQuality == fFilterQuality) {
109         allow_ignore_fractional_translate = false;
110     }
111 
112     SkDefaultBitmapController controller(SkDefaultBitmapController::CanShadeHQ::kNo);
113     fBMState = controller.requestBitmap(fProvider, inv, paint.getFilterQuality(),
114                                         fBMStateStorage.get(), fBMStateStorage.size());
115     // Note : we allow the controller to return an empty (zero-dimension) result. Should we?
116     if (nullptr == fBMState || fBMState->pixmap().info().isEmpty()) {
117         return false;
118     }
119     fPixmap = fBMState->pixmap();
120     fInvMatrix = fBMState->invMatrix();
121     fRealInvMatrix = fBMState->invMatrix();
122     fPaintColor = paint.getColor();
123     fFilterQuality = fBMState->quality();
124     SkASSERT(fPixmap.addr());
125 
126     bool trivialMatrix = (fInvMatrix.getType() & ~SkMatrix::kTranslate_Mask) == 0;
127     bool clampClamp = SkShader::kClamp_TileMode == fTileModeX &&
128                       SkShader::kClamp_TileMode == fTileModeY;
129 
130     // Most of the scanline procs deal with "unit" texture coordinates, as this
131     // makes it easy to perform tiling modes (repeat = (x & 0xFFFF)). To generate
132     // those, we divide the matrix by its dimensions here.
133     //
134     // We don't do this if we're either trivial (can ignore the matrix) or clamping
135     // in both X and Y since clamping to width,height is just as easy as to 0xFFFF.
136 
137     // Note that we cannot ignore the matrix when allow_ignore_fractional_translate is false.
138 
139     if (!(clampClamp || (trivialMatrix && allow_ignore_fractional_translate))) {
140         fInvMatrix.postIDiv(fPixmap.width(), fPixmap.height());
141     }
142 
143     // Now that all possible changes to the matrix have taken place, check
144     // to see if we're really close to a no-scale matrix.  If so, explicitly
145     // set it to be so.  Subsequent code may inspect this matrix to choose
146     // a faster path in this case.
147 
148     // This code will only execute if the matrix has some scale component;
149     // if it's already pure translate then we won't do this inversion.
150 
151     if (matrix_only_scale_translate(fInvMatrix)) {
152         SkMatrix forward;
153         if (fInvMatrix.invert(&forward)) {
154             if ((clampClamp && allow_ignore_fractional_translate)
155                 ? just_trans_clamp(forward, fPixmap)
156                 : just_trans_general(forward)) {
157                 fInvMatrix.setTranslate(-forward.getTranslateX(), -forward.getTranslateY());
158             }
159         }
160     }
161 
162     fInvType = fInvMatrix.getType();
163 
164     // If our target pixmap is the same as the original, then we revert back to legacy behavior
165     // and allow the code to ignore fractional translate.
166     //
167     // The width/height check allows allow_ignore_fractional_translate to stay false if we
168     // previously set it that way (e.g. we started in kMedium).
169     //
170     if (fPixmap.width() == origW && fPixmap.height() == origH) {
171         allow_ignore_fractional_translate = true;
172     }
173 
174     if (kLow_SkFilterQuality == fFilterQuality && allow_ignore_fractional_translate) {
175         // Only try bilerp if the matrix is "interesting" and
176         // the image has a suitable size.
177 
178         if (fInvType <= SkMatrix::kTranslate_Mask ||
179             !valid_for_filtering(fPixmap.width() | fPixmap.height()))
180         {
181             fFilterQuality = kNone_SkFilterQuality;
182         }
183     }
184 
185     return true;
186 }
187 
188 /*
189  *  Analyze filter-quality and matrix, and decide how to implement that.
190  *
191  *  In general, we cascade down the request level [ High ... None ]
192  *  - for a given level, if we can fulfill it, fine, else
193  *    - else we downgrade to the next lower level and try again.
194  *  We can always fulfill requests for Low and None
195  *  - sometimes we will "ignore" Low and give None, but this is likely a legacy perf hack
196  *    and may be removed.
197  */
chooseProcs()198 bool SkBitmapProcState::chooseProcs() {
199     fInvProc            = fInvMatrix.getMapXYProc();
200     fInvSx              = SkScalarToFixed(fInvMatrix.getScaleX());
201     fInvSxFractionalInt = SkScalarToFractionalInt(fInvMatrix.getScaleX());
202     fInvKy              = SkScalarToFixed(fInvMatrix.getSkewY());
203     fInvKyFractionalInt = SkScalarToFractionalInt(fInvMatrix.getSkewY());
204 
205     fAlphaScale = SkAlpha255To256(SkColorGetA(fPaintColor));
206 
207     fShaderProc32 = nullptr;
208     fShaderProc16 = nullptr;
209     fSampleProc32 = nullptr;
210 
211     const bool trivialMatrix = (fInvMatrix.getType() & ~SkMatrix::kTranslate_Mask) == 0;
212     const bool clampClamp = SkShader::kClamp_TileMode == fTileModeX &&
213                             SkShader::kClamp_TileMode == fTileModeY;
214 
215     return this->chooseScanlineProcs(trivialMatrix, clampClamp);
216 }
217 
chooseScanlineProcs(bool trivialMatrix,bool clampClamp)218 bool SkBitmapProcState::chooseScanlineProcs(bool trivialMatrix, bool clampClamp) {
219     fMatrixProc = this->chooseMatrixProc(trivialMatrix);
220     // TODO(dominikg): SkASSERT(fMatrixProc) instead? chooseMatrixProc never returns nullptr.
221     if (nullptr == fMatrixProc) {
222         return false;
223     }
224 
225     ///////////////////////////////////////////////////////////////////////
226 
227     const SkAlphaType at = fPixmap.alphaType();
228 
229     // No need to do this if we're doing HQ sampling; if filter quality is
230     // still set to HQ by the time we get here, then we must have installed
231     // the shader procs above and can skip all this.
232 
233     if (fFilterQuality < kHigh_SkFilterQuality) {
234 
235         int index = 0;
236         if (fAlphaScale < 256) {  // note: this distinction is not used for D16
237             index |= 1;
238         }
239         if (fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) {
240             index |= 2;
241         }
242         if (fFilterQuality > kNone_SkFilterQuality) {
243             index |= 4;
244         }
245         // bits 3,4,5 encoding the source bitmap format
246         switch (fPixmap.colorType()) {
247             case kN32_SkColorType:
248                 if (kPremul_SkAlphaType != at && kOpaque_SkAlphaType != at) {
249                     return false;
250                 }
251                 index |= 0;
252                 break;
253             case kRGB_565_SkColorType:
254                 index |= 8;
255                 break;
256             case kIndex_8_SkColorType:
257                 if (kPremul_SkAlphaType != at && kOpaque_SkAlphaType != at) {
258                     return false;
259                 }
260                 index |= 16;
261                 break;
262             case kARGB_4444_SkColorType:
263                 if (kPremul_SkAlphaType != at && kOpaque_SkAlphaType != at) {
264                     return false;
265                 }
266                 index |= 24;
267                 break;
268             case kAlpha_8_SkColorType:
269                 index |= 32;
270                 fPaintPMColor = SkPreMultiplyColor(fPaintColor);
271                 break;
272             case kGray_8_SkColorType:
273                 index |= 40;
274                 fPaintPMColor = SkPreMultiplyColor(fPaintColor);
275                 break;
276             default:
277                 // TODO(dominikg): Should we ever get here? SkASSERT(false) instead?
278                 return false;
279         }
280 
281 #if !defined(SK_ARM_HAS_NEON)
282         static const SampleProc32 gSkBitmapProcStateSample32[] = {
283             S32_opaque_D32_nofilter_DXDY,
284             S32_alpha_D32_nofilter_DXDY,
285             S32_opaque_D32_nofilter_DX,
286             S32_alpha_D32_nofilter_DX,
287             S32_opaque_D32_filter_DXDY,
288             S32_alpha_D32_filter_DXDY,
289             S32_opaque_D32_filter_DX,
290             S32_alpha_D32_filter_DX,
291 
292             S16_opaque_D32_nofilter_DXDY,
293             S16_alpha_D32_nofilter_DXDY,
294             S16_opaque_D32_nofilter_DX,
295             S16_alpha_D32_nofilter_DX,
296             S16_opaque_D32_filter_DXDY,
297             S16_alpha_D32_filter_DXDY,
298             S16_opaque_D32_filter_DX,
299             S16_alpha_D32_filter_DX,
300 
301             SI8_opaque_D32_nofilter_DXDY,
302             SI8_alpha_D32_nofilter_DXDY,
303             SI8_opaque_D32_nofilter_DX,
304             SI8_alpha_D32_nofilter_DX,
305             SI8_opaque_D32_filter_DXDY,
306             SI8_alpha_D32_filter_DXDY,
307             SI8_opaque_D32_filter_DX,
308             SI8_alpha_D32_filter_DX,
309 
310             S4444_opaque_D32_nofilter_DXDY,
311             S4444_alpha_D32_nofilter_DXDY,
312             S4444_opaque_D32_nofilter_DX,
313             S4444_alpha_D32_nofilter_DX,
314             S4444_opaque_D32_filter_DXDY,
315             S4444_alpha_D32_filter_DXDY,
316             S4444_opaque_D32_filter_DX,
317             S4444_alpha_D32_filter_DX,
318 
319             // A8 treats alpha/opaque the same (equally efficient)
320             SA8_alpha_D32_nofilter_DXDY,
321             SA8_alpha_D32_nofilter_DXDY,
322             SA8_alpha_D32_nofilter_DX,
323             SA8_alpha_D32_nofilter_DX,
324             SA8_alpha_D32_filter_DXDY,
325             SA8_alpha_D32_filter_DXDY,
326             SA8_alpha_D32_filter_DX,
327             SA8_alpha_D32_filter_DX,
328 
329             // todo: possibly specialize on opaqueness
330             SG8_alpha_D32_nofilter_DXDY,
331             SG8_alpha_D32_nofilter_DXDY,
332             SG8_alpha_D32_nofilter_DX,
333             SG8_alpha_D32_nofilter_DX,
334             SG8_alpha_D32_filter_DXDY,
335             SG8_alpha_D32_filter_DXDY,
336             SG8_alpha_D32_filter_DX,
337             SG8_alpha_D32_filter_DX
338         };
339 #endif
340 
341         fSampleProc32 = SK_ARM_NEON_WRAP(gSkBitmapProcStateSample32)[index];
342 
343         // our special-case shaderprocs
344         if (SK_ARM_NEON_WRAP(SI8_opaque_D32_filter_DX) == fSampleProc32 && clampClamp) {
345             fShaderProc32 = SK_ARM_NEON_WRAP(Clamp_SI8_opaque_D32_filter_DX_shaderproc);
346         } else if (S32_opaque_D32_nofilter_DX == fSampleProc32 && clampClamp) {
347             fShaderProc32 = Clamp_S32_opaque_D32_nofilter_DX_shaderproc;
348         }
349 
350         if (nullptr == fShaderProc32) {
351             fShaderProc32 = this->chooseShaderProc32();
352         }
353     }
354 
355     // see if our platform has any accelerated overrides
356     this->platformProcs();
357 
358     return true;
359 }
360 
Clamp_S32_D32_nofilter_trans_shaderproc(const void * sIn,int x,int y,SkPMColor * SK_RESTRICT colors,int count)361 static void Clamp_S32_D32_nofilter_trans_shaderproc(const void* sIn,
362                                                     int x, int y,
363                                                     SkPMColor* SK_RESTRICT colors,
364                                                     int count) {
365     const SkBitmapProcState& s = *static_cast<const SkBitmapProcState*>(sIn);
366     SkASSERT(((s.fInvType & ~SkMatrix::kTranslate_Mask)) == 0);
367     SkASSERT(s.fInvKy == 0);
368     SkASSERT(count > 0 && colors != nullptr);
369     SkASSERT(kNone_SkFilterQuality == s.fFilterQuality);
370 
371     const int maxX = s.fPixmap.width() - 1;
372     const int maxY = s.fPixmap.height() - 1;
373     int ix = s.fFilterOneX + x;
374     int iy = SkClampMax(s.fFilterOneY + y, maxY);
375     const SkPMColor* row = s.fPixmap.addr32(0, iy);
376 
377     // clamp to the left
378     if (ix < 0) {
379         int n = SkMin32(-ix, count);
380         sk_memset32(colors, row[0], n);
381         count -= n;
382         if (0 == count) {
383             return;
384         }
385         colors += n;
386         SkASSERT(-ix == n);
387         ix = 0;
388     }
389     // copy the middle
390     if (ix <= maxX) {
391         int n = SkMin32(maxX - ix + 1, count);
392         memcpy(colors, row + ix, n * sizeof(SkPMColor));
393         count -= n;
394         if (0 == count) {
395             return;
396         }
397         colors += n;
398     }
399     SkASSERT(count > 0);
400     // clamp to the right
401     sk_memset32(colors, row[maxX], count);
402 }
403 
sk_int_mod(int x,int n)404 static inline int sk_int_mod(int x, int n) {
405     SkASSERT(n > 0);
406     if ((unsigned)x >= (unsigned)n) {
407         if (x < 0) {
408             x = n + ~(~x % n);
409         } else {
410             x = x % n;
411         }
412     }
413     return x;
414 }
415 
sk_int_mirror(int x,int n)416 static inline int sk_int_mirror(int x, int n) {
417     x = sk_int_mod(x, 2 * n);
418     if (x >= n) {
419         x = n + ~(x - n);
420     }
421     return x;
422 }
423 
Repeat_S32_D32_nofilter_trans_shaderproc(const void * sIn,int x,int y,SkPMColor * SK_RESTRICT colors,int count)424 static void Repeat_S32_D32_nofilter_trans_shaderproc(const void* sIn,
425                                                      int x, int y,
426                                                      SkPMColor* SK_RESTRICT colors,
427                                                      int count) {
428     const SkBitmapProcState& s = *static_cast<const SkBitmapProcState*>(sIn);
429     SkASSERT(((s.fInvType & ~SkMatrix::kTranslate_Mask)) == 0);
430     SkASSERT(s.fInvKy == 0);
431     SkASSERT(count > 0 && colors != nullptr);
432     SkASSERT(kNone_SkFilterQuality == s.fFilterQuality);
433 
434     const int stopX = s.fPixmap.width();
435     const int stopY = s.fPixmap.height();
436     int ix = s.fFilterOneX + x;
437     int iy = sk_int_mod(s.fFilterOneY + y, stopY);
438     const SkPMColor* row = s.fPixmap.addr32(0, iy);
439 
440     ix = sk_int_mod(ix, stopX);
441     for (;;) {
442         int n = SkMin32(stopX - ix, count);
443         memcpy(colors, row + ix, n * sizeof(SkPMColor));
444         count -= n;
445         if (0 == count) {
446             return;
447         }
448         colors += n;
449         ix = 0;
450     }
451 }
452 
S32_D32_constX_shaderproc(const void * sIn,int x,int y,SkPMColor * SK_RESTRICT colors,int count)453 static void S32_D32_constX_shaderproc(const void* sIn,
454                                       int x, int y,
455                                       SkPMColor* SK_RESTRICT colors,
456                                       int count) {
457     const SkBitmapProcState& s = *static_cast<const SkBitmapProcState*>(sIn);
458     SkASSERT((s.fInvType & ~(SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) == 0);
459     SkASSERT(s.fInvKy == 0);
460     SkASSERT(count > 0 && colors != nullptr);
461     SkASSERT(1 == s.fPixmap.width());
462 
463     int iY0;
464     int iY1   SK_INIT_TO_AVOID_WARNING;
465     int iSubY SK_INIT_TO_AVOID_WARNING;
466 
467     if (kNone_SkFilterQuality != s.fFilterQuality) {
468         SkBitmapProcState::MatrixProc mproc = s.getMatrixProc();
469         uint32_t xy[2];
470 
471         mproc(s, xy, 1, x, y);
472 
473         iY0 = xy[0] >> 18;
474         iY1 = xy[0] & 0x3FFF;
475         iSubY = (xy[0] >> 14) & 0xF;
476     } else {
477         int yTemp;
478 
479         if (s.fInvType > SkMatrix::kTranslate_Mask) {
480             const SkBitmapProcStateAutoMapper mapper(s, x, y);
481 
482             // When the matrix has a scale component the setup code in
483             // chooseProcs multiples the inverse matrix by the inverse of the
484             // bitmap's width and height. Since this method is going to do
485             // its own tiling and sampling we need to undo that here.
486             if (SkShader::kClamp_TileMode != s.fTileModeX ||
487                 SkShader::kClamp_TileMode != s.fTileModeY) {
488                 yTemp = SkFractionalIntToInt(mapper.fractionalIntY() * s.fPixmap.height());
489             } else {
490                 yTemp = mapper.intY();
491             }
492         } else {
493             yTemp = s.fFilterOneY + y;
494         }
495 
496         const int stopY = s.fPixmap.height();
497         switch (s.fTileModeY) {
498             case SkShader::kClamp_TileMode:
499                 iY0 = SkClampMax(yTemp, stopY-1);
500                 break;
501             case SkShader::kRepeat_TileMode:
502                 iY0 = sk_int_mod(yTemp, stopY);
503                 break;
504             case SkShader::kMirror_TileMode:
505             default:
506                 iY0 = sk_int_mirror(yTemp, stopY);
507                 break;
508         }
509 
510 #ifdef SK_DEBUG
511         {
512             const SkBitmapProcStateAutoMapper mapper(s, x, y);
513             int iY2;
514 
515             if (s.fInvType > SkMatrix::kTranslate_Mask &&
516                 (SkShader::kClamp_TileMode != s.fTileModeX ||
517                  SkShader::kClamp_TileMode != s.fTileModeY)) {
518                 iY2 = SkFractionalIntToInt(mapper.fractionalIntY() * s.fPixmap.height());
519             } else {
520                 iY2 = mapper.intY();
521             }
522 
523             switch (s.fTileModeY) {
524             case SkShader::kClamp_TileMode:
525                 iY2 = SkClampMax(iY2, stopY-1);
526                 break;
527             case SkShader::kRepeat_TileMode:
528                 iY2 = sk_int_mod(iY2, stopY);
529                 break;
530             case SkShader::kMirror_TileMode:
531             default:
532                 iY2 = sk_int_mirror(iY2, stopY);
533                 break;
534             }
535 
536             SkASSERT(iY0 == iY2);
537         }
538 #endif
539     }
540 
541     const SkPMColor* row0 = s.fPixmap.addr32(0, iY0);
542     SkPMColor color;
543 
544     if (kNone_SkFilterQuality != s.fFilterQuality) {
545         const SkPMColor* row1 = s.fPixmap.addr32(0, iY1);
546 
547         if (s.fAlphaScale < 256) {
548             Filter_32_alpha(iSubY, *row0, *row1, &color, s.fAlphaScale);
549         } else {
550             Filter_32_opaque(iSubY, *row0, *row1, &color);
551         }
552     } else {
553         if (s.fAlphaScale < 256) {
554             color = SkAlphaMulQ(*row0, s.fAlphaScale);
555         } else {
556             color = *row0;
557         }
558     }
559 
560     sk_memset32(colors, color, count);
561 }
562 
DoNothing_shaderproc(const void *,int x,int y,SkPMColor * SK_RESTRICT colors,int count)563 static void DoNothing_shaderproc(const void*, int x, int y,
564                                  SkPMColor* SK_RESTRICT colors, int count) {
565     // if we get called, the matrix is too tricky, so we just draw nothing
566     sk_memset32(colors, 0, count);
567 }
568 
setupForTranslate()569 bool SkBitmapProcState::setupForTranslate() {
570     SkPoint pt;
571     const SkBitmapProcStateAutoMapper mapper(*this, 0, 0, &pt);
572 
573     /*
574      *  if the translate is larger than our ints, we can get random results, or
575      *  worse, we might get 0x80000000, which wreaks havoc on us, since we can't
576      *  negate it.
577      */
578     const SkScalar too_big = SkIntToScalar(1 << 30);
579     if (SkScalarAbs(pt.fX) > too_big || SkScalarAbs(pt.fY) > too_big) {
580         return false;
581     }
582 
583     // Since we know we're not filtered, we re-purpose these fields allow
584     // us to go from device -> src coordinates w/ just an integer add,
585     // rather than running through the inverse-matrix
586     fFilterOneX = mapper.intX();
587     fFilterOneY = mapper.intY();
588 
589     return true;
590 }
591 
chooseShaderProc32()592 SkBitmapProcState::ShaderProc32 SkBitmapProcState::chooseShaderProc32() {
593 
594     if (kN32_SkColorType != fPixmap.colorType()) {
595         return nullptr;
596     }
597 
598     static const unsigned kMask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask;
599 
600     if (1 == fPixmap.width() && 0 == (fInvType & ~kMask)) {
601         if (kNone_SkFilterQuality == fFilterQuality &&
602             fInvType <= SkMatrix::kTranslate_Mask &&
603             !this->setupForTranslate()) {
604             return DoNothing_shaderproc;
605         }
606         return S32_D32_constX_shaderproc;
607     }
608 
609     if (fAlphaScale < 256) {
610         return nullptr;
611     }
612     if (fInvType > SkMatrix::kTranslate_Mask) {
613         return nullptr;
614     }
615     if (kNone_SkFilterQuality != fFilterQuality) {
616         return nullptr;
617     }
618 
619     SkShader::TileMode tx = (SkShader::TileMode)fTileModeX;
620     SkShader::TileMode ty = (SkShader::TileMode)fTileModeY;
621 
622     if (SkShader::kClamp_TileMode == tx && SkShader::kClamp_TileMode == ty) {
623         if (this->setupForTranslate()) {
624             return Clamp_S32_D32_nofilter_trans_shaderproc;
625         }
626         return DoNothing_shaderproc;
627     }
628     if (SkShader::kRepeat_TileMode == tx && SkShader::kRepeat_TileMode == ty) {
629         if (this->setupForTranslate()) {
630             return Repeat_S32_D32_nofilter_trans_shaderproc;
631         }
632         return DoNothing_shaderproc;
633     }
634     return nullptr;
635 }
636 
637 ///////////////////////////////////////////////////////////////////////////////
638 
639 #ifdef SK_DEBUG
640 
check_scale_nofilter(uint32_t bitmapXY[],int count,unsigned mx,unsigned my)641 static void check_scale_nofilter(uint32_t bitmapXY[], int count,
642                                  unsigned mx, unsigned my) {
643     unsigned y = *bitmapXY++;
644     SkASSERT(y < my);
645 
646     const uint16_t* xptr = reinterpret_cast<const uint16_t*>(bitmapXY);
647     for (int i = 0; i < count; ++i) {
648         SkASSERT(xptr[i] < mx);
649     }
650 }
651 
check_scale_filter(uint32_t bitmapXY[],int count,unsigned mx,unsigned my)652 static void check_scale_filter(uint32_t bitmapXY[], int count,
653                                  unsigned mx, unsigned my) {
654     uint32_t YY = *bitmapXY++;
655     unsigned y0 = YY >> 18;
656     unsigned y1 = YY & 0x3FFF;
657     SkASSERT(y0 < my);
658     SkASSERT(y1 < my);
659 
660     for (int i = 0; i < count; ++i) {
661         uint32_t XX = bitmapXY[i];
662         unsigned x0 = XX >> 18;
663         unsigned x1 = XX & 0x3FFF;
664         SkASSERT(x0 < mx);
665         SkASSERT(x1 < mx);
666     }
667 }
668 
check_affine_nofilter(uint32_t bitmapXY[],int count,unsigned mx,unsigned my)669 static void check_affine_nofilter(uint32_t bitmapXY[], int count,
670                                  unsigned mx, unsigned my) {
671     for (int i = 0; i < count; ++i) {
672         uint32_t XY = bitmapXY[i];
673         unsigned x = XY & 0xFFFF;
674         unsigned y = XY >> 16;
675         SkASSERT(x < mx);
676         SkASSERT(y < my);
677     }
678 }
679 
check_affine_filter(uint32_t bitmapXY[],int count,unsigned mx,unsigned my)680 static void check_affine_filter(uint32_t bitmapXY[], int count,
681                                  unsigned mx, unsigned my) {
682     for (int i = 0; i < count; ++i) {
683         uint32_t YY = *bitmapXY++;
684         unsigned y0 = YY >> 18;
685         unsigned y1 = YY & 0x3FFF;
686         SkASSERT(y0 < my);
687         SkASSERT(y1 < my);
688 
689         uint32_t XX = *bitmapXY++;
690         unsigned x0 = XX >> 18;
691         unsigned x1 = XX & 0x3FFF;
692         SkASSERT(x0 < mx);
693         SkASSERT(x1 < mx);
694     }
695 }
696 
DebugMatrixProc(const SkBitmapProcState & state,uint32_t bitmapXY[],int count,int x,int y)697 void SkBitmapProcState::DebugMatrixProc(const SkBitmapProcState& state,
698                                         uint32_t bitmapXY[], int count,
699                                         int x, int y) {
700     SkASSERT(bitmapXY);
701     SkASSERT(count > 0);
702 
703     state.fMatrixProc(state, bitmapXY, count, x, y);
704 
705     void (*proc)(uint32_t bitmapXY[], int count, unsigned mx, unsigned my);
706 
707     // There are four formats possible:
708     //  scale -vs- affine
709     //  filter -vs- nofilter
710     if (state.fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) {
711         proc = state.fFilterQuality != kNone_SkFilterQuality ?
712                     check_scale_filter : check_scale_nofilter;
713     } else {
714         proc = state.fFilterQuality != kNone_SkFilterQuality ?
715                     check_affine_filter : check_affine_nofilter;
716     }
717     proc(bitmapXY, count, state.fPixmap.width(), state.fPixmap.height());
718 }
719 
getMatrixProc() const720 SkBitmapProcState::MatrixProc SkBitmapProcState::getMatrixProc() const {
721     return DebugMatrixProc;
722 }
723 
724 #endif
725 
726 ///////////////////////////////////////////////////////////////////////////////
727 /*
728     The storage requirements for the different matrix procs are as follows,
729     where each X or Y is 2 bytes, and N is the number of pixels/elements:
730 
731     scale/translate     nofilter      Y(4bytes) + N * X
732     affine/perspective  nofilter      N * (X Y)
733     scale/translate     filter        Y Y + N * (X X)
734     affine/perspective  filter        N * (Y Y X X)
735  */
maxCountForBufferSize(size_t bufferSize) const736 int SkBitmapProcState::maxCountForBufferSize(size_t bufferSize) const {
737     int32_t size = static_cast<int32_t>(bufferSize);
738 
739     size &= ~3; // only care about 4-byte aligned chunks
740     if (fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) {
741         size -= 4;   // the shared Y (or YY) coordinate
742         if (size < 0) {
743             size = 0;
744         }
745         size >>= 1;
746     } else {
747         size >>= 2;
748     }
749 
750     if (fFilterQuality != kNone_SkFilterQuality) {
751         size >>= 1;
752     }
753 
754     return size;
755 }
756 
757 ///////////////////////
758 
Clamp_S32_opaque_D32_nofilter_DX_shaderproc(const void * sIn,int x,int y,SkPMColor * SK_RESTRICT dst,int count)759 void  Clamp_S32_opaque_D32_nofilter_DX_shaderproc(const void* sIn, int x, int y,
760                                                   SkPMColor* SK_RESTRICT dst, int count) {
761     const SkBitmapProcState& s = *static_cast<const SkBitmapProcState*>(sIn);
762     SkASSERT((s.fInvType & ~(SkMatrix::kTranslate_Mask |
763                              SkMatrix::kScale_Mask)) == 0);
764 
765     const unsigned maxX = s.fPixmap.width() - 1;
766     SkFractionalInt fx;
767     int dstY;
768     {
769         const SkBitmapProcStateAutoMapper mapper(s, x, y);
770         const unsigned maxY = s.fPixmap.height() - 1;
771         dstY = SkClampMax(mapper.intY(), maxY);
772         fx = mapper.fractionalIntX();
773     }
774 
775     const SkPMColor* SK_RESTRICT src = s.fPixmap.addr32(0, dstY);
776     const SkFractionalInt dx = s.fInvSxFractionalInt;
777 
778     // Check if we're safely inside [0...maxX] so no need to clamp each computed index.
779     //
780     if ((uint64_t)SkFractionalIntToInt(fx) <= maxX &&
781         (uint64_t)SkFractionalIntToInt(fx + dx * (count - 1)) <= maxX)
782     {
783         int count4 = count >> 2;
784         for (int i = 0; i < count4; ++i) {
785             SkPMColor src0 = src[SkFractionalIntToInt(fx)]; fx += dx;
786             SkPMColor src1 = src[SkFractionalIntToInt(fx)]; fx += dx;
787             SkPMColor src2 = src[SkFractionalIntToInt(fx)]; fx += dx;
788             SkPMColor src3 = src[SkFractionalIntToInt(fx)]; fx += dx;
789             dst[0] = src0;
790             dst[1] = src1;
791             dst[2] = src2;
792             dst[3] = src3;
793             dst += 4;
794         }
795         for (int i = (count4 << 2); i < count; ++i) {
796             unsigned index = SkFractionalIntToInt(fx);
797             SkASSERT(index <= maxX);
798             *dst++ = src[index];
799             fx += dx;
800         }
801     } else {
802         for (int i = 0; i < count; ++i) {
803             dst[i] = src[SkClampMax(SkFractionalIntToInt(fx), maxX)];
804             fx += dx;
805         }
806     }
807 }
808