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