SkBitmapProcState.cpp revision 60cc7d353b2adc8fcc1712e1f7a965e70121ebcc
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 "SkBitmapProcState.h"
10#include "SkColorPriv.h"
11#include "SkFilterProc.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
20#if !SK_ARM_NEON_IS_NONE
21// These are defined in src/opts/SkBitmapProcState_arm_neon.cpp
22extern const SkBitmapProcState::SampleProc16 gSkBitmapProcStateSample16_neon[];
23extern const SkBitmapProcState::SampleProc32 gSkBitmapProcStateSample32_neon[];
24extern void  S16_D16_filter_DX_neon(const SkBitmapProcState&, const uint32_t*, int, uint16_t*);
25extern void  Clamp_S16_D16_filter_DX_shaderproc_neon(const SkBitmapProcState&, int, int, uint16_t*, int);
26extern void  Repeat_S16_D16_filter_DX_shaderproc_neon(const SkBitmapProcState&, int, int, uint16_t*, int);
27extern void  SI8_opaque_D32_filter_DX_neon(const SkBitmapProcState&, const uint32_t*, int, SkPMColor*);
28extern void  SI8_opaque_D32_filter_DX_shaderproc_neon(const SkBitmapProcState&, int, int, uint32_t*, int);
29extern void  Clamp_SI8_opaque_D32_filter_DX_shaderproc_neon(const SkBitmapProcState&, int, int, uint32_t*, int);
30#endif
31
32#define   NAME_WRAP(x)  x
33#include "SkBitmapProcState_filter.h"
34#include "SkBitmapProcState_procs.h"
35
36///////////////////////////////////////////////////////////////////////////////
37
38// true iff the matrix contains, at most, scale and translate elements
39static bool matrix_only_scale_translate(const SkMatrix& m) {
40    return m.getType() <= (SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask);
41}
42
43/**
44 *  For the purposes of drawing bitmaps, if a matrix is "almost" translate
45 *  go ahead and treat it as if it were, so that subsequent code can go fast.
46 */
47static bool just_trans_clamp(const SkMatrix& matrix, const SkBitmap& bitmap) {
48    SkASSERT(matrix_only_scale_translate(matrix));
49
50    if (matrix.getType() & SkMatrix::kScale_Mask) {
51        SkRect src, dst;
52        bitmap.getBounds(&src);
53
54        // Can't call mapRect(), since that will fix up inverted rectangles,
55        // e.g. when scale is negative, and we don't want to return true for
56        // those.
57        matrix.mapPoints(SkTCast<SkPoint*>(&dst),
58                         SkTCast<const SkPoint*>(&src),
59                         2);
60
61        // Now round all 4 edges to device space, and then compare the device
62        // width/height to the original. Note: we must map all 4 and subtract
63        // rather than map the "width" and compare, since we care about the
64        // phase (in pixel space) that any translate in the matrix might impart.
65        SkIRect idst;
66        dst.round(&idst);
67        return idst.width() == bitmap.width() && idst.height() == bitmap.height();
68    }
69    // if we got here, we're either kTranslate_Mask or identity
70    return true;
71}
72
73static bool just_trans_general(const SkMatrix& matrix) {
74    SkASSERT(matrix_only_scale_translate(matrix));
75
76    if (matrix.getType() & SkMatrix::kScale_Mask) {
77        const SkScalar tol = SK_Scalar1 / 32768;
78
79        if (!SkScalarNearlyZero(matrix[SkMatrix::kMScaleX] - SK_Scalar1, tol)) {
80            return false;
81        }
82        if (!SkScalarNearlyZero(matrix[SkMatrix::kMScaleY] - SK_Scalar1, tol)) {
83            return false;
84        }
85    }
86    // if we got here, treat us as either kTranslate_Mask or identity
87    return true;
88}
89
90///////////////////////////////////////////////////////////////////////////////
91
92static bool valid_for_filtering(unsigned dimension) {
93    // for filtering, width and height must fit in 14bits, since we use steal
94    // 2 bits from each to store our 4bit subpixel data
95    return (dimension & ~0x3FFF) == 0;
96}
97
98static SkScalar effective_matrix_scale_sqrd(const SkMatrix& mat) {
99    SkPoint v1, v2;
100
101    v1.fX = mat.getScaleX();
102    v1.fY = mat.getSkewY();
103
104    v2.fX = mat.getSkewX();
105    v2.fY = mat.getScaleY();
106
107    return SkMaxScalar(v1.lengthSqd(), v2.lengthSqd());
108}
109
110class AutoScaledCacheUnlocker {
111public:
112    AutoScaledCacheUnlocker(SkScaledImageCache::ID* idPtr) : fIDPtr(idPtr) {}
113    ~AutoScaledCacheUnlocker() {
114        if (fIDPtr && *fIDPtr) {
115            SkScaledImageCache::Unlock(*fIDPtr);
116            *fIDPtr = NULL;
117        }
118    }
119
120    // forgets the ID, so it won't call Unlock
121    void release() {
122        fIDPtr = NULL;
123    }
124
125private:
126    SkScaledImageCache::ID* fIDPtr;
127};
128#define AutoScaledCacheUnlocker(...) SK_REQUIRE_LOCAL_VAR(AutoScaledCacheUnlocker)
129
130// Check to see that the size of the bitmap that would be produced by
131// scaling by the given inverted matrix is less than the maximum allowed.
132static inline bool cache_size_okay(const SkBitmap& bm, const SkMatrix& invMat) {
133    size_t maximumAllocation
134        = SkScaledImageCache::GetSingleAllocationByteLimit();
135    if (0 == maximumAllocation) {
136        return true;
137    }
138    // float matrixScaleFactor = 1.0 / (invMat.scaleX * invMat.scaleY);
139    // return ((origBitmapSize * matrixScaleFactor) < maximumAllocationSize);
140    // Skip the division step:
141    return bm.info().getSafeSize(bm.info().minRowBytes())
142        < (maximumAllocation * invMat.getScaleX() * invMat.getScaleY());
143}
144
145// TODO -- we may want to pass the clip into this function so we only scale
146// the portion of the image that we're going to need.  This will complicate
147// the interface to the cache, but might be well worth it.
148
149bool SkBitmapProcState::possiblyScaleImage() {
150    SkASSERT(NULL == fBitmap);
151
152    if (fFilterLevel <= SkPaint::kLow_FilterLevel) {
153        return false;
154    }
155    // Check to see if the transformation matrix is simple, and if we're
156    // doing high quality scaling.  If so, do the bitmap scale here and
157    // remove the scaling component from the matrix.
158
159    if (SkPaint::kHigh_FilterLevel == fFilterLevel &&
160        fInvMatrix.getType() <= (SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask) &&
161        kN32_SkColorType == fOrigBitmap.colorType() &&
162        cache_size_okay(fOrigBitmap, fInvMatrix)) {
163
164        SkScalar invScaleX = fInvMatrix.getScaleX();
165        SkScalar invScaleY = fInvMatrix.getScaleY();
166
167        if (SkScalarNearlyEqual(invScaleX,1.0f) &&
168            SkScalarNearlyEqual(invScaleY,1.0f)) {
169            // short-circuit identity scaling; the output is supposed to
170            // be the same as the input, so we might as well go fast.
171
172            // Note(humper): We could also probably do this if the scales
173            // are close to -1 as well, since the flip doesn't require
174            // any fancy re-sampling...
175
176            // Set our filter level to low -- the only post-filtering this
177            // image might require is some interpolation if the translation
178            // is fractional.
179            fFilterLevel = SkPaint::kLow_FilterLevel;
180            return false;
181        }
182
183        if (!SkBitmapCache::Find(fOrigBitmap, invScaleX, invScaleY, &fScaledBitmap)) {
184            float dest_width  = fOrigBitmap.width() / invScaleX;
185            float dest_height = fOrigBitmap.height() / invScaleY;
186
187            // All the criteria are met; let's make a new bitmap.
188
189            if (!SkBitmapScaler::Resize(&fScaledBitmap,
190                                        fOrigBitmap,
191                                        SkBitmapScaler::RESIZE_BEST,
192                                        dest_width,
193                                        dest_height,
194                                        SkScaledImageCache::GetAllocator())) {
195                // we failed to create fScaledBitmap, so just return and let
196                // the scanline proc handle it.
197                return false;
198
199            }
200
201            SkASSERT(NULL != fScaledBitmap.getPixels());
202            SkBitmapCache::Add(fOrigBitmap, invScaleX, invScaleY, fScaledBitmap);
203        }
204
205        SkASSERT(NULL != fScaledBitmap.getPixels());
206        fBitmap = &fScaledBitmap;
207
208        // set the inv matrix type to translate-only;
209        fInvMatrix.setTranslate(fInvMatrix.getTranslateX() / fInvMatrix.getScaleX(),
210                                fInvMatrix.getTranslateY() / fInvMatrix.getScaleY());
211
212        // Set our filter level to low -- the only post-filtering this
213        // image might require is some interpolation if the translation
214        // is fractional.
215        fFilterLevel = SkPaint::kLow_FilterLevel;
216        return true;
217    }
218
219    /*
220     *  If High, then our special-case for scale-only did not take, and so we
221     *  have to make a choice:
222     *      1. fall back on mipmaps + bilerp
223     *      2. fall back on scanline bicubic filter
224     *  For now, we compute the "scale" value from the matrix, and have a
225     *  threshold to decide when bicubic is better, and when mips are better.
226     *  No doubt a fancier decision tree could be used uere.
227     *
228     *  If Medium, then we just try to build a mipmap and select a level,
229     *  setting the filter-level to kLow to signal that we just need bilerp
230     *  to process the selected level.
231     */
232
233    SkScalar scaleSqd = effective_matrix_scale_sqrd(fInvMatrix);
234
235    if (SkPaint::kHigh_FilterLevel == fFilterLevel) {
236        // Set the limit at 0.25 for the CTM... if the CTM is scaling smaller
237        // than this, then the mipmaps quality may be greater (certainly faster)
238        // so we only keep High quality if the scale is greater than this.
239        //
240        // Since we're dealing with the inverse, we compare against its inverse.
241        const SkScalar bicubicLimit = 4.0f;
242        const SkScalar bicubicLimitSqd = bicubicLimit * bicubicLimit;
243        if (scaleSqd < bicubicLimitSqd) {  // use bicubic scanline
244            return false;
245        }
246
247        // else set the filter-level to Medium, since we're scaling down and
248        // want to reqeust mipmaps
249        fFilterLevel = SkPaint::kMedium_FilterLevel;
250    }
251
252    SkASSERT(SkPaint::kMedium_FilterLevel == fFilterLevel);
253
254    /**
255     *  Medium quality means use a mipmap for down-scaling, and just bilper
256     *  for upscaling. Since we're examining the inverse matrix, we look for
257     *  a scale > 1 to indicate down scaling by the CTM.
258     */
259    if (scaleSqd > SK_Scalar1) {
260        fCurrMip.reset(SkMipMapCache::FindAndRef(fOrigBitmap));
261        if (NULL == fCurrMip.get()) {
262            fCurrMip.reset(SkMipMap::Build(fOrigBitmap));
263            if (NULL == fCurrMip.get()) {
264                return false;
265            }
266            SkMipMapCache::Add(fOrigBitmap, fCurrMip);
267        }
268
269        SkScalar levelScale = SkScalarInvert(SkScalarSqrt(scaleSqd));
270        SkMipMap::Level level;
271        if (fCurrMip->extractLevel(levelScale, &level)) {
272            SkScalar invScaleFixup = level.fScale;
273            fInvMatrix.postScale(invScaleFixup, invScaleFixup);
274
275            SkImageInfo info = fOrigBitmap.info();
276            info.fWidth = level.fWidth;
277            info.fHeight = level.fHeight;
278            // todo: if we could wrap the fCurrMip in a pixelref, then we could just install
279            //       that here, and not need to explicitly track it ourselves.
280            fScaledBitmap.installPixels(info, level.fPixels, level.fRowBytes);
281            fBitmap = &fScaledBitmap;
282            fFilterLevel = SkPaint::kLow_FilterLevel;
283            return true;
284        }
285    }
286
287    return false;
288}
289
290static bool get_locked_pixels(const SkBitmap& src, int pow2, SkBitmap* dst) {
291    SkPixelRef* pr = src.pixelRef();
292    if (pr && pr->decodeInto(pow2, dst)) {
293        return true;
294    }
295
296    /*
297     *  If decodeInto() fails, it is possibe that we have an old subclass that
298     *  does not, or cannot, implement that. In that case we fall back to the
299     *  older protocol of having the pixelRef handle the caching for us.
300     */
301    *dst = src;
302    dst->lockPixels();
303    return SkToBool(dst->getPixels());
304}
305
306bool SkBitmapProcState::lockBaseBitmap() {
307    SkPixelRef* pr = fOrigBitmap.pixelRef();
308
309    if (pr->isLocked() || !pr->implementsDecodeInto()) {
310        // fast-case, no need to look in our cache
311        fScaledBitmap = fOrigBitmap;
312        fScaledBitmap.lockPixels();
313        if (NULL == fScaledBitmap.getPixels()) {
314            return false;
315        }
316    } else {
317        if (!SkBitmapCache::Find(fOrigBitmap, 1, 1, &fScaledBitmap)) {
318            if (!get_locked_pixels(fOrigBitmap, 0, &fScaledBitmap)) {
319                return false;
320            }
321
322            // TODO: if fScaled comes back at a different width/height than fOrig,
323            // we need to update the matrix we are using to sample from this guy.
324
325            SkBitmapCache::Add(fOrigBitmap, 1, 1, fScaledBitmap);
326        }
327    }
328    fBitmap = &fScaledBitmap;
329    return true;
330}
331
332SkBitmapProcState::~SkBitmapProcState() {
333    SkDELETE(fBitmapFilter);
334}
335
336bool SkBitmapProcState::chooseProcs(const SkMatrix& inv, const SkPaint& paint) {
337    SkASSERT(fOrigBitmap.width() && fOrigBitmap.height());
338
339    fBitmap = NULL;
340    fInvMatrix = inv;
341    fFilterLevel = paint.getFilterLevel();
342
343    // possiblyScaleImage will look to see if it can rescale the image as a
344    // preprocess; either by scaling up to the target size, or by selecting
345    // a nearby mipmap level.  If it does, it will adjust the working
346    // matrix as well as the working bitmap.  It may also adjust the filter
347    // quality to avoid re-filtering an already perfectly scaled image.
348    if (!this->possiblyScaleImage()) {
349        if (!this->lockBaseBitmap()) {
350            return false;
351        }
352    }
353    // The above logic should have always assigned fBitmap, but in case it
354    // didn't, we check for that now...
355    // TODO(dominikg): Ask humper@ if we can just use an SkASSERT(fBitmap)?
356    if (NULL == fBitmap) {
357        return false;
358    }
359
360    // If we are "still" kMedium_FilterLevel, then the request was not fulfilled by possiblyScale,
361    // so we downgrade to kLow (so the rest of the sniffing code can assume that)
362    if (SkPaint::kMedium_FilterLevel == fFilterLevel) {
363        fFilterLevel = SkPaint::kLow_FilterLevel;
364    }
365
366    bool trivialMatrix = (fInvMatrix.getType() & ~SkMatrix::kTranslate_Mask) == 0;
367    bool clampClamp = SkShader::kClamp_TileMode == fTileModeX &&
368                      SkShader::kClamp_TileMode == fTileModeY;
369
370    if (!(clampClamp || trivialMatrix)) {
371        fInvMatrix.postIDiv(fOrigBitmap.width(), fOrigBitmap.height());
372    }
373
374    // Now that all possible changes to the matrix have taken place, check
375    // to see if we're really close to a no-scale matrix.  If so, explicitly
376    // set it to be so.  Subsequent code may inspect this matrix to choose
377    // a faster path in this case.
378
379    // This code will only execute if the matrix has some scale component;
380    // if it's already pure translate then we won't do this inversion.
381
382    if (matrix_only_scale_translate(fInvMatrix)) {
383        SkMatrix forward;
384        if (fInvMatrix.invert(&forward)) {
385            if (clampClamp ? just_trans_clamp(forward, *fBitmap)
386                            : just_trans_general(forward)) {
387                SkScalar tx = -SkScalarRoundToScalar(forward.getTranslateX());
388                SkScalar ty = -SkScalarRoundToScalar(forward.getTranslateY());
389                fInvMatrix.setTranslate(tx, ty);
390            }
391        }
392    }
393
394    fInvProc        = fInvMatrix.getMapXYProc();
395    fInvType        = fInvMatrix.getType();
396    fInvSx          = SkScalarToFixed(fInvMatrix.getScaleX());
397    fInvSxFractionalInt = SkScalarToFractionalInt(fInvMatrix.getScaleX());
398    fInvKy          = SkScalarToFixed(fInvMatrix.getSkewY());
399    fInvKyFractionalInt = SkScalarToFractionalInt(fInvMatrix.getSkewY());
400
401    fAlphaScale = SkAlpha255To256(paint.getAlpha());
402
403    fShaderProc32 = NULL;
404    fShaderProc16 = NULL;
405    fSampleProc32 = NULL;
406    fSampleProc16 = NULL;
407
408    // recompute the triviality of the matrix here because we may have
409    // changed it!
410
411    trivialMatrix = (fInvMatrix.getType() & ~SkMatrix::kTranslate_Mask) == 0;
412
413    if (SkPaint::kHigh_FilterLevel == fFilterLevel) {
414        // If this is still set, that means we wanted HQ sampling
415        // but couldn't do it as a preprocess.  Let's try to install
416        // the scanline version of the HQ sampler.  If that process fails,
417        // downgrade to bilerp.
418
419        // NOTE: Might need to be careful here in the future when we want
420        // to have the platform proc have a shot at this; it's possible that
421        // the chooseBitmapFilterProc will fail to install a shader but a
422        // platform-specific one might succeed, so it might be premature here
423        // to fall back to bilerp.  This needs thought.
424
425        if (!this->setBitmapFilterProcs()) {
426            fFilterLevel = SkPaint::kLow_FilterLevel;
427        }
428    }
429
430    if (SkPaint::kLow_FilterLevel == fFilterLevel) {
431        // Only try bilerp if the matrix is "interesting" and
432        // the image has a suitable size.
433
434        if (fInvType <= SkMatrix::kTranslate_Mask ||
435                !valid_for_filtering(fBitmap->width() | fBitmap->height())) {
436            fFilterLevel = SkPaint::kNone_FilterLevel;
437        }
438    }
439
440    // At this point, we know exactly what kind of sampling the per-scanline
441    // shader will perform.
442
443    fMatrixProc = this->chooseMatrixProc(trivialMatrix);
444    // TODO(dominikg): SkASSERT(fMatrixProc) instead? chooseMatrixProc never returns NULL.
445    if (NULL == fMatrixProc) {
446        return false;
447    }
448
449    ///////////////////////////////////////////////////////////////////////
450
451    const SkAlphaType at = fBitmap->alphaType();
452
453    // No need to do this if we're doing HQ sampling; if filter quality is
454    // still set to HQ by the time we get here, then we must have installed
455    // the shader procs above and can skip all this.
456
457    if (fFilterLevel < SkPaint::kHigh_FilterLevel) {
458
459        int index = 0;
460        if (fAlphaScale < 256) {  // note: this distinction is not used for D16
461            index |= 1;
462        }
463        if (fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) {
464            index |= 2;
465        }
466        if (fFilterLevel > SkPaint::kNone_FilterLevel) {
467            index |= 4;
468        }
469        // bits 3,4,5 encoding the source bitmap format
470        switch (fBitmap->colorType()) {
471            case kN32_SkColorType:
472                if (kPremul_SkAlphaType != at && kOpaque_SkAlphaType != at) {
473                    return false;
474                }
475                index |= 0;
476                break;
477            case kRGB_565_SkColorType:
478                index |= 8;
479                break;
480            case kIndex_8_SkColorType:
481                if (kPremul_SkAlphaType != at && kOpaque_SkAlphaType != at) {
482                    return false;
483                }
484                index |= 16;
485                break;
486            case kARGB_4444_SkColorType:
487                if (kPremul_SkAlphaType != at && kOpaque_SkAlphaType != at) {
488                    return false;
489                }
490                index |= 24;
491                break;
492            case kAlpha_8_SkColorType:
493                index |= 32;
494                fPaintPMColor = SkPreMultiplyColor(paint.getColor());
495                break;
496            default:
497                // TODO(dominikg): Should we ever get here? SkASSERT(false) instead?
498                return false;
499        }
500
501    #if !SK_ARM_NEON_IS_ALWAYS
502        static const SampleProc32 gSkBitmapProcStateSample32[] = {
503            S32_opaque_D32_nofilter_DXDY,
504            S32_alpha_D32_nofilter_DXDY,
505            S32_opaque_D32_nofilter_DX,
506            S32_alpha_D32_nofilter_DX,
507            S32_opaque_D32_filter_DXDY,
508            S32_alpha_D32_filter_DXDY,
509            S32_opaque_D32_filter_DX,
510            S32_alpha_D32_filter_DX,
511
512            S16_opaque_D32_nofilter_DXDY,
513            S16_alpha_D32_nofilter_DXDY,
514            S16_opaque_D32_nofilter_DX,
515            S16_alpha_D32_nofilter_DX,
516            S16_opaque_D32_filter_DXDY,
517            S16_alpha_D32_filter_DXDY,
518            S16_opaque_D32_filter_DX,
519            S16_alpha_D32_filter_DX,
520
521            SI8_opaque_D32_nofilter_DXDY,
522            SI8_alpha_D32_nofilter_DXDY,
523            SI8_opaque_D32_nofilter_DX,
524            SI8_alpha_D32_nofilter_DX,
525            SI8_opaque_D32_filter_DXDY,
526            SI8_alpha_D32_filter_DXDY,
527            SI8_opaque_D32_filter_DX,
528            SI8_alpha_D32_filter_DX,
529
530            S4444_opaque_D32_nofilter_DXDY,
531            S4444_alpha_D32_nofilter_DXDY,
532            S4444_opaque_D32_nofilter_DX,
533            S4444_alpha_D32_nofilter_DX,
534            S4444_opaque_D32_filter_DXDY,
535            S4444_alpha_D32_filter_DXDY,
536            S4444_opaque_D32_filter_DX,
537            S4444_alpha_D32_filter_DX,
538
539            // A8 treats alpha/opaque the same (equally efficient)
540            SA8_alpha_D32_nofilter_DXDY,
541            SA8_alpha_D32_nofilter_DXDY,
542            SA8_alpha_D32_nofilter_DX,
543            SA8_alpha_D32_nofilter_DX,
544            SA8_alpha_D32_filter_DXDY,
545            SA8_alpha_D32_filter_DXDY,
546            SA8_alpha_D32_filter_DX,
547            SA8_alpha_D32_filter_DX
548        };
549
550        static const SampleProc16 gSkBitmapProcStateSample16[] = {
551            S32_D16_nofilter_DXDY,
552            S32_D16_nofilter_DX,
553            S32_D16_filter_DXDY,
554            S32_D16_filter_DX,
555
556            S16_D16_nofilter_DXDY,
557            S16_D16_nofilter_DX,
558            S16_D16_filter_DXDY,
559            S16_D16_filter_DX,
560
561            SI8_D16_nofilter_DXDY,
562            SI8_D16_nofilter_DX,
563            SI8_D16_filter_DXDY,
564            SI8_D16_filter_DX,
565
566            // Don't support 4444 -> 565
567            NULL, NULL, NULL, NULL,
568            // Don't support A8 -> 565
569            NULL, NULL, NULL, NULL
570        };
571    #endif
572
573        fSampleProc32 = SK_ARM_NEON_WRAP(gSkBitmapProcStateSample32)[index];
574        index >>= 1;    // shift away any opaque/alpha distinction
575        fSampleProc16 = SK_ARM_NEON_WRAP(gSkBitmapProcStateSample16)[index];
576
577        // our special-case shaderprocs
578        if (SK_ARM_NEON_WRAP(S16_D16_filter_DX) == fSampleProc16) {
579            if (clampClamp) {
580                fShaderProc16 = SK_ARM_NEON_WRAP(Clamp_S16_D16_filter_DX_shaderproc);
581            } else if (SkShader::kRepeat_TileMode == fTileModeX &&
582                       SkShader::kRepeat_TileMode == fTileModeY) {
583                fShaderProc16 = SK_ARM_NEON_WRAP(Repeat_S16_D16_filter_DX_shaderproc);
584            }
585        } else if (SK_ARM_NEON_WRAP(SI8_opaque_D32_filter_DX) == fSampleProc32 && clampClamp) {
586            fShaderProc32 = SK_ARM_NEON_WRAP(Clamp_SI8_opaque_D32_filter_DX_shaderproc);
587        }
588
589        if (NULL == fShaderProc32) {
590            fShaderProc32 = this->chooseShaderProc32();
591        }
592    }
593
594    // see if our platform has any accelerated overrides
595    this->platformProcs();
596
597    return true;
598}
599
600static void Clamp_S32_D32_nofilter_trans_shaderproc(const SkBitmapProcState& s,
601                                                    int x, int y,
602                                                    SkPMColor* SK_RESTRICT colors,
603                                                    int count) {
604    SkASSERT(((s.fInvType & ~SkMatrix::kTranslate_Mask)) == 0);
605    SkASSERT(s.fInvKy == 0);
606    SkASSERT(count > 0 && colors != NULL);
607    SkASSERT(SkPaint::kNone_FilterLevel == s.fFilterLevel);
608
609    const int maxX = s.fBitmap->width() - 1;
610    const int maxY = s.fBitmap->height() - 1;
611    int ix = s.fFilterOneX + x;
612    int iy = SkClampMax(s.fFilterOneY + y, maxY);
613#ifdef SK_DEBUG
614    {
615        SkPoint pt;
616        s.fInvProc(s.fInvMatrix, SkIntToScalar(x) + SK_ScalarHalf,
617                   SkIntToScalar(y) + SK_ScalarHalf, &pt);
618        int iy2 = SkClampMax(SkScalarFloorToInt(pt.fY), maxY);
619        int ix2 = SkScalarFloorToInt(pt.fX);
620
621        SkASSERT(iy == iy2);
622        SkASSERT(ix == ix2);
623    }
624#endif
625    const SkPMColor* row = s.fBitmap->getAddr32(0, iy);
626
627    // clamp to the left
628    if (ix < 0) {
629        int n = SkMin32(-ix, count);
630        sk_memset32(colors, row[0], n);
631        count -= n;
632        if (0 == count) {
633            return;
634        }
635        colors += n;
636        SkASSERT(-ix == n);
637        ix = 0;
638    }
639    // copy the middle
640    if (ix <= maxX) {
641        int n = SkMin32(maxX - ix + 1, count);
642        memcpy(colors, row + ix, n * sizeof(SkPMColor));
643        count -= n;
644        if (0 == count) {
645            return;
646        }
647        colors += n;
648    }
649    SkASSERT(count > 0);
650    // clamp to the right
651    sk_memset32(colors, row[maxX], count);
652}
653
654static inline int sk_int_mod(int x, int n) {
655    SkASSERT(n > 0);
656    if ((unsigned)x >= (unsigned)n) {
657        if (x < 0) {
658            x = n + ~(~x % n);
659        } else {
660            x = x % n;
661        }
662    }
663    return x;
664}
665
666static inline int sk_int_mirror(int x, int n) {
667    x = sk_int_mod(x, 2 * n);
668    if (x >= n) {
669        x = n + ~(x - n);
670    }
671    return x;
672}
673
674static void Repeat_S32_D32_nofilter_trans_shaderproc(const SkBitmapProcState& s,
675                                                     int x, int y,
676                                                     SkPMColor* SK_RESTRICT colors,
677                                                     int count) {
678    SkASSERT(((s.fInvType & ~SkMatrix::kTranslate_Mask)) == 0);
679    SkASSERT(s.fInvKy == 0);
680    SkASSERT(count > 0 && colors != NULL);
681    SkASSERT(SkPaint::kNone_FilterLevel == s.fFilterLevel);
682
683    const int stopX = s.fBitmap->width();
684    const int stopY = s.fBitmap->height();
685    int ix = s.fFilterOneX + x;
686    int iy = sk_int_mod(s.fFilterOneY + y, stopY);
687#ifdef SK_DEBUG
688    {
689        SkPoint pt;
690        s.fInvProc(s.fInvMatrix, SkIntToScalar(x) + SK_ScalarHalf,
691                   SkIntToScalar(y) + SK_ScalarHalf, &pt);
692        int iy2 = sk_int_mod(SkScalarFloorToInt(pt.fY), stopY);
693        int ix2 = SkScalarFloorToInt(pt.fX);
694
695        SkASSERT(iy == iy2);
696        SkASSERT(ix == ix2);
697    }
698#endif
699    const SkPMColor* row = s.fBitmap->getAddr32(0, iy);
700
701    ix = sk_int_mod(ix, stopX);
702    for (;;) {
703        int n = SkMin32(stopX - ix, count);
704        memcpy(colors, row + ix, n * sizeof(SkPMColor));
705        count -= n;
706        if (0 == count) {
707            return;
708        }
709        colors += n;
710        ix = 0;
711    }
712}
713
714static void S32_D32_constX_shaderproc(const SkBitmapProcState& s,
715                                      int x, int y,
716                                      SkPMColor* SK_RESTRICT colors,
717                                      int count) {
718    SkASSERT((s.fInvType & ~(SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) == 0);
719    SkASSERT(s.fInvKy == 0);
720    SkASSERT(count > 0 && colors != NULL);
721    SkASSERT(1 == s.fBitmap->width());
722
723    int iY0;
724    int iY1   SK_INIT_TO_AVOID_WARNING;
725    int iSubY SK_INIT_TO_AVOID_WARNING;
726
727    if (SkPaint::kNone_FilterLevel != s.fFilterLevel) {
728        SkBitmapProcState::MatrixProc mproc = s.getMatrixProc();
729        uint32_t xy[2];
730
731        mproc(s, xy, 1, x, y);
732
733        iY0 = xy[0] >> 18;
734        iY1 = xy[0] & 0x3FFF;
735        iSubY = (xy[0] >> 14) & 0xF;
736    } else {
737        int yTemp;
738
739        if (s.fInvType > SkMatrix::kTranslate_Mask) {
740            SkPoint pt;
741            s.fInvProc(s.fInvMatrix,
742                       SkIntToScalar(x) + SK_ScalarHalf,
743                       SkIntToScalar(y) + SK_ScalarHalf,
744                       &pt);
745            // When the matrix has a scale component the setup code in
746            // chooseProcs multiples the inverse matrix by the inverse of the
747            // bitmap's width and height. Since this method is going to do
748            // its own tiling and sampling we need to undo that here.
749            if (SkShader::kClamp_TileMode != s.fTileModeX ||
750                SkShader::kClamp_TileMode != s.fTileModeY) {
751                yTemp = SkScalarFloorToInt(pt.fY * s.fBitmap->height());
752            } else {
753                yTemp = SkScalarFloorToInt(pt.fY);
754            }
755        } else {
756            yTemp = s.fFilterOneY + y;
757        }
758
759        const int stopY = s.fBitmap->height();
760        switch (s.fTileModeY) {
761            case SkShader::kClamp_TileMode:
762                iY0 = SkClampMax(yTemp, stopY-1);
763                break;
764            case SkShader::kRepeat_TileMode:
765                iY0 = sk_int_mod(yTemp, stopY);
766                break;
767            case SkShader::kMirror_TileMode:
768            default:
769                iY0 = sk_int_mirror(yTemp, stopY);
770                break;
771        }
772
773#ifdef SK_DEBUG
774        {
775            SkPoint pt;
776            s.fInvProc(s.fInvMatrix,
777                       SkIntToScalar(x) + SK_ScalarHalf,
778                       SkIntToScalar(y) + SK_ScalarHalf,
779                       &pt);
780            if (s.fInvType > SkMatrix::kTranslate_Mask &&
781                (SkShader::kClamp_TileMode != s.fTileModeX ||
782                 SkShader::kClamp_TileMode != s.fTileModeY)) {
783                pt.fY *= s.fBitmap->height();
784            }
785            int iY2;
786
787            switch (s.fTileModeY) {
788            case SkShader::kClamp_TileMode:
789                iY2 = SkClampMax(SkScalarFloorToInt(pt.fY), stopY-1);
790                break;
791            case SkShader::kRepeat_TileMode:
792                iY2 = sk_int_mod(SkScalarFloorToInt(pt.fY), stopY);
793                break;
794            case SkShader::kMirror_TileMode:
795            default:
796                iY2 = sk_int_mirror(SkScalarFloorToInt(pt.fY), stopY);
797                break;
798            }
799
800            SkASSERT(iY0 == iY2);
801        }
802#endif
803    }
804
805    const SkPMColor* row0 = s.fBitmap->getAddr32(0, iY0);
806    SkPMColor color;
807
808    if (SkPaint::kNone_FilterLevel != s.fFilterLevel) {
809        const SkPMColor* row1 = s.fBitmap->getAddr32(0, iY1);
810
811        if (s.fAlphaScale < 256) {
812            Filter_32_alpha(iSubY, *row0, *row1, &color, s.fAlphaScale);
813        } else {
814            Filter_32_opaque(iSubY, *row0, *row1, &color);
815        }
816    } else {
817        if (s.fAlphaScale < 256) {
818            color = SkAlphaMulQ(*row0, s.fAlphaScale);
819        } else {
820            color = *row0;
821        }
822    }
823
824    sk_memset32(colors, color, count);
825}
826
827static void DoNothing_shaderproc(const SkBitmapProcState&, int x, int y,
828                                 SkPMColor* SK_RESTRICT colors, int count) {
829    // if we get called, the matrix is too tricky, so we just draw nothing
830    sk_memset32(colors, 0, count);
831}
832
833bool SkBitmapProcState::setupForTranslate() {
834    SkPoint pt;
835    fInvProc(fInvMatrix, SK_ScalarHalf, SK_ScalarHalf, &pt);
836
837    /*
838     *  if the translate is larger than our ints, we can get random results, or
839     *  worse, we might get 0x80000000, which wreaks havoc on us, since we can't
840     *  negate it.
841     */
842    const SkScalar too_big = SkIntToScalar(1 << 30);
843    if (SkScalarAbs(pt.fX) > too_big || SkScalarAbs(pt.fY) > too_big) {
844        return false;
845    }
846
847    // Since we know we're not filtered, we re-purpose these fields allow
848    // us to go from device -> src coordinates w/ just an integer add,
849    // rather than running through the inverse-matrix
850    fFilterOneX = SkScalarFloorToInt(pt.fX);
851    fFilterOneY = SkScalarFloorToInt(pt.fY);
852    return true;
853}
854
855SkBitmapProcState::ShaderProc32 SkBitmapProcState::chooseShaderProc32() {
856
857    if (kN32_SkColorType != fBitmap->colorType()) {
858        return NULL;
859    }
860
861    static const unsigned kMask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask;
862
863    if (1 == fBitmap->width() && 0 == (fInvType & ~kMask)) {
864        if (SkPaint::kNone_FilterLevel == fFilterLevel &&
865            fInvType <= SkMatrix::kTranslate_Mask &&
866            !this->setupForTranslate()) {
867            return DoNothing_shaderproc;
868        }
869        return S32_D32_constX_shaderproc;
870    }
871
872    if (fAlphaScale < 256) {
873        return NULL;
874    }
875    if (fInvType > SkMatrix::kTranslate_Mask) {
876        return NULL;
877    }
878    if (SkPaint::kNone_FilterLevel != fFilterLevel) {
879        return NULL;
880    }
881
882    SkShader::TileMode tx = (SkShader::TileMode)fTileModeX;
883    SkShader::TileMode ty = (SkShader::TileMode)fTileModeY;
884
885    if (SkShader::kClamp_TileMode == tx && SkShader::kClamp_TileMode == ty) {
886        if (this->setupForTranslate()) {
887            return Clamp_S32_D32_nofilter_trans_shaderproc;
888        }
889        return DoNothing_shaderproc;
890    }
891    if (SkShader::kRepeat_TileMode == tx && SkShader::kRepeat_TileMode == ty) {
892        if (this->setupForTranslate()) {
893            return Repeat_S32_D32_nofilter_trans_shaderproc;
894        }
895        return DoNothing_shaderproc;
896    }
897    return NULL;
898}
899
900///////////////////////////////////////////////////////////////////////////////
901
902#ifdef SK_DEBUG
903
904static void check_scale_nofilter(uint32_t bitmapXY[], int count,
905                                 unsigned mx, unsigned my) {
906    unsigned y = *bitmapXY++;
907    SkASSERT(y < my);
908
909    const uint16_t* xptr = reinterpret_cast<const uint16_t*>(bitmapXY);
910    for (int i = 0; i < count; ++i) {
911        SkASSERT(xptr[i] < mx);
912    }
913}
914
915static void check_scale_filter(uint32_t bitmapXY[], int count,
916                                 unsigned mx, unsigned my) {
917    uint32_t YY = *bitmapXY++;
918    unsigned y0 = YY >> 18;
919    unsigned y1 = YY & 0x3FFF;
920    SkASSERT(y0 < my);
921    SkASSERT(y1 < my);
922
923    for (int i = 0; i < count; ++i) {
924        uint32_t XX = bitmapXY[i];
925        unsigned x0 = XX >> 18;
926        unsigned x1 = XX & 0x3FFF;
927        SkASSERT(x0 < mx);
928        SkASSERT(x1 < mx);
929    }
930}
931
932static void check_affine_nofilter(uint32_t bitmapXY[], int count,
933                                 unsigned mx, unsigned my) {
934    for (int i = 0; i < count; ++i) {
935        uint32_t XY = bitmapXY[i];
936        unsigned x = XY & 0xFFFF;
937        unsigned y = XY >> 16;
938        SkASSERT(x < mx);
939        SkASSERT(y < my);
940    }
941}
942
943static void check_affine_filter(uint32_t bitmapXY[], int count,
944                                 unsigned mx, unsigned my) {
945    for (int i = 0; i < count; ++i) {
946        uint32_t YY = *bitmapXY++;
947        unsigned y0 = YY >> 18;
948        unsigned y1 = YY & 0x3FFF;
949        SkASSERT(y0 < my);
950        SkASSERT(y1 < my);
951
952        uint32_t XX = *bitmapXY++;
953        unsigned x0 = XX >> 18;
954        unsigned x1 = XX & 0x3FFF;
955        SkASSERT(x0 < mx);
956        SkASSERT(x1 < mx);
957    }
958}
959
960void SkBitmapProcState::DebugMatrixProc(const SkBitmapProcState& state,
961                                        uint32_t bitmapXY[], int count,
962                                        int x, int y) {
963    SkASSERT(bitmapXY);
964    SkASSERT(count > 0);
965
966    state.fMatrixProc(state, bitmapXY, count, x, y);
967
968    void (*proc)(uint32_t bitmapXY[], int count, unsigned mx, unsigned my);
969
970    // There are four formats possible:
971    //  scale -vs- affine
972    //  filter -vs- nofilter
973    if (state.fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) {
974        proc = state.fFilterLevel != SkPaint::kNone_FilterLevel ? check_scale_filter : check_scale_nofilter;
975    } else {
976        proc = state.fFilterLevel != SkPaint::kNone_FilterLevel ? check_affine_filter : check_affine_nofilter;
977    }
978    proc(bitmapXY, count, state.fBitmap->width(), state.fBitmap->height());
979}
980
981SkBitmapProcState::MatrixProc SkBitmapProcState::getMatrixProc() const {
982    return DebugMatrixProc;
983}
984
985#endif
986
987///////////////////////////////////////////////////////////////////////////////
988/*
989    The storage requirements for the different matrix procs are as follows,
990    where each X or Y is 2 bytes, and N is the number of pixels/elements:
991
992    scale/translate     nofilter      Y(4bytes) + N * X
993    affine/perspective  nofilter      N * (X Y)
994    scale/translate     filter        Y Y + N * (X X)
995    affine/perspective  filter        N * (Y Y X X)
996 */
997int SkBitmapProcState::maxCountForBufferSize(size_t bufferSize) const {
998    int32_t size = static_cast<int32_t>(bufferSize);
999
1000    size &= ~3; // only care about 4-byte aligned chunks
1001    if (fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) {
1002        size -= 4;   // the shared Y (or YY) coordinate
1003        if (size < 0) {
1004            size = 0;
1005        }
1006        size >>= 1;
1007    } else {
1008        size >>= 2;
1009    }
1010
1011    if (fFilterLevel != SkPaint::kNone_FilterLevel) {
1012        size >>= 1;
1013    }
1014
1015    return size;
1016}
1017