SkBitmapProcState.cpp revision b088947f27496a9b9dc48a7cfb170f9d59589825
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
15#if !SK_ARM_NEON_IS_NONE
16// These are defined in src/opts/SkBitmapProcState_arm_neon.cpp
17extern const SkBitmapProcState::SampleProc16 gSkBitmapProcStateSample16_neon[];
18extern const SkBitmapProcState::SampleProc32 gSkBitmapProcStateSample32_neon[];
19extern void  S16_D16_filter_DX_neon(const SkBitmapProcState&, const uint32_t*, int, uint16_t*);
20extern void  Clamp_S16_D16_filter_DX_shaderproc_neon(const SkBitmapProcState&, int, int, uint16_t*, int);
21extern void  Repeat_S16_D16_filter_DX_shaderproc_neon(const SkBitmapProcState&, int, int, uint16_t*, int);
22extern void  SI8_opaque_D32_filter_DX_neon(const SkBitmapProcState&, const uint32_t*, int, SkPMColor*);
23extern void  SI8_opaque_D32_filter_DX_shaderproc_neon(const SkBitmapProcState&, int, int, uint32_t*, int);
24extern void  Clamp_SI8_opaque_D32_filter_DX_shaderproc_neon(const SkBitmapProcState&, int, int, uint32_t*, int);
25#endif
26
27#define   NAME_WRAP(x)  x
28#include "SkBitmapProcState_filter.h"
29#include "SkBitmapProcState_procs.h"
30
31///////////////////////////////////////////////////////////////////////////////
32
33// true iff the matrix contains, at most, scale and translate elements
34static bool matrix_only_scale_translate(const SkMatrix& m) {
35    return m.getType() <= (SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask);
36}
37
38/**
39 *  For the purposes of drawing bitmaps, if a matrix is "almost" translate
40 *  go ahead and treat it as if it were, so that subsequent code can go fast.
41 */
42static bool just_trans_clamp(const SkMatrix& matrix, const SkBitmap& bitmap) {
43    SkASSERT(matrix_only_scale_translate(matrix));
44
45    if (matrix.getType() & SkMatrix::kScale_Mask) {
46        SkRect src, dst;
47        bitmap.getBounds(&src);
48
49        // Can't call mapRect(), since that will fix up inverted rectangles,
50        // e.g. when scale is negative, and we don't want to return true for
51        // those.
52        matrix.mapPoints(SkTCast<SkPoint*>(&dst),
53                         SkTCast<const SkPoint*>(&src),
54                         2);
55
56        // Now round all 4 edges to device space, and then compare the device
57        // width/height to the original. Note: we must map all 4 and subtract
58        // rather than map the "width" and compare, since we care about the
59        // phase (in pixel space) that any translate in the matrix might impart.
60        SkIRect idst;
61        dst.round(&idst);
62        return idst.width() == bitmap.width() && idst.height() == bitmap.height();
63    }
64    // if we got here, we're either kTranslate_Mask or identity
65    return true;
66}
67
68static bool just_trans_general(const SkMatrix& matrix) {
69    SkASSERT(matrix_only_scale_translate(matrix));
70
71    if (matrix.getType() & SkMatrix::kScale_Mask) {
72        const SkScalar tol = SK_Scalar1 / 32768;
73
74        if (!SkScalarNearlyZero(matrix[SkMatrix::kMScaleX] - SK_Scalar1, tol)) {
75            return false;
76        }
77        if (!SkScalarNearlyZero(matrix[SkMatrix::kMScaleY] - SK_Scalar1, tol)) {
78            return false;
79        }
80    }
81    // if we got here, treat us as either kTranslate_Mask or identity
82    return true;
83}
84
85///////////////////////////////////////////////////////////////////////////////
86
87static bool valid_for_filtering(unsigned dimension) {
88    // for filtering, width and height must fit in 14bits, since we use steal
89    // 2 bits from each to store our 4bit subpixel data
90    return (dimension & ~0x3FFF) == 0;
91}
92
93bool SkBitmapProcState::chooseProcs(const SkMatrix& inv, const SkPaint& paint) {
94    if (fOrigBitmap.width() == 0 || fOrigBitmap.height() == 0) {
95        return false;
96    }
97
98    const SkMatrix* m;
99    bool trivial_matrix = (inv.getType() & ~SkMatrix::kTranslate_Mask) == 0;
100    bool clamp_clamp = SkShader::kClamp_TileMode == fTileModeX &&
101                       SkShader::kClamp_TileMode == fTileModeY;
102
103    if (clamp_clamp || trivial_matrix) {
104        m = &inv;
105    } else {
106        fUnitInvMatrix = inv;
107        fUnitInvMatrix.postIDiv(fOrigBitmap.width(), fOrigBitmap.height());
108        m = &fUnitInvMatrix;
109    }
110
111    fBitmap = &fOrigBitmap;
112    if (fOrigBitmap.hasMipMap()) {
113        int shift = fOrigBitmap.extractMipLevel(&fMipBitmap,
114                                                SkScalarToFixed(m->getScaleX()),
115                                                SkScalarToFixed(m->getSkewY()));
116
117        if (shift > 0) {
118            if (m != &fUnitInvMatrix) {
119                fUnitInvMatrix = *m;
120                m = &fUnitInvMatrix;
121            }
122
123            SkScalar scale = SkFixedToScalar(SK_Fixed1 >> shift);
124            fUnitInvMatrix.postScale(scale, scale);
125
126            // now point here instead of fOrigBitmap
127            fBitmap = &fMipBitmap;
128        }
129    }
130
131    // wack our matrix to exactly no-scale, if we're really close to begin with
132    if (matrix_only_scale_translate(*m)) {
133        SkMatrix forward;
134        if (m->invert(&forward)) {
135            if (clamp_clamp ? just_trans_clamp(forward, *fBitmap)
136                            : just_trans_general(forward)) {
137                SkScalar tx = -SkScalarRoundToScalar(forward.getTranslateX());
138                SkScalar ty = -SkScalarRoundToScalar(forward.getTranslateY());
139                fUnitInvMatrix.setTranslate(tx, ty);
140                m = &fUnitInvMatrix;
141                // now the following code will sniff m, and decide to take the
142                // fast case (since m is purely translate).
143            }
144        }
145    }
146
147    // Below this point, we should never refer to the inv parameter, since we
148    // may be using a munged version for "our" inverse.
149
150    fInvMatrix      = m;
151    fInvProc        = m->getMapXYProc();
152    fInvType        = m->getType();
153    fInvSx          = SkScalarToFixed(m->getScaleX());
154    fInvSxFractionalInt = SkScalarToFractionalInt(m->getScaleX());
155    fInvKy          = SkScalarToFixed(m->getSkewY());
156    fInvKyFractionalInt = SkScalarToFractionalInt(m->getSkewY());
157
158    fAlphaScale = SkAlpha255To256(paint.getAlpha());
159
160    // pick-up filtering from the paint, but only if the matrix is
161    // more complex than identity/translate (i.e. no need to pay the cost
162    // of filtering if we're not scaled etc.).
163    // note: we explicitly check inv, since m might be scaled due to unitinv
164    //       trickery, but we don't want to see that for this test
165    fDoFilter = paint.isFilterBitmap() &&
166                (fInvType > SkMatrix::kTranslate_Mask &&
167                 valid_for_filtering(fBitmap->width() | fBitmap->height()));
168
169    fShaderProc32 = NULL;
170    fShaderProc16 = NULL;
171    fSampleProc32 = NULL;
172    fSampleProc16 = NULL;
173
174    fMatrixProc = this->chooseMatrixProc(trivial_matrix);
175    if (NULL == fMatrixProc) {
176        return false;
177    }
178
179    ///////////////////////////////////////////////////////////////////////
180
181    int index = 0;
182    if (fAlphaScale < 256) {  // note: this distinction is not used for D16
183        index |= 1;
184    }
185    if (fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) {
186        index |= 2;
187    }
188    if (fDoFilter) {
189        index |= 4;
190    }
191    // bits 3,4,5 encoding the source bitmap format
192    switch (fBitmap->config()) {
193        case SkBitmap::kARGB_8888_Config:
194            index |= 0;
195            break;
196        case SkBitmap::kRGB_565_Config:
197            index |= 8;
198            break;
199        case SkBitmap::kIndex8_Config:
200            index |= 16;
201            break;
202        case SkBitmap::kARGB_4444_Config:
203            index |= 24;
204            break;
205        case SkBitmap::kA8_Config:
206            index |= 32;
207            fPaintPMColor = SkPreMultiplyColor(paint.getColor());
208            break;
209        default:
210            return false;
211    }
212
213#if !SK_ARM_NEON_IS_ALWAYS
214    static const SampleProc32 gSkBitmapProcStateSample32[] = {
215        S32_opaque_D32_nofilter_DXDY,
216        S32_alpha_D32_nofilter_DXDY,
217        S32_opaque_D32_nofilter_DX,
218        S32_alpha_D32_nofilter_DX,
219        S32_opaque_D32_filter_DXDY,
220        S32_alpha_D32_filter_DXDY,
221        S32_opaque_D32_filter_DX,
222        S32_alpha_D32_filter_DX,
223
224        S16_opaque_D32_nofilter_DXDY,
225        S16_alpha_D32_nofilter_DXDY,
226        S16_opaque_D32_nofilter_DX,
227        S16_alpha_D32_nofilter_DX,
228        S16_opaque_D32_filter_DXDY,
229        S16_alpha_D32_filter_DXDY,
230        S16_opaque_D32_filter_DX,
231        S16_alpha_D32_filter_DX,
232
233        SI8_opaque_D32_nofilter_DXDY,
234        SI8_alpha_D32_nofilter_DXDY,
235        SI8_opaque_D32_nofilter_DX,
236        SI8_alpha_D32_nofilter_DX,
237        SI8_opaque_D32_filter_DXDY,
238        SI8_alpha_D32_filter_DXDY,
239        SI8_opaque_D32_filter_DX,
240        SI8_alpha_D32_filter_DX,
241
242        S4444_opaque_D32_nofilter_DXDY,
243        S4444_alpha_D32_nofilter_DXDY,
244        S4444_opaque_D32_nofilter_DX,
245        S4444_alpha_D32_nofilter_DX,
246        S4444_opaque_D32_filter_DXDY,
247        S4444_alpha_D32_filter_DXDY,
248        S4444_opaque_D32_filter_DX,
249        S4444_alpha_D32_filter_DX,
250
251        // A8 treats alpha/opaque the same (equally efficient)
252        SA8_alpha_D32_nofilter_DXDY,
253        SA8_alpha_D32_nofilter_DXDY,
254        SA8_alpha_D32_nofilter_DX,
255        SA8_alpha_D32_nofilter_DX,
256        SA8_alpha_D32_filter_DXDY,
257        SA8_alpha_D32_filter_DXDY,
258        SA8_alpha_D32_filter_DX,
259        SA8_alpha_D32_filter_DX
260    };
261
262    static const SampleProc16 gSkBitmapProcStateSample16[] = {
263        S32_D16_nofilter_DXDY,
264        S32_D16_nofilter_DX,
265        S32_D16_filter_DXDY,
266        S32_D16_filter_DX,
267
268        S16_D16_nofilter_DXDY,
269        S16_D16_nofilter_DX,
270        S16_D16_filter_DXDY,
271        S16_D16_filter_DX,
272
273        SI8_D16_nofilter_DXDY,
274        SI8_D16_nofilter_DX,
275        SI8_D16_filter_DXDY,
276        SI8_D16_filter_DX,
277
278        // Don't support 4444 -> 565
279        NULL, NULL, NULL, NULL,
280        // Don't support A8 -> 565
281        NULL, NULL, NULL, NULL
282    };
283#endif
284
285    fSampleProc32 = SK_ARM_NEON_WRAP(gSkBitmapProcStateSample32)[index];
286    index >>= 1;    // shift away any opaque/alpha distinction
287    fSampleProc16 = SK_ARM_NEON_WRAP(gSkBitmapProcStateSample16)[index];
288
289    // our special-case shaderprocs
290    if (SK_ARM_NEON_WRAP(S16_D16_filter_DX) == fSampleProc16) {
291        if (clamp_clamp) {
292            fShaderProc16 = SK_ARM_NEON_WRAP(Clamp_S16_D16_filter_DX_shaderproc);
293        } else if (SkShader::kRepeat_TileMode == fTileModeX &&
294                   SkShader::kRepeat_TileMode == fTileModeY) {
295            fShaderProc16 = SK_ARM_NEON_WRAP(Repeat_S16_D16_filter_DX_shaderproc);
296        }
297    } else if (SK_ARM_NEON_WRAP(SI8_opaque_D32_filter_DX) == fSampleProc32 && clamp_clamp) {
298        fShaderProc32 = SK_ARM_NEON_WRAP(Clamp_SI8_opaque_D32_filter_DX_shaderproc);
299    }
300
301    if (NULL == fShaderProc32) {
302        fShaderProc32 = this->chooseShaderProc32();
303    }
304
305    if (NULL == fShaderProc32) {
306        fShaderProc32 = this->chooseBitmapFilterProc(paint);
307    }
308
309    // see if our platform has any accelerated overrides
310    this->platformProcs();
311
312    return true;
313}
314
315static void Clamp_S32_D32_nofilter_trans_shaderproc(const SkBitmapProcState& s,
316                                                    int x, int y,
317                                                    SkPMColor* SK_RESTRICT colors,
318                                                    int count) {
319    SkASSERT(((s.fInvType & ~SkMatrix::kTranslate_Mask)) == 0);
320    SkASSERT(s.fInvKy == 0);
321    SkASSERT(count > 0 && colors != NULL);
322    SkASSERT(!s.fDoFilter);
323
324    const int maxX = s.fBitmap->width() - 1;
325    const int maxY = s.fBitmap->height() - 1;
326    int ix = s.fFilterOneX + x;
327    int iy = SkClampMax(s.fFilterOneY + y, maxY);
328#ifdef SK_DEBUG
329    {
330        SkPoint pt;
331        s.fInvProc(*s.fInvMatrix, SkIntToScalar(x) + SK_ScalarHalf,
332                   SkIntToScalar(y) + SK_ScalarHalf, &pt);
333        int iy2 = SkClampMax(SkScalarFloorToInt(pt.fY), maxY);
334        int ix2 = SkScalarFloorToInt(pt.fX);
335
336        SkASSERT(iy == iy2);
337        SkASSERT(ix == ix2);
338    }
339#endif
340    const SkPMColor* row = s.fBitmap->getAddr32(0, iy);
341
342    // clamp to the left
343    if (ix < 0) {
344        int n = SkMin32(-ix, count);
345        sk_memset32(colors, row[0], n);
346        count -= n;
347        if (0 == count) {
348            return;
349        }
350        colors += n;
351        SkASSERT(-ix == n);
352        ix = 0;
353    }
354    // copy the middle
355    if (ix <= maxX) {
356        int n = SkMin32(maxX - ix + 1, count);
357        memcpy(colors, row + ix, n * sizeof(SkPMColor));
358        count -= n;
359        if (0 == count) {
360            return;
361        }
362        colors += n;
363    }
364    SkASSERT(count > 0);
365    // clamp to the right
366    sk_memset32(colors, row[maxX], count);
367}
368
369static inline int sk_int_mod(int x, int n) {
370    SkASSERT(n > 0);
371    if ((unsigned)x >= (unsigned)n) {
372        if (x < 0) {
373            x = n + ~(~x % n);
374        } else {
375            x = x % n;
376        }
377    }
378    return x;
379}
380
381static inline int sk_int_mirror(int x, int n) {
382    x = sk_int_mod(x, 2 * n);
383    if (x >= n) {
384        x = n + ~(x - n);
385    }
386    return x;
387}
388
389static void Repeat_S32_D32_nofilter_trans_shaderproc(const SkBitmapProcState& s,
390                                                     int x, int y,
391                                                     SkPMColor* SK_RESTRICT colors,
392                                                     int count) {
393    SkASSERT(((s.fInvType & ~SkMatrix::kTranslate_Mask)) == 0);
394    SkASSERT(s.fInvKy == 0);
395    SkASSERT(count > 0 && colors != NULL);
396    SkASSERT(!s.fDoFilter);
397
398    const int stopX = s.fBitmap->width();
399    const int stopY = s.fBitmap->height();
400    int ix = s.fFilterOneX + x;
401    int iy = sk_int_mod(s.fFilterOneY + y, stopY);
402#ifdef SK_DEBUG
403    {
404        SkPoint pt;
405        s.fInvProc(*s.fInvMatrix, SkIntToScalar(x) + SK_ScalarHalf,
406                   SkIntToScalar(y) + SK_ScalarHalf, &pt);
407        int iy2 = sk_int_mod(SkScalarFloorToInt(pt.fY), stopY);
408        int ix2 = SkScalarFloorToInt(pt.fX);
409
410        SkASSERT(iy == iy2);
411        SkASSERT(ix == ix2);
412    }
413#endif
414    const SkPMColor* row = s.fBitmap->getAddr32(0, iy);
415
416    ix = sk_int_mod(ix, stopX);
417    for (;;) {
418        int n = SkMin32(stopX - ix, count);
419        memcpy(colors, row + ix, n * sizeof(SkPMColor));
420        count -= n;
421        if (0 == count) {
422            return;
423        }
424        colors += n;
425        ix = 0;
426    }
427}
428
429static void S32_D32_constX_shaderproc(const SkBitmapProcState& s,
430                                      int x, int y,
431                                      SkPMColor* SK_RESTRICT colors,
432                                      int count) {
433    SkASSERT((s.fInvType & ~(SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) == 0);
434    SkASSERT(s.fInvKy == 0);
435    SkASSERT(count > 0 && colors != NULL);
436    SkASSERT(1 == s.fBitmap->width());
437
438    int iY0;
439    int iY1   SK_INIT_TO_AVOID_WARNING;
440    int iSubY SK_INIT_TO_AVOID_WARNING;
441
442    if (s.fDoFilter) {
443        SkBitmapProcState::MatrixProc mproc = s.getMatrixProc();
444        uint32_t xy[2];
445
446        mproc(s, xy, 1, x, y);
447
448        iY0 = xy[0] >> 18;
449        iY1 = xy[0] & 0x3FFF;
450        iSubY = (xy[0] >> 14) & 0xF;
451    } else {
452        int yTemp;
453
454        if (s.fInvType > SkMatrix::kTranslate_Mask) {
455            SkPoint pt;
456            s.fInvProc(*s.fInvMatrix,
457                       SkIntToScalar(x) + SK_ScalarHalf,
458                       SkIntToScalar(y) + SK_ScalarHalf,
459                       &pt);
460            // When the matrix has a scale component the setup code in
461            // chooseProcs multiples the inverse matrix by the inverse of the
462            // bitmap's width and height. Since this method is going to do
463            // its own tiling and sampling we need to undo that here.
464            if (SkShader::kClamp_TileMode != s.fTileModeX ||
465                SkShader::kClamp_TileMode != s.fTileModeY) {
466                yTemp = SkScalarFloorToInt(pt.fY * s.fBitmap->height());
467            } else {
468                yTemp = SkScalarFloorToInt(pt.fY);
469            }
470        } else {
471            yTemp = s.fFilterOneY + y;
472        }
473
474        const int stopY = s.fBitmap->height();
475        switch (s.fTileModeY) {
476            case SkShader::kClamp_TileMode:
477                iY0 = SkClampMax(yTemp, stopY-1);
478                break;
479            case SkShader::kRepeat_TileMode:
480                iY0 = sk_int_mod(yTemp, stopY);
481                break;
482            case SkShader::kMirror_TileMode:
483            default:
484                iY0 = sk_int_mirror(yTemp, stopY);
485                break;
486        }
487
488#ifdef SK_DEBUG
489        {
490            SkPoint pt;
491            s.fInvProc(*s.fInvMatrix,
492                       SkIntToScalar(x) + SK_ScalarHalf,
493                       SkIntToScalar(y) + SK_ScalarHalf,
494                       &pt);
495            if (s.fInvType > SkMatrix::kTranslate_Mask &&
496                (SkShader::kClamp_TileMode != s.fTileModeX ||
497                 SkShader::kClamp_TileMode != s.fTileModeY)) {
498                pt.fY *= s.fBitmap->height();
499            }
500            int iY2;
501
502            switch (s.fTileModeY) {
503            case SkShader::kClamp_TileMode:
504                iY2 = SkClampMax(SkScalarFloorToInt(pt.fY), stopY-1);
505                break;
506            case SkShader::kRepeat_TileMode:
507                iY2 = sk_int_mod(SkScalarFloorToInt(pt.fY), stopY);
508                break;
509            case SkShader::kMirror_TileMode:
510            default:
511                iY2 = sk_int_mirror(SkScalarFloorToInt(pt.fY), stopY);
512                break;
513            }
514
515            SkASSERT(iY0 == iY2);
516        }
517#endif
518    }
519
520    const SkPMColor* row0 = s.fBitmap->getAddr32(0, iY0);
521    SkPMColor color;
522
523    if (s.fDoFilter) {
524        const SkPMColor* row1 = s.fBitmap->getAddr32(0, iY1);
525
526        if (s.fAlphaScale < 256) {
527            Filter_32_alpha(iSubY, *row0, *row1, &color, s.fAlphaScale);
528        } else {
529            Filter_32_opaque(iSubY, *row0, *row1, &color);
530        }
531    } else {
532        if (s.fAlphaScale < 256) {
533            color = SkAlphaMulQ(*row0, s.fAlphaScale);
534        } else {
535            color = *row0;
536        }
537    }
538
539    sk_memset32(colors, color, count);
540}
541
542static void DoNothing_shaderproc(const SkBitmapProcState&, int x, int y,
543                                 SkPMColor* SK_RESTRICT colors, int count) {
544    // if we get called, the matrix is too tricky, so we just draw nothing
545    sk_memset32(colors, 0, count);
546}
547
548bool SkBitmapProcState::setupForTranslate() {
549    SkPoint pt;
550    fInvProc(*fInvMatrix, SK_ScalarHalf, SK_ScalarHalf, &pt);
551
552    /*
553     *  if the translate is larger than our ints, we can get random results, or
554     *  worse, we might get 0x80000000, which wreaks havoc on us, since we can't
555     *  negate it.
556     */
557    const SkScalar too_big = SkIntToScalar(1 << 30);
558    if (SkScalarAbs(pt.fX) > too_big || SkScalarAbs(pt.fY) > too_big) {
559        return false;
560    }
561
562    // Since we know we're not filtered, we re-purpose these fields allow
563    // us to go from device -> src coordinates w/ just an integer add,
564    // rather than running through the inverse-matrix
565    fFilterOneX = SkScalarFloorToInt(pt.fX);
566    fFilterOneY = SkScalarFloorToInt(pt.fY);
567    return true;
568}
569
570SkBitmapProcState::ShaderProc32 SkBitmapProcState::chooseShaderProc32() {
571
572    if (SkBitmap::kARGB_8888_Config != fBitmap->config()) {
573        return NULL;
574    }
575
576    static const unsigned kMask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask;
577
578    if (1 == fBitmap->width() && 0 == (fInvType & ~kMask)) {
579        if (!fDoFilter && fInvType <= SkMatrix::kTranslate_Mask && !this->setupForTranslate()) {
580            return DoNothing_shaderproc;
581        }
582        return S32_D32_constX_shaderproc;
583    }
584
585    if (fAlphaScale < 256) {
586        return NULL;
587    }
588    if (fInvType > SkMatrix::kTranslate_Mask) {
589        return NULL;
590    }
591    if (fDoFilter) {
592        return NULL;
593    }
594
595    SkShader::TileMode tx = (SkShader::TileMode)fTileModeX;
596    SkShader::TileMode ty = (SkShader::TileMode)fTileModeY;
597
598    if (SkShader::kClamp_TileMode == tx && SkShader::kClamp_TileMode == ty) {
599        if (this->setupForTranslate()) {
600            return Clamp_S32_D32_nofilter_trans_shaderproc;
601        }
602        return DoNothing_shaderproc;
603    }
604    if (SkShader::kRepeat_TileMode == tx && SkShader::kRepeat_TileMode == ty) {
605        if (this->setupForTranslate()) {
606            return Repeat_S32_D32_nofilter_trans_shaderproc;
607        }
608        return DoNothing_shaderproc;
609    }
610    return NULL;
611}
612
613///////////////////////////////////////////////////////////////////////////////
614
615#ifdef SK_DEBUG
616
617static void check_scale_nofilter(uint32_t bitmapXY[], int count,
618                                 unsigned mx, unsigned my) {
619    unsigned y = *bitmapXY++;
620    SkASSERT(y < my);
621
622    const uint16_t* xptr = reinterpret_cast<const uint16_t*>(bitmapXY);
623    for (int i = 0; i < count; ++i) {
624        SkASSERT(xptr[i] < mx);
625    }
626}
627
628static void check_scale_filter(uint32_t bitmapXY[], int count,
629                                 unsigned mx, unsigned my) {
630    uint32_t YY = *bitmapXY++;
631    unsigned y0 = YY >> 18;
632    unsigned y1 = YY & 0x3FFF;
633    SkASSERT(y0 < my);
634    SkASSERT(y1 < my);
635
636    for (int i = 0; i < count; ++i) {
637        uint32_t XX = bitmapXY[i];
638        unsigned x0 = XX >> 18;
639        unsigned x1 = XX & 0x3FFF;
640        SkASSERT(x0 < mx);
641        SkASSERT(x1 < mx);
642    }
643}
644
645static void check_affine_nofilter(uint32_t bitmapXY[], int count,
646                                 unsigned mx, unsigned my) {
647    for (int i = 0; i < count; ++i) {
648        uint32_t XY = bitmapXY[i];
649        unsigned x = XY & 0xFFFF;
650        unsigned y = XY >> 16;
651        SkASSERT(x < mx);
652        SkASSERT(y < my);
653    }
654}
655
656static void check_affine_filter(uint32_t bitmapXY[], int count,
657                                 unsigned mx, unsigned my) {
658    for (int i = 0; i < count; ++i) {
659        uint32_t YY = *bitmapXY++;
660        unsigned y0 = YY >> 18;
661        unsigned y1 = YY & 0x3FFF;
662        SkASSERT(y0 < my);
663        SkASSERT(y1 < my);
664
665        uint32_t XX = *bitmapXY++;
666        unsigned x0 = XX >> 18;
667        unsigned x1 = XX & 0x3FFF;
668        SkASSERT(x0 < mx);
669        SkASSERT(x1 < mx);
670    }
671}
672
673void SkBitmapProcState::DebugMatrixProc(const SkBitmapProcState& state,
674                                        uint32_t bitmapXY[], int count,
675                                        int x, int y) {
676    SkASSERT(bitmapXY);
677    SkASSERT(count > 0);
678
679    state.fMatrixProc(state, bitmapXY, count, x, y);
680
681    void (*proc)(uint32_t bitmapXY[], int count, unsigned mx, unsigned my);
682
683    // There are four formats possible:
684    //  scale -vs- affine
685    //  filter -vs- nofilter
686    if (state.fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) {
687        proc = state.fDoFilter ? check_scale_filter : check_scale_nofilter;
688    } else {
689        proc = state.fDoFilter ? check_affine_filter : check_affine_nofilter;
690    }
691    proc(bitmapXY, count, state.fBitmap->width(), state.fBitmap->height());
692}
693
694SkBitmapProcState::MatrixProc SkBitmapProcState::getMatrixProc() const {
695    return DebugMatrixProc;
696}
697
698#endif
699
700///////////////////////////////////////////////////////////////////////////////
701/*
702    The storage requirements for the different matrix procs are as follows,
703    where each X or Y is 2 bytes, and N is the number of pixels/elements:
704
705    scale/translate     nofilter      Y(4bytes) + N * X
706    affine/perspective  nofilter      N * (X Y)
707    scale/translate     filter        Y Y + N * (X X)
708    affine/perspective  filter        N * (Y Y X X)
709 */
710int SkBitmapProcState::maxCountForBufferSize(size_t bufferSize) const {
711    int32_t size = static_cast<int32_t>(bufferSize);
712
713    size &= ~3; // only care about 4-byte aligned chunks
714    if (fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) {
715        size -= 4;   // the shared Y (or YY) coordinate
716        if (size < 0) {
717            size = 0;
718        }
719        size >>= 1;
720    } else {
721        size >>= 2;
722    }
723
724    if (fDoFilter) {
725        size >>= 1;
726    }
727
728    return size;
729}
730