SkBitmapProcState.cpp revision 6bb92bc0b52d31f3ded38927cdefbeb13a3df87a
1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com
2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com/*
3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2011 Google Inc.
4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com *
5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be
6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file.
7ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com */
88a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkBitmapProcState.h"
98a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkColorPriv.h"
108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkFilterProc.h"
118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkPaint.h"
128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkShader.h"   // for tilemodes
133ada0efdc8de8316df8113ec54ffd1a3f33ecd21digit@google.com#include "SkUtilsArm.h"
143ada0efdc8de8316df8113ec54ffd1a3f33ecd21digit@google.com
153ada0efdc8de8316df8113ec54ffd1a3f33ecd21digit@google.com#if !SK_ARM_NEON_IS_NONE
163ada0efdc8de8316df8113ec54ffd1a3f33ecd21digit@google.com// These are defined in src/opts/SkBitmapProcState_arm_neon.cpp
173ada0efdc8de8316df8113ec54ffd1a3f33ecd21digit@google.comextern const SkBitmapProcState::SampleProc16 gSkBitmapProcStateSample16_neon[];
183ada0efdc8de8316df8113ec54ffd1a3f33ecd21digit@google.comextern const SkBitmapProcState::SampleProc32 gSkBitmapProcStateSample32_neon[];
193ada0efdc8de8316df8113ec54ffd1a3f33ecd21digit@google.comextern void  S16_D16_filter_DX_neon(const SkBitmapProcState&, const uint32_t*, int, uint16_t*);
203ada0efdc8de8316df8113ec54ffd1a3f33ecd21digit@google.comextern void  Clamp_S16_D16_filter_DX_shaderproc_neon(const SkBitmapProcState&, int, int, uint16_t*, int);
213ada0efdc8de8316df8113ec54ffd1a3f33ecd21digit@google.comextern void  Repeat_S16_D16_filter_DX_shaderproc_neon(const SkBitmapProcState&, int, int, uint16_t*, int);
223ada0efdc8de8316df8113ec54ffd1a3f33ecd21digit@google.comextern void  SI8_opaque_D32_filter_DX_neon(const SkBitmapProcState&, const uint32_t*, int, SkPMColor*);
233ada0efdc8de8316df8113ec54ffd1a3f33ecd21digit@google.comextern void  SI8_opaque_D32_filter_DX_shaderproc_neon(const SkBitmapProcState&, int, int, uint32_t*, int);
243ada0efdc8de8316df8113ec54ffd1a3f33ecd21digit@google.comextern void  Clamp_SI8_opaque_D32_filter_DX_shaderproc_neon(const SkBitmapProcState&, int, int, uint32_t*, int);
253ada0efdc8de8316df8113ec54ffd1a3f33ecd21digit@google.com#endif
263ada0efdc8de8316df8113ec54ffd1a3f33ecd21digit@google.com
273ada0efdc8de8316df8113ec54ffd1a3f33ecd21digit@google.com#if !SK_ARM_NEON_IS_ALWAYS
283ada0efdc8de8316df8113ec54ffd1a3f33ecd21digit@google.com#define   NAME_WRAP(x)  x
293ada0efdc8de8316df8113ec54ffd1a3f33ecd21digit@google.com#include "SkBitmapProcState_filter.h"
303ada0efdc8de8316df8113ec54ffd1a3f33ecd21digit@google.com#include "SkBitmapProcState_procs.h"
313ada0efdc8de8316df8113ec54ffd1a3f33ecd21digit@google.com#endif
32b577b41c8ec26c21ae599e80a2707d42f03eaa60reed@android.com
33a44b4cc7976b06caf3a3f6b7913c2af92eb32217reed@android.com///////////////////////////////////////////////////////////////////////////////
34a44b4cc7976b06caf3a3f6b7913c2af92eb32217reed@android.com
35c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com/**
36c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com *  For the purposes of drawing bitmaps, if a matrix is "almost" translate
37c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com *  go ahead and treat it as if it were, so that subsequent code can go fast.
38c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com */
39c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.comstatic bool just_trans_clamp(const SkMatrix& matrix, const SkBitmap& bitmap) {
40c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com    SkMatrix::TypeMask mask = matrix.getType();
41c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com
42c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com    if (mask & (SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Mask)) {
43c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com        return false;
44c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com    }
45c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com    if (mask & SkMatrix::kScale_Mask) {
46c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com        SkScalar sx = matrix[SkMatrix::kMScaleX];
47c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com        SkScalar sy = matrix[SkMatrix::kMScaleY];
48c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com        int w = bitmap.width();
49c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com        int h = bitmap.height();
50c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com        int sw = SkScalarRound(SkScalarMul(sx, SkIntToScalar(w)));
51c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com        int sh = SkScalarRound(SkScalarMul(sy, SkIntToScalar(h)));
52c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com        return sw == w && sh == h;
53c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com    }
54c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com    // if we got here, we're either kTranslate_Mask or identity
55c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com    return true;
56c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com}
57c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com
58c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.comstatic bool just_trans_general(const SkMatrix& matrix) {
59c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com    SkMatrix::TypeMask mask = matrix.getType();
60c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com
61c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com    if (mask & (SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Mask)) {
62c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com        return false;
63c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com    }
64c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com    if (mask & SkMatrix::kScale_Mask) {
65c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com        const SkScalar tol = SK_Scalar1 / 32768;
66989a95ea77230e8347da18876e1bd5f39a78ebb5skia.committer@gmail.com
67c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com        if (!SkScalarNearlyZero(matrix[SkMatrix::kMScaleX] - SK_Scalar1, tol)) {
68c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com            return false;
69c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com        }
70c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com        if (!SkScalarNearlyZero(matrix[SkMatrix::kMScaleY] - SK_Scalar1, tol)) {
71c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com            return false;
72c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com        }
73c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com    }
74c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com    // if we got here, treat us as either kTranslate_Mask or identity
75c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com    return true;
76c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com}
77c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com
78c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com///////////////////////////////////////////////////////////////////////////////
79c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com
808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic bool valid_for_filtering(unsigned dimension) {
818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // for filtering, width and height must fit in 14bits, since we use steal
828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // 2 bits from each to store our 4bit subpixel data
838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return (dimension & ~0x3FFF) == 0;
848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkBitmapProcState::chooseProcs(const SkMatrix& inv, const SkPaint& paint) {
878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (fOrigBitmap.width() == 0 || fOrigBitmap.height() == 0) {
888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return false;
898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
9007d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com
918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const SkMatrix* m;
9207d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    bool trivial_matrix = (inv.getType() & ~SkMatrix::kTranslate_Mask) == 0;
9307d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    bool clamp_clamp = SkShader::kClamp_TileMode == fTileModeX &&
94c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com    SkShader::kClamp_TileMode == fTileModeY;
95a44b4cc7976b06caf3a3f6b7913c2af92eb32217reed@android.com
9607d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    if (clamp_clamp || trivial_matrix) {
978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        m = &inv;
988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    } else {
998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fUnitInvMatrix = inv;
1008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fUnitInvMatrix.postIDiv(fOrigBitmap.width(), fOrigBitmap.height());
1018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        m = &fUnitInvMatrix;
1028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
10307d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com
1048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fBitmap = &fOrigBitmap;
1058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (fOrigBitmap.hasMipMap()) {
1068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        int shift = fOrigBitmap.extractMipLevel(&fMipBitmap,
1078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                                SkScalarToFixed(m->getScaleX()),
1088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                                SkScalarToFixed(m->getSkewY()));
109989a95ea77230e8347da18876e1bd5f39a78ebb5skia.committer@gmail.com
1108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (shift > 0) {
1118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (m != &fUnitInvMatrix) {
1128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                fUnitInvMatrix = *m;
1138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                m = &fUnitInvMatrix;
1148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
1158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkScalar scale = SkFixedToScalar(SK_Fixed1 >> shift);
1178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fUnitInvMatrix.postScale(scale, scale);
118fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
1198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            // now point here instead of fOrigBitmap
1208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fBitmap = &fMipBitmap;
1218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
1228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
124c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com    // wack our matrix to exactly no-scale, if we're really close to begin with
125c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com    {
126c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com        bool fixupMatrix = clamp_clamp ?
127c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com        just_trans_clamp(*m, *fBitmap) : just_trans_general(*m);
128c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com        if (fixupMatrix) {
129c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com            if (m != &fUnitInvMatrix) {    // can't mutate the original
130c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com                fUnitInvMatrix = inv;
131c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com                m = &fUnitInvMatrix;
132c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com            }
133c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com            fUnitInvMatrix.set(SkMatrix::kMScaleX, SK_Scalar1);
134c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com            fUnitInvMatrix.set(SkMatrix::kMScaleY, SK_Scalar1);
135c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com        }
136c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com    }
137c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com
138c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com    // Below this point, we should never refer to the inv parameter, since we
139c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com    // may be using a munged version for "our" inverse.
140989a95ea77230e8347da18876e1bd5f39a78ebb5skia.committer@gmail.com
1418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fInvMatrix      = m;
1428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fInvProc        = m->getMapXYProc();
1438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fInvType        = m->getType();
1448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fInvSx          = SkScalarToFixed(m->getScaleX());
1454bc0a9db18d58698057b8f38a6f21537aca4ddcfreed@google.com    fInvSxFractionalInt = SkScalarToFractionalInt(m->getScaleX());
1468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fInvKy          = SkScalarToFixed(m->getSkewY());
147411215ae2b9a36ff6e262f77d7fb5071cc084f00reed@google.com    fInvKyFractionalInt = SkScalarToFractionalInt(m->getSkewY());
1488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fAlphaScale = SkAlpha255To256(paint.getAlpha());
1508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // pick-up filtering from the paint, but only if the matrix is
1528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // more complex than identity/translate (i.e. no need to pay the cost
1538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // of filtering if we're not scaled etc.).
1548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // note: we explicitly check inv, since m might be scaled due to unitinv
1558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    //       trickery, but we don't want to see that for this test
1568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fDoFilter = paint.isFilterBitmap() &&
157c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com                (fInvType > SkMatrix::kTranslate_Mask &&
1588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                 valid_for_filtering(fBitmap->width() | fBitmap->height()));
1598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1607a99eb1c63d4327d352af09ea59f039f014e4028reed@android.com    fShaderProc32 = NULL;
1617a99eb1c63d4327d352af09ea59f039f014e4028reed@android.com    fShaderProc16 = NULL;
1627a99eb1c63d4327d352af09ea59f039f014e4028reed@android.com    fSampleProc32 = NULL;
1637a99eb1c63d4327d352af09ea59f039f014e4028reed@android.com    fSampleProc16 = NULL;
16448534f96b9ccb747cecbdf3818bfbd3523a4d034reed@android.com
16507d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    fMatrixProc = this->chooseMatrixProc(trivial_matrix);
1668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (NULL == fMatrixProc) {
1678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return false;
1688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    ///////////////////////////////////////////////////////////////////////
171fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
1728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int index = 0;
1738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (fAlphaScale < 256) {  // note: this distinction is not used for D16
1748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        index |= 1;
1758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) {
1778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        index |= 2;
1788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (fDoFilter) {
1808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        index |= 4;
1818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // bits 3,4,5 encoding the source bitmap format
1838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    switch (fBitmap->config()) {
1848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        case SkBitmap::kARGB_8888_Config:
1858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            index |= 0;
1868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            break;
1878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        case SkBitmap::kRGB_565_Config:
1888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            index |= 8;
1898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            break;
1908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        case SkBitmap::kIndex8_Config:
1918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            index |= 16;
1928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            break;
1938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        case SkBitmap::kARGB_4444_Config:
1948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            index |= 24;
1958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            break;
1968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        case SkBitmap::kA8_Config:
1978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            index |= 32;
1988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fPaintPMColor = SkPreMultiplyColor(paint.getColor());
1993469c76c40790b409621fd7eff34f56240718549reed@android.com            break;
2008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        default:
2018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            return false;
2028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
2038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2043ada0efdc8de8316df8113ec54ffd1a3f33ecd21digit@google.com#if !SK_ARM_NEON_IS_ALWAYS
2053ada0efdc8de8316df8113ec54ffd1a3f33ecd21digit@google.com    static const SampleProc32 gSkBitmapProcStateSample32[] = {
2068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        S32_opaque_D32_nofilter_DXDY,
2078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        S32_alpha_D32_nofilter_DXDY,
2088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        S32_opaque_D32_nofilter_DX,
2098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        S32_alpha_D32_nofilter_DX,
2108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        S32_opaque_D32_filter_DXDY,
2118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        S32_alpha_D32_filter_DXDY,
2128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        S32_opaque_D32_filter_DX,
2138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        S32_alpha_D32_filter_DX,
214fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
2158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        S16_opaque_D32_nofilter_DXDY,
2168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        S16_alpha_D32_nofilter_DXDY,
2178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        S16_opaque_D32_nofilter_DX,
2188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        S16_alpha_D32_nofilter_DX,
2198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        S16_opaque_D32_filter_DXDY,
2208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        S16_alpha_D32_filter_DXDY,
2218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        S16_opaque_D32_filter_DX,
2228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        S16_alpha_D32_filter_DX,
223fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
2248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SI8_opaque_D32_nofilter_DXDY,
2258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SI8_alpha_D32_nofilter_DXDY,
2268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SI8_opaque_D32_nofilter_DX,
2278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SI8_alpha_D32_nofilter_DX,
2288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SI8_opaque_D32_filter_DXDY,
2298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SI8_alpha_D32_filter_DXDY,
2308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SI8_opaque_D32_filter_DX,
2318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SI8_alpha_D32_filter_DX,
232fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
2338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        S4444_opaque_D32_nofilter_DXDY,
2348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        S4444_alpha_D32_nofilter_DXDY,
2358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        S4444_opaque_D32_nofilter_DX,
2368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        S4444_alpha_D32_nofilter_DX,
2378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        S4444_opaque_D32_filter_DXDY,
2388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        S4444_alpha_D32_filter_DXDY,
2398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        S4444_opaque_D32_filter_DX,
2408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        S4444_alpha_D32_filter_DX,
241fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
2428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        // A8 treats alpha/opauqe the same (equally efficient)
2438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SA8_alpha_D32_nofilter_DXDY,
2448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SA8_alpha_D32_nofilter_DXDY,
2458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SA8_alpha_D32_nofilter_DX,
2468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SA8_alpha_D32_nofilter_DX,
2478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SA8_alpha_D32_filter_DXDY,
2488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SA8_alpha_D32_filter_DXDY,
2498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SA8_alpha_D32_filter_DX,
2508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SA8_alpha_D32_filter_DX
2518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    };
252fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
2533ada0efdc8de8316df8113ec54ffd1a3f33ecd21digit@google.com    static const SampleProc16 gSkBitmapProcStateSample16[] = {
2548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        S32_D16_nofilter_DXDY,
2558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        S32_D16_nofilter_DX,
2568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        S32_D16_filter_DXDY,
2578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        S32_D16_filter_DX,
258fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
2598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        S16_D16_nofilter_DXDY,
2608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        S16_D16_nofilter_DX,
2618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        S16_D16_filter_DXDY,
2628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        S16_D16_filter_DX,
263fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
2648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SI8_D16_nofilter_DXDY,
2658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SI8_D16_nofilter_DX,
2668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SI8_D16_filter_DXDY,
2678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SI8_D16_filter_DX,
268fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
2698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        // Don't support 4444 -> 565
2708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        NULL, NULL, NULL, NULL,
2718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        // Don't support A8 -> 565
2728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        NULL, NULL, NULL, NULL
2738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    };
2743ada0efdc8de8316df8113ec54ffd1a3f33ecd21digit@google.com#endif
27548534f96b9ccb747cecbdf3818bfbd3523a4d034reed@android.com
2763ada0efdc8de8316df8113ec54ffd1a3f33ecd21digit@google.com    fSampleProc32 = SK_ARM_NEON_WRAP(gSkBitmapProcStateSample32)[index];
2778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    index >>= 1;    // shift away any opaque/alpha distinction
2783ada0efdc8de8316df8113ec54ffd1a3f33ecd21digit@google.com    fSampleProc16 = SK_ARM_NEON_WRAP(gSkBitmapProcStateSample16)[index];
2798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
280a44b4cc7976b06caf3a3f6b7913c2af92eb32217reed@android.com    // our special-case shaderprocs
2813ada0efdc8de8316df8113ec54ffd1a3f33ecd21digit@google.com    if (SK_ARM_NEON_WRAP(S16_D16_filter_DX) == fSampleProc16) {
282aa9152abbca3a958a9379f4e5067a1c37486d677reed@android.com        if (clamp_clamp) {
2833ada0efdc8de8316df8113ec54ffd1a3f33ecd21digit@google.com            fShaderProc16 = SK_ARM_NEON_WRAP(Clamp_S16_D16_filter_DX_shaderproc);
284aa9152abbca3a958a9379f4e5067a1c37486d677reed@android.com        } else if (SkShader::kRepeat_TileMode == fTileModeX &&
285aa9152abbca3a958a9379f4e5067a1c37486d677reed@android.com                   SkShader::kRepeat_TileMode == fTileModeY) {
2863ada0efdc8de8316df8113ec54ffd1a3f33ecd21digit@google.com            fShaderProc16 = SK_ARM_NEON_WRAP(Repeat_S16_D16_filter_DX_shaderproc);
287aa9152abbca3a958a9379f4e5067a1c37486d677reed@android.com        }
2883ada0efdc8de8316df8113ec54ffd1a3f33ecd21digit@google.com    } else if (SK_ARM_NEON_WRAP(SI8_opaque_D32_filter_DX) == fSampleProc32 && clamp_clamp) {
2893ada0efdc8de8316df8113ec54ffd1a3f33ecd21digit@google.com        fShaderProc32 = SK_ARM_NEON_WRAP(Clamp_SI8_opaque_D32_filter_DX_shaderproc);
290a44b4cc7976b06caf3a3f6b7913c2af92eb32217reed@android.com    }
291c9a1d4b519c2db8e43e54fef068c46462d2f8a4breed@android.com
2929a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com    if (NULL == fShaderProc32) {
2939a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com        fShaderProc32 = this->chooseShaderProc32();
2949a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com    }
2959a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com
296c9a1d4b519c2db8e43e54fef068c46462d2f8a4breed@android.com    // see if our platform has any accelerated overrides
297c9a1d4b519c2db8e43e54fef068c46462d2f8a4breed@android.com    this->platformProcs();
2988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return true;
2998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
3008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3019a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.comstatic void Clamp_S32_D32_nofilter_trans_shaderproc(const SkBitmapProcState& s,
3029a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com                                                    int x, int y,
3039a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com                                                    SkPMColor* SK_RESTRICT colors,
3049a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com                                                    int count) {
3059a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com    SkASSERT(((s.fInvType & ~SkMatrix::kTranslate_Mask)) == 0);
3069a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com    SkASSERT(s.fInvKy == 0);
3079a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com    SkASSERT(count > 0 && colors != NULL);
3089a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com    SkASSERT(!s.fDoFilter);
30920c301bd1aa4578c6d0abb23ac2c72b5fbb436dbskia.committer@gmail.com
3109a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com    const int maxX = s.fBitmap->width() - 1;
311f7698de60e2cfecf84cb84f957e6fe69325fe67freed@google.com    const int maxY = s.fBitmap->height() - 1;
312f7698de60e2cfecf84cb84f957e6fe69325fe67freed@google.com    int ix = s.fFilterOneX + x;
313f7698de60e2cfecf84cb84f957e6fe69325fe67freed@google.com    int iy = SkClampMax(s.fFilterOneY + y, maxY);
314f7698de60e2cfecf84cb84f957e6fe69325fe67freed@google.com#ifdef SK_DEBUG
3159a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com    {
3169a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com        SkPoint pt;
3179a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com        s.fInvProc(*s.fInvMatrix, SkIntToScalar(x) + SK_ScalarHalf,
3189a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com                   SkIntToScalar(y) + SK_ScalarHalf, &pt);
319f7698de60e2cfecf84cb84f957e6fe69325fe67freed@google.com        int iy2 = SkClampMax(SkScalarFloorToInt(pt.fY), maxY);
320f7698de60e2cfecf84cb84f957e6fe69325fe67freed@google.com        int ix2 = SkScalarFloorToInt(pt.fX);
32120c301bd1aa4578c6d0abb23ac2c72b5fbb436dbskia.committer@gmail.com
322f7698de60e2cfecf84cb84f957e6fe69325fe67freed@google.com        SkASSERT(iy == iy2);
323f7698de60e2cfecf84cb84f957e6fe69325fe67freed@google.com        SkASSERT(ix == ix2);
3249a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com    }
325f7698de60e2cfecf84cb84f957e6fe69325fe67freed@google.com#endif
326f7698de60e2cfecf84cb84f957e6fe69325fe67freed@google.com    const SkPMColor* row = s.fBitmap->getAddr32(0, iy);
32720c301bd1aa4578c6d0abb23ac2c72b5fbb436dbskia.committer@gmail.com
3289a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com    // clamp to the left
3299a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com    if (ix < 0) {
3309a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com        int n = SkMin32(-ix, count);
3319a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com        sk_memset32(colors, row[0], n);
3329a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com        count -= n;
3339a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com        if (0 == count) {
3349a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com            return;
3359a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com        }
3369a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com        colors += n;
3379a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com        SkASSERT(-ix == n);
3389a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com        ix = 0;
3399a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com    }
3409a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com    // copy the middle
3419a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com    if (ix <= maxX) {
3429a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com        int n = SkMin32(maxX - ix + 1, count);
3439a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com        memcpy(colors, row + ix, n * sizeof(SkPMColor));
3449a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com        count -= n;
3459a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com        if (0 == count) {
3469a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com            return;
3479a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com        }
3489a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com        colors += n;
3499a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com    }
3509a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com    SkASSERT(count > 0);
3519a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com    // clamp to the right
3529a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com    sk_memset32(colors, row[maxX], count);
3539a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com}
3549a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com
355a8d99307717c5fe02043969db0566c236a08c313reed@google.comstatic inline int sk_int_mod(int x, int n) {
356a8d99307717c5fe02043969db0566c236a08c313reed@google.com    SkASSERT(n > 0);
357a8d99307717c5fe02043969db0566c236a08c313reed@google.com    if ((unsigned)x >= (unsigned)n) {
358a8d99307717c5fe02043969db0566c236a08c313reed@google.com        if (x < 0) {
359a8d99307717c5fe02043969db0566c236a08c313reed@google.com            x = n + ~(~x % n);
360a8d99307717c5fe02043969db0566c236a08c313reed@google.com        } else {
361a8d99307717c5fe02043969db0566c236a08c313reed@google.com            x = x % n;
362a8d99307717c5fe02043969db0566c236a08c313reed@google.com        }
363a8d99307717c5fe02043969db0566c236a08c313reed@google.com    }
364a8d99307717c5fe02043969db0566c236a08c313reed@google.com    return x;
365a8d99307717c5fe02043969db0566c236a08c313reed@google.com}
366a8d99307717c5fe02043969db0566c236a08c313reed@google.com
367a8d99307717c5fe02043969db0566c236a08c313reed@google.comstatic void Repeat_S32_D32_nofilter_trans_shaderproc(const SkBitmapProcState& s,
368a8d99307717c5fe02043969db0566c236a08c313reed@google.com                                                     int x, int y,
369a8d99307717c5fe02043969db0566c236a08c313reed@google.com                                                     SkPMColor* SK_RESTRICT colors,
370a8d99307717c5fe02043969db0566c236a08c313reed@google.com                                                     int count) {
371a8d99307717c5fe02043969db0566c236a08c313reed@google.com    SkASSERT(((s.fInvType & ~SkMatrix::kTranslate_Mask)) == 0);
372a8d99307717c5fe02043969db0566c236a08c313reed@google.com    SkASSERT(s.fInvKy == 0);
373a8d99307717c5fe02043969db0566c236a08c313reed@google.com    SkASSERT(count > 0 && colors != NULL);
374a8d99307717c5fe02043969db0566c236a08c313reed@google.com    SkASSERT(!s.fDoFilter);
37520c301bd1aa4578c6d0abb23ac2c72b5fbb436dbskia.committer@gmail.com
376a8d99307717c5fe02043969db0566c236a08c313reed@google.com    const int stopX = s.fBitmap->width();
377a8d99307717c5fe02043969db0566c236a08c313reed@google.com    const int stopY = s.fBitmap->height();
378a8d99307717c5fe02043969db0566c236a08c313reed@google.com    int ix = s.fFilterOneX + x;
379a8d99307717c5fe02043969db0566c236a08c313reed@google.com    int iy = sk_int_mod(s.fFilterOneY + y, stopY);
380a8d99307717c5fe02043969db0566c236a08c313reed@google.com#ifdef SK_DEBUG
381a8d99307717c5fe02043969db0566c236a08c313reed@google.com    {
382a8d99307717c5fe02043969db0566c236a08c313reed@google.com        SkPoint pt;
383a8d99307717c5fe02043969db0566c236a08c313reed@google.com        s.fInvProc(*s.fInvMatrix, SkIntToScalar(x) + SK_ScalarHalf,
384a8d99307717c5fe02043969db0566c236a08c313reed@google.com                   SkIntToScalar(y) + SK_ScalarHalf, &pt);
385a8d99307717c5fe02043969db0566c236a08c313reed@google.com        int iy2 = sk_int_mod(SkScalarFloorToInt(pt.fY), stopY);
386a8d99307717c5fe02043969db0566c236a08c313reed@google.com        int ix2 = SkScalarFloorToInt(pt.fX);
38720c301bd1aa4578c6d0abb23ac2c72b5fbb436dbskia.committer@gmail.com
388a8d99307717c5fe02043969db0566c236a08c313reed@google.com        SkASSERT(iy == iy2);
389a8d99307717c5fe02043969db0566c236a08c313reed@google.com        SkASSERT(ix == ix2);
390a8d99307717c5fe02043969db0566c236a08c313reed@google.com    }
391a8d99307717c5fe02043969db0566c236a08c313reed@google.com#endif
392a8d99307717c5fe02043969db0566c236a08c313reed@google.com    const SkPMColor* row = s.fBitmap->getAddr32(0, iy);
393a8d99307717c5fe02043969db0566c236a08c313reed@google.com
394a8d99307717c5fe02043969db0566c236a08c313reed@google.com    ix = sk_int_mod(ix, stopX);
395a8d99307717c5fe02043969db0566c236a08c313reed@google.com    for (;;) {
396a8d99307717c5fe02043969db0566c236a08c313reed@google.com        int n = SkMin32(stopX - ix, count);
397a8d99307717c5fe02043969db0566c236a08c313reed@google.com        memcpy(colors, row + ix, n * sizeof(SkPMColor));
398a8d99307717c5fe02043969db0566c236a08c313reed@google.com        count -= n;
399a8d99307717c5fe02043969db0566c236a08c313reed@google.com        if (0 == count) {
400a8d99307717c5fe02043969db0566c236a08c313reed@google.com            return;
401a8d99307717c5fe02043969db0566c236a08c313reed@google.com        }
402a8d99307717c5fe02043969db0566c236a08c313reed@google.com        colors += n;
403a8d99307717c5fe02043969db0566c236a08c313reed@google.com        ix = 0;
404a8d99307717c5fe02043969db0566c236a08c313reed@google.com    }
405a8d99307717c5fe02043969db0566c236a08c313reed@google.com}
406a8d99307717c5fe02043969db0566c236a08c313reed@google.com
4076bb92bc0b52d31f3ded38927cdefbeb13a3df87areed@google.comstatic void DoNothing_shaderproc(const SkBitmapProcState&, int x, int y,
4086bb92bc0b52d31f3ded38927cdefbeb13a3df87areed@google.com                                 SkPMColor* SK_RESTRICT colors, int count) {
4096bb92bc0b52d31f3ded38927cdefbeb13a3df87areed@google.com    // if we get called, the matrix is too tricky, so we just draw nothing
4106bb92bc0b52d31f3ded38927cdefbeb13a3df87areed@google.com    sk_memset32(colors, 0, count);
4116bb92bc0b52d31f3ded38927cdefbeb13a3df87areed@google.com}
4126bb92bc0b52d31f3ded38927cdefbeb13a3df87areed@google.com
4136bb92bc0b52d31f3ded38927cdefbeb13a3df87areed@google.combool SkBitmapProcState::setupForTranslate() {
414a8d99307717c5fe02043969db0566c236a08c313reed@google.com    SkPoint pt;
415a8d99307717c5fe02043969db0566c236a08c313reed@google.com    fInvProc(*fInvMatrix, SK_ScalarHalf, SK_ScalarHalf, &pt);
4166bb92bc0b52d31f3ded38927cdefbeb13a3df87areed@google.com
4176bb92bc0b52d31f3ded38927cdefbeb13a3df87areed@google.com    /*
4186bb92bc0b52d31f3ded38927cdefbeb13a3df87areed@google.com     *  if the translate is larger than our ints, we can get random results, or
4196bb92bc0b52d31f3ded38927cdefbeb13a3df87areed@google.com     *  worse, we might get 0x80000000, which wreaks havoc on us, since we can't
4206bb92bc0b52d31f3ded38927cdefbeb13a3df87areed@google.com     *  negate it.
4216bb92bc0b52d31f3ded38927cdefbeb13a3df87areed@google.com     */
4226bb92bc0b52d31f3ded38927cdefbeb13a3df87areed@google.com    const SkScalar too_big = SkIntToScalar(1 << 30);
4236bb92bc0b52d31f3ded38927cdefbeb13a3df87areed@google.com    if (SkScalarAbs(pt.fX) > too_big || SkScalarAbs(pt.fY) > too_big) {
4246bb92bc0b52d31f3ded38927cdefbeb13a3df87areed@google.com        return false;
4256bb92bc0b52d31f3ded38927cdefbeb13a3df87areed@google.com    }
4266bb92bc0b52d31f3ded38927cdefbeb13a3df87areed@google.com
427a8d99307717c5fe02043969db0566c236a08c313reed@google.com    // Since we know we're not filtered, we re-purpose these fields allow
428a8d99307717c5fe02043969db0566c236a08c313reed@google.com    // us to go from device -> src coordinates w/ just an integer add,
429a8d99307717c5fe02043969db0566c236a08c313reed@google.com    // rather than running through the inverse-matrix
430a8d99307717c5fe02043969db0566c236a08c313reed@google.com    fFilterOneX = SkScalarFloorToInt(pt.fX);
431a8d99307717c5fe02043969db0566c236a08c313reed@google.com    fFilterOneY = SkScalarFloorToInt(pt.fY);
4326bb92bc0b52d31f3ded38927cdefbeb13a3df87areed@google.com    return true;
433a8d99307717c5fe02043969db0566c236a08c313reed@google.com}
434a8d99307717c5fe02043969db0566c236a08c313reed@google.com
4359a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.comSkBitmapProcState::ShaderProc32 SkBitmapProcState::chooseShaderProc32() {
4369a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com    if (fAlphaScale < 256) {
4379a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com        return NULL;
4389a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com    }
4399a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com    if (fInvType > SkMatrix::kTranslate_Mask) {
4409a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com        return NULL;
4419a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com    }
4429a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com    if (fDoFilter) {
4439a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com        return NULL;
4449a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com    }
4459a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com    if (SkBitmap::kARGB_8888_Config != fBitmap->config()) {
4469a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com        return NULL;
4479a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com    }
4489a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com
449a8d99307717c5fe02043969db0566c236a08c313reed@google.com    SkShader::TileMode tx = (SkShader::TileMode)fTileModeX;
450a8d99307717c5fe02043969db0566c236a08c313reed@google.com    SkShader::TileMode ty = (SkShader::TileMode)fTileModeY;
451a8d99307717c5fe02043969db0566c236a08c313reed@google.com
452a8d99307717c5fe02043969db0566c236a08c313reed@google.com    if (SkShader::kClamp_TileMode == tx && SkShader::kClamp_TileMode == ty) {
4536bb92bc0b52d31f3ded38927cdefbeb13a3df87areed@google.com        if (this->setupForTranslate()) {
4546bb92bc0b52d31f3ded38927cdefbeb13a3df87areed@google.com            return Clamp_S32_D32_nofilter_trans_shaderproc;
4556bb92bc0b52d31f3ded38927cdefbeb13a3df87areed@google.com        }
4566bb92bc0b52d31f3ded38927cdefbeb13a3df87areed@google.com        return DoNothing_shaderproc;
4579a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com    }
458a8d99307717c5fe02043969db0566c236a08c313reed@google.com    if (SkShader::kRepeat_TileMode == tx && SkShader::kRepeat_TileMode == ty) {
4596bb92bc0b52d31f3ded38927cdefbeb13a3df87areed@google.com        if (this->setupForTranslate()) {
4606bb92bc0b52d31f3ded38927cdefbeb13a3df87areed@google.com            return Repeat_S32_D32_nofilter_trans_shaderproc;
4616bb92bc0b52d31f3ded38927cdefbeb13a3df87areed@google.com        }
4626bb92bc0b52d31f3ded38927cdefbeb13a3df87areed@google.com        return DoNothing_shaderproc;
463a8d99307717c5fe02043969db0566c236a08c313reed@google.com    }
4649a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com    return NULL;
4659a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com}
4669a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com
4674c128c4917acf25c2cc5d1bd22282a4e1bb53d96reed@android.com///////////////////////////////////////////////////////////////////////////////
4689fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com
4699fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com#ifdef SK_DEBUG
4709fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com
4719fe287bd07baa6d9e890b627c102bba562954f7dreed@google.comstatic void check_scale_nofilter(uint32_t bitmapXY[], int count,
4729fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com                                 unsigned mx, unsigned my) {
4739fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com    unsigned y = *bitmapXY++;
4749fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com    SkASSERT(y < my);
475fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
4769fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com    const uint16_t* xptr = reinterpret_cast<const uint16_t*>(bitmapXY);
4779fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com    for (int i = 0; i < count; ++i) {
4789fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com        SkASSERT(xptr[i] < mx);
4799fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com    }
4809fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com}
4819fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com
4829fe287bd07baa6d9e890b627c102bba562954f7dreed@google.comstatic void check_scale_filter(uint32_t bitmapXY[], int count,
4839fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com                                 unsigned mx, unsigned my) {
4849fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com    uint32_t YY = *bitmapXY++;
4859fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com    unsigned y0 = YY >> 18;
486fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com    unsigned y1 = YY & 0x3FFF;
4879fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com    SkASSERT(y0 < my);
4889fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com    SkASSERT(y1 < my);
489fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
4909fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com    for (int i = 0; i < count; ++i) {
4919fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com        uint32_t XX = bitmapXY[i];
4929fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com        unsigned x0 = XX >> 18;
4939fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com        unsigned x1 = XX & 0x3FFF;
4949fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com        SkASSERT(x0 < mx);
4959fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com        SkASSERT(x1 < mx);
4969fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com    }
4979fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com}
4989fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com
4999fe287bd07baa6d9e890b627c102bba562954f7dreed@google.comstatic void check_affine_nofilter(uint32_t bitmapXY[], int count,
5009fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com                                 unsigned mx, unsigned my) {
5019fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com    for (int i = 0; i < count; ++i) {
5029fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com        uint32_t XY = bitmapXY[i];
5039fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com        unsigned x = XY & 0xFFFF;
5049fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com        unsigned y = XY >> 16;
5059fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com        SkASSERT(x < mx);
5069fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com        SkASSERT(y < my);
5079fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com    }
5089fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com}
5099fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com
5109fe287bd07baa6d9e890b627c102bba562954f7dreed@google.comstatic void check_affine_filter(uint32_t bitmapXY[], int count,
5119fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com                                 unsigned mx, unsigned my) {
5129fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com    for (int i = 0; i < count; ++i) {
5139fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com        uint32_t YY = *bitmapXY++;
5149fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com        unsigned y0 = YY >> 18;
5159fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com        unsigned y1 = YY & 0x3FFF;
5169fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com        SkASSERT(y0 < my);
5179fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com        SkASSERT(y1 < my);
5189fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com
5199fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com        uint32_t XX = *bitmapXY++;
5209fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com        unsigned x0 = XX >> 18;
5219fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com        unsigned x1 = XX & 0x3FFF;
5229fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com        SkASSERT(x0 < mx);
5239fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com        SkASSERT(x1 < mx);
5249fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com    }
5259fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com}
5269fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com
5279fe287bd07baa6d9e890b627c102bba562954f7dreed@google.comvoid SkBitmapProcState::DebugMatrixProc(const SkBitmapProcState& state,
5289fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com                                        uint32_t bitmapXY[], int count,
5299fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com                                        int x, int y) {
5309fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com    SkASSERT(bitmapXY);
5319fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com    SkASSERT(count > 0);
5329fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com
5339fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com    state.fMatrixProc(state, bitmapXY, count, x, y);
5349fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com
5359fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com    void (*proc)(uint32_t bitmapXY[], int count, unsigned mx, unsigned my);
5369fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com
5379fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com    // There are four formats possible:
5389fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com    //  scale -vs- affine
5399fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com    //  filter -vs- nofilter
5409fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com    if (state.fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) {
5419fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com        proc = state.fDoFilter ? check_scale_filter : check_scale_nofilter;
5429fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com    } else {
5439fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com        proc = state.fDoFilter ? check_affine_filter : check_affine_nofilter;
5449fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com    }
5459fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com    proc(bitmapXY, count, state.fBitmap->width(), state.fBitmap->height());
5469fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com}
5479fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com
5489fe287bd07baa6d9e890b627c102bba562954f7dreed@google.comSkBitmapProcState::MatrixProc SkBitmapProcState::getMatrixProc() const {
5499fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com    return DebugMatrixProc;
5509fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com}
5519fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com
5529fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com#endif
5539fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com
5549fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com///////////////////////////////////////////////////////////////////////////////
5554c128c4917acf25c2cc5d1bd22282a4e1bb53d96reed@android.com/*
5564c128c4917acf25c2cc5d1bd22282a4e1bb53d96reed@android.com    The storage requirements for the different matrix procs are as follows,
5574c128c4917acf25c2cc5d1bd22282a4e1bb53d96reed@android.com    where each X or Y is 2 bytes, and N is the number of pixels/elements:
558fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
5594c128c4917acf25c2cc5d1bd22282a4e1bb53d96reed@android.com    scale/translate     nofilter      Y(4bytes) + N * X
5604c128c4917acf25c2cc5d1bd22282a4e1bb53d96reed@android.com    affine/perspective  nofilter      N * (X Y)
5614c128c4917acf25c2cc5d1bd22282a4e1bb53d96reed@android.com    scale/translate     filter        Y Y + N * (X X)
5624c128c4917acf25c2cc5d1bd22282a4e1bb53d96reed@android.com    affine/perspective  filter        N * (Y Y X X)
5634c128c4917acf25c2cc5d1bd22282a4e1bb53d96reed@android.com */
5644c128c4917acf25c2cc5d1bd22282a4e1bb53d96reed@android.comint SkBitmapProcState::maxCountForBufferSize(size_t bufferSize) const {
5654c128c4917acf25c2cc5d1bd22282a4e1bb53d96reed@android.com    int32_t size = static_cast<int32_t>(bufferSize);
5664c128c4917acf25c2cc5d1bd22282a4e1bb53d96reed@android.com
5674c128c4917acf25c2cc5d1bd22282a4e1bb53d96reed@android.com    size &= ~3; // only care about 4-byte aligned chunks
5684c128c4917acf25c2cc5d1bd22282a4e1bb53d96reed@android.com    if (fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) {
5694c128c4917acf25c2cc5d1bd22282a4e1bb53d96reed@android.com        size -= 4;   // the shared Y (or YY) coordinate
5704c128c4917acf25c2cc5d1bd22282a4e1bb53d96reed@android.com        if (size < 0) {
5714c128c4917acf25c2cc5d1bd22282a4e1bb53d96reed@android.com            size = 0;
5724c128c4917acf25c2cc5d1bd22282a4e1bb53d96reed@android.com        }
573258cb228c636282a3e4f4ce87b1017498e207f33reed@android.com        size >>= 1;
5744c128c4917acf25c2cc5d1bd22282a4e1bb53d96reed@android.com    } else {
575258cb228c636282a3e4f4ce87b1017498e207f33reed@android.com        size >>= 2;
5764c128c4917acf25c2cc5d1bd22282a4e1bb53d96reed@android.com    }
5774c128c4917acf25c2cc5d1bd22282a4e1bb53d96reed@android.com
578258cb228c636282a3e4f4ce87b1017498e207f33reed@android.com    if (fDoFilter) {
579258cb228c636282a3e4f4ce87b1017498e207f33reed@android.com        size >>= 1;
580258cb228c636282a3e4f4ce87b1017498e207f33reed@android.com    }
581258cb228c636282a3e4f4ce87b1017498e207f33reed@android.com
582258cb228c636282a3e4f4ce87b1017498e207f33reed@android.com    return size;
5834c128c4917acf25c2cc5d1bd22282a4e1bb53d96reed@android.com}
5844c128c4917acf25c2cc5d1bd22282a4e1bb53d96reed@android.com
585