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