SkBitmapProcState.cpp revision a8d99307717c5fe02043969db0566c236a08c313
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#if !SK_ARM_NEON_IS_ALWAYS
28#define   NAME_WRAP(x)  x
29#include "SkBitmapProcState_filter.h"
30#include "SkBitmapProcState_procs.h"
31#endif
32
33///////////////////////////////////////////////////////////////////////////////
34
35static bool valid_for_filtering(unsigned dimension) {
36    // for filtering, width and height must fit in 14bits, since we use steal
37    // 2 bits from each to store our 4bit subpixel data
38    return (dimension & ~0x3FFF) == 0;
39}
40
41bool SkBitmapProcState::chooseProcs(const SkMatrix& inv, const SkPaint& paint) {
42    if (fOrigBitmap.width() == 0 || fOrigBitmap.height() == 0) {
43        return false;
44    }
45
46    const SkMatrix* m;
47    bool trivial_matrix = (inv.getType() & ~SkMatrix::kTranslate_Mask) == 0;
48    bool clamp_clamp = SkShader::kClamp_TileMode == fTileModeX &&
49                       SkShader::kClamp_TileMode == fTileModeY;
50
51    if (clamp_clamp || trivial_matrix) {
52        m = &inv;
53    } else {
54        fUnitInvMatrix = inv;
55        fUnitInvMatrix.postIDiv(fOrigBitmap.width(), fOrigBitmap.height());
56        m = &fUnitInvMatrix;
57    }
58
59    fBitmap = &fOrigBitmap;
60    if (fOrigBitmap.hasMipMap()) {
61        int shift = fOrigBitmap.extractMipLevel(&fMipBitmap,
62                                                SkScalarToFixed(m->getScaleX()),
63                                                SkScalarToFixed(m->getSkewY()));
64
65        if (shift > 0) {
66            if (m != &fUnitInvMatrix) {
67                fUnitInvMatrix = *m;
68                m = &fUnitInvMatrix;
69            }
70
71            SkScalar scale = SkFixedToScalar(SK_Fixed1 >> shift);
72            fUnitInvMatrix.postScale(scale, scale);
73
74            // now point here instead of fOrigBitmap
75            fBitmap = &fMipBitmap;
76        }
77    }
78
79    fInvMatrix      = m;
80    fInvProc        = m->getMapXYProc();
81    fInvType        = m->getType();
82    fInvSx          = SkScalarToFixed(m->getScaleX());
83    fInvSxFractionalInt = SkScalarToFractionalInt(m->getScaleX());
84    fInvKy          = SkScalarToFixed(m->getSkewY());
85    fInvKyFractionalInt = SkScalarToFractionalInt(m->getSkewY());
86
87    fAlphaScale = SkAlpha255To256(paint.getAlpha());
88
89    // pick-up filtering from the paint, but only if the matrix is
90    // more complex than identity/translate (i.e. no need to pay the cost
91    // of filtering if we're not scaled etc.).
92    // note: we explicitly check inv, since m might be scaled due to unitinv
93    //       trickery, but we don't want to see that for this test
94    fDoFilter = paint.isFilterBitmap() &&
95                (inv.getType() > SkMatrix::kTranslate_Mask &&
96                 valid_for_filtering(fBitmap->width() | fBitmap->height()));
97
98    fShaderProc32 = NULL;
99    fShaderProc16 = NULL;
100    fSampleProc32 = NULL;
101    fSampleProc16 = NULL;
102
103    fMatrixProc = this->chooseMatrixProc(trivial_matrix);
104    if (NULL == fMatrixProc) {
105        return false;
106    }
107
108    ///////////////////////////////////////////////////////////////////////
109
110    int index = 0;
111    if (fAlphaScale < 256) {  // note: this distinction is not used for D16
112        index |= 1;
113    }
114    if (fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) {
115        index |= 2;
116    }
117    if (fDoFilter) {
118        index |= 4;
119    }
120    // bits 3,4,5 encoding the source bitmap format
121    switch (fBitmap->config()) {
122        case SkBitmap::kARGB_8888_Config:
123            index |= 0;
124            break;
125        case SkBitmap::kRGB_565_Config:
126            index |= 8;
127            break;
128        case SkBitmap::kIndex8_Config:
129            index |= 16;
130            break;
131        case SkBitmap::kARGB_4444_Config:
132            index |= 24;
133            break;
134        case SkBitmap::kA8_Config:
135            index |= 32;
136            fPaintPMColor = SkPreMultiplyColor(paint.getColor());
137            break;
138        default:
139            return false;
140    }
141
142#if !SK_ARM_NEON_IS_ALWAYS
143    static const SampleProc32 gSkBitmapProcStateSample32[] = {
144        S32_opaque_D32_nofilter_DXDY,
145        S32_alpha_D32_nofilter_DXDY,
146        S32_opaque_D32_nofilter_DX,
147        S32_alpha_D32_nofilter_DX,
148        S32_opaque_D32_filter_DXDY,
149        S32_alpha_D32_filter_DXDY,
150        S32_opaque_D32_filter_DX,
151        S32_alpha_D32_filter_DX,
152
153        S16_opaque_D32_nofilter_DXDY,
154        S16_alpha_D32_nofilter_DXDY,
155        S16_opaque_D32_nofilter_DX,
156        S16_alpha_D32_nofilter_DX,
157        S16_opaque_D32_filter_DXDY,
158        S16_alpha_D32_filter_DXDY,
159        S16_opaque_D32_filter_DX,
160        S16_alpha_D32_filter_DX,
161
162        SI8_opaque_D32_nofilter_DXDY,
163        SI8_alpha_D32_nofilter_DXDY,
164        SI8_opaque_D32_nofilter_DX,
165        SI8_alpha_D32_nofilter_DX,
166        SI8_opaque_D32_filter_DXDY,
167        SI8_alpha_D32_filter_DXDY,
168        SI8_opaque_D32_filter_DX,
169        SI8_alpha_D32_filter_DX,
170
171        S4444_opaque_D32_nofilter_DXDY,
172        S4444_alpha_D32_nofilter_DXDY,
173        S4444_opaque_D32_nofilter_DX,
174        S4444_alpha_D32_nofilter_DX,
175        S4444_opaque_D32_filter_DXDY,
176        S4444_alpha_D32_filter_DXDY,
177        S4444_opaque_D32_filter_DX,
178        S4444_alpha_D32_filter_DX,
179
180        // A8 treats alpha/opauqe the same (equally efficient)
181        SA8_alpha_D32_nofilter_DXDY,
182        SA8_alpha_D32_nofilter_DXDY,
183        SA8_alpha_D32_nofilter_DX,
184        SA8_alpha_D32_nofilter_DX,
185        SA8_alpha_D32_filter_DXDY,
186        SA8_alpha_D32_filter_DXDY,
187        SA8_alpha_D32_filter_DX,
188        SA8_alpha_D32_filter_DX
189    };
190
191    static const SampleProc16 gSkBitmapProcStateSample16[] = {
192        S32_D16_nofilter_DXDY,
193        S32_D16_nofilter_DX,
194        S32_D16_filter_DXDY,
195        S32_D16_filter_DX,
196
197        S16_D16_nofilter_DXDY,
198        S16_D16_nofilter_DX,
199        S16_D16_filter_DXDY,
200        S16_D16_filter_DX,
201
202        SI8_D16_nofilter_DXDY,
203        SI8_D16_nofilter_DX,
204        SI8_D16_filter_DXDY,
205        SI8_D16_filter_DX,
206
207        // Don't support 4444 -> 565
208        NULL, NULL, NULL, NULL,
209        // Don't support A8 -> 565
210        NULL, NULL, NULL, NULL
211    };
212#endif
213
214    fSampleProc32 = SK_ARM_NEON_WRAP(gSkBitmapProcStateSample32)[index];
215    index >>= 1;    // shift away any opaque/alpha distinction
216    fSampleProc16 = SK_ARM_NEON_WRAP(gSkBitmapProcStateSample16)[index];
217
218    // our special-case shaderprocs
219    if (SK_ARM_NEON_WRAP(S16_D16_filter_DX) == fSampleProc16) {
220        if (clamp_clamp) {
221            fShaderProc16 = SK_ARM_NEON_WRAP(Clamp_S16_D16_filter_DX_shaderproc);
222        } else if (SkShader::kRepeat_TileMode == fTileModeX &&
223                   SkShader::kRepeat_TileMode == fTileModeY) {
224            fShaderProc16 = SK_ARM_NEON_WRAP(Repeat_S16_D16_filter_DX_shaderproc);
225        }
226    } else if (SK_ARM_NEON_WRAP(SI8_opaque_D32_filter_DX) == fSampleProc32 && clamp_clamp) {
227        fShaderProc32 = SK_ARM_NEON_WRAP(Clamp_SI8_opaque_D32_filter_DX_shaderproc);
228    }
229
230    if (NULL == fShaderProc32) {
231        fShaderProc32 = this->chooseShaderProc32();
232    }
233
234    // see if our platform has any accelerated overrides
235    this->platformProcs();
236    return true;
237}
238
239static void Clamp_S32_D32_nofilter_trans_shaderproc(const SkBitmapProcState& s,
240                                                    int x, int y,
241                                                    SkPMColor* SK_RESTRICT colors,
242                                                    int count) {
243    SkASSERT(((s.fInvType & ~SkMatrix::kTranslate_Mask)) == 0);
244    SkASSERT(s.fInvKy == 0);
245    SkASSERT(count > 0 && colors != NULL);
246    SkASSERT(!s.fDoFilter);
247
248    const int maxX = s.fBitmap->width() - 1;
249    const int maxY = s.fBitmap->height() - 1;
250    int ix = s.fFilterOneX + x;
251    int iy = SkClampMax(s.fFilterOneY + y, maxY);
252#ifdef SK_DEBUG
253    {
254        SkPoint pt;
255        s.fInvProc(*s.fInvMatrix, SkIntToScalar(x) + SK_ScalarHalf,
256                   SkIntToScalar(y) + SK_ScalarHalf, &pt);
257        int iy2 = SkClampMax(SkScalarFloorToInt(pt.fY), maxY);
258        int ix2 = SkScalarFloorToInt(pt.fX);
259
260        SkASSERT(iy == iy2);
261        SkASSERT(ix == ix2);
262    }
263#endif
264    const SkPMColor* row = s.fBitmap->getAddr32(0, iy);
265
266    // clamp to the left
267    if (ix < 0) {
268        int n = SkMin32(-ix, count);
269        sk_memset32(colors, row[0], n);
270        count -= n;
271        if (0 == count) {
272            return;
273        }
274        colors += n;
275        SkASSERT(-ix == n);
276        ix = 0;
277    }
278    // copy the middle
279    if (ix <= maxX) {
280        int n = SkMin32(maxX - ix + 1, count);
281        memcpy(colors, row + ix, n * sizeof(SkPMColor));
282        count -= n;
283        if (0 == count) {
284            return;
285        }
286        colors += n;
287    }
288    SkASSERT(count > 0);
289    // clamp to the right
290    sk_memset32(colors, row[maxX], count);
291}
292
293static inline int sk_int_mod(int x, int n) {
294    SkASSERT(n > 0);
295    if ((unsigned)x >= (unsigned)n) {
296        if (x < 0) {
297            x = n + ~(~x % n);
298        } else {
299            x = x % n;
300        }
301    }
302    return x;
303}
304
305static void Repeat_S32_D32_nofilter_trans_shaderproc(const SkBitmapProcState& s,
306                                                     int x, int y,
307                                                     SkPMColor* SK_RESTRICT colors,
308                                                     int count) {
309    SkASSERT(((s.fInvType & ~SkMatrix::kTranslate_Mask)) == 0);
310    SkASSERT(s.fInvKy == 0);
311    SkASSERT(count > 0 && colors != NULL);
312    SkASSERT(!s.fDoFilter);
313
314    const int stopX = s.fBitmap->width();
315    const int stopY = s.fBitmap->height();
316    int ix = s.fFilterOneX + x;
317    int iy = sk_int_mod(s.fFilterOneY + y, stopY);
318#ifdef SK_DEBUG
319    {
320        SkPoint pt;
321        s.fInvProc(*s.fInvMatrix, SkIntToScalar(x) + SK_ScalarHalf,
322                   SkIntToScalar(y) + SK_ScalarHalf, &pt);
323        int iy2 = sk_int_mod(SkScalarFloorToInt(pt.fY), stopY);
324        int ix2 = SkScalarFloorToInt(pt.fX);
325
326        SkASSERT(iy == iy2);
327        SkASSERT(ix == ix2);
328    }
329#endif
330    const SkPMColor* row = s.fBitmap->getAddr32(0, iy);
331
332    ix = sk_int_mod(ix, stopX);
333    for (;;) {
334        int n = SkMin32(stopX - ix, count);
335        memcpy(colors, row + ix, n * sizeof(SkPMColor));
336        count -= n;
337        if (0 == count) {
338            return;
339        }
340        colors += n;
341        ix = 0;
342    }
343}
344
345void SkBitmapProcState::setupForTranslate() {
346    SkPoint pt;
347    fInvProc(*fInvMatrix, SK_ScalarHalf, SK_ScalarHalf, &pt);
348    // Since we know we're not filtered, we re-purpose these fields allow
349    // us to go from device -> src coordinates w/ just an integer add,
350    // rather than running through the inverse-matrix
351    fFilterOneX = SkScalarFloorToInt(pt.fX);
352    fFilterOneY = SkScalarFloorToInt(pt.fY);
353}
354
355SkBitmapProcState::ShaderProc32 SkBitmapProcState::chooseShaderProc32() {
356    if (fAlphaScale < 256) {
357        return NULL;
358    }
359    if (fInvType > SkMatrix::kTranslate_Mask) {
360        return NULL;
361    }
362    if (fDoFilter) {
363        return NULL;
364    }
365    if (SkBitmap::kARGB_8888_Config != fBitmap->config()) {
366        return NULL;
367    }
368
369    SkShader::TileMode tx = (SkShader::TileMode)fTileModeX;
370    SkShader::TileMode ty = (SkShader::TileMode)fTileModeY;
371
372    if (SkShader::kClamp_TileMode == tx && SkShader::kClamp_TileMode == ty) {
373        this->setupForTranslate();
374        return Clamp_S32_D32_nofilter_trans_shaderproc;
375    }
376    if (SkShader::kRepeat_TileMode == tx && SkShader::kRepeat_TileMode == ty) {
377        this->setupForTranslate();
378        return Repeat_S32_D32_nofilter_trans_shaderproc;
379    }
380    return NULL;
381}
382
383///////////////////////////////////////////////////////////////////////////////
384
385#ifdef SK_DEBUG
386
387static void check_scale_nofilter(uint32_t bitmapXY[], int count,
388                                 unsigned mx, unsigned my) {
389    unsigned y = *bitmapXY++;
390    SkASSERT(y < my);
391
392    const uint16_t* xptr = reinterpret_cast<const uint16_t*>(bitmapXY);
393    for (int i = 0; i < count; ++i) {
394        SkASSERT(xptr[i] < mx);
395    }
396}
397
398static void check_scale_filter(uint32_t bitmapXY[], int count,
399                                 unsigned mx, unsigned my) {
400    uint32_t YY = *bitmapXY++;
401    unsigned y0 = YY >> 18;
402    unsigned y1 = YY & 0x3FFF;
403    SkASSERT(y0 < my);
404    SkASSERT(y1 < my);
405
406    for (int i = 0; i < count; ++i) {
407        uint32_t XX = bitmapXY[i];
408        unsigned x0 = XX >> 18;
409        unsigned x1 = XX & 0x3FFF;
410        SkASSERT(x0 < mx);
411        SkASSERT(x1 < mx);
412    }
413}
414
415static void check_affine_nofilter(uint32_t bitmapXY[], int count,
416                                 unsigned mx, unsigned my) {
417    for (int i = 0; i < count; ++i) {
418        uint32_t XY = bitmapXY[i];
419        unsigned x = XY & 0xFFFF;
420        unsigned y = XY >> 16;
421        SkASSERT(x < mx);
422        SkASSERT(y < my);
423    }
424}
425
426static void check_affine_filter(uint32_t bitmapXY[], int count,
427                                 unsigned mx, unsigned my) {
428    for (int i = 0; i < count; ++i) {
429        uint32_t YY = *bitmapXY++;
430        unsigned y0 = YY >> 18;
431        unsigned y1 = YY & 0x3FFF;
432        SkASSERT(y0 < my);
433        SkASSERT(y1 < my);
434
435        uint32_t XX = *bitmapXY++;
436        unsigned x0 = XX >> 18;
437        unsigned x1 = XX & 0x3FFF;
438        SkASSERT(x0 < mx);
439        SkASSERT(x1 < mx);
440    }
441}
442
443void SkBitmapProcState::DebugMatrixProc(const SkBitmapProcState& state,
444                                        uint32_t bitmapXY[], int count,
445                                        int x, int y) {
446    SkASSERT(bitmapXY);
447    SkASSERT(count > 0);
448
449    state.fMatrixProc(state, bitmapXY, count, x, y);
450
451    void (*proc)(uint32_t bitmapXY[], int count, unsigned mx, unsigned my);
452
453    // There are four formats possible:
454    //  scale -vs- affine
455    //  filter -vs- nofilter
456    if (state.fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) {
457        proc = state.fDoFilter ? check_scale_filter : check_scale_nofilter;
458    } else {
459        proc = state.fDoFilter ? check_affine_filter : check_affine_nofilter;
460    }
461    proc(bitmapXY, count, state.fBitmap->width(), state.fBitmap->height());
462}
463
464SkBitmapProcState::MatrixProc SkBitmapProcState::getMatrixProc() const {
465    return DebugMatrixProc;
466}
467
468#endif
469
470///////////////////////////////////////////////////////////////////////////////
471/*
472    The storage requirements for the different matrix procs are as follows,
473    where each X or Y is 2 bytes, and N is the number of pixels/elements:
474
475    scale/translate     nofilter      Y(4bytes) + N * X
476    affine/perspective  nofilter      N * (X Y)
477    scale/translate     filter        Y Y + N * (X X)
478    affine/perspective  filter        N * (Y Y X X)
479 */
480int SkBitmapProcState::maxCountForBufferSize(size_t bufferSize) const {
481    int32_t size = static_cast<int32_t>(bufferSize);
482
483    size &= ~3; // only care about 4-byte aligned chunks
484    if (fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) {
485        size -= 4;   // the shared Y (or YY) coordinate
486        if (size < 0) {
487            size = 0;
488        }
489        size >>= 1;
490    } else {
491        size >>= 2;
492    }
493
494    if (fDoFilter) {
495        size >>= 1;
496    }
497
498    return size;
499}
500
501