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