SkBitmapProcState.cpp revision 3469c76c40790b409621fd7eff34f56240718549
1#include "SkBitmapProcState.h"
2#include "SkColorPriv.h"
3#include "SkFilterProc.h"
4#include "SkPaint.h"
5#include "SkShader.h"   // for tilemodes
6
7#ifdef SK_CPU_BENDIAN
8    #define UNPACK_PRIMARY_SHORT(packed)    ((uint32_t)(packed) >> 16)
9    #define UNPACK_SECONDARY_SHORT(packed)  ((packed) & 0xFFFF)
10#else
11    #define UNPACK_PRIMARY_SHORT(packed)    ((packed) & 0xFFFF)
12    #define UNPACK_SECONDARY_SHORT(packed)  ((uint32_t)(packed) >> 16)
13#endif
14
15static inline SkPMColor Filter_32(unsigned x, unsigned y,
16                                  SkPMColor a00, SkPMColor a01,
17                                  SkPMColor a10, SkPMColor a11) {
18    SkASSERT((unsigned)x <= 0xF);
19    SkASSERT((unsigned)y <= 0xF);
20
21    int xy = x * y;
22    uint32_t mask = gMask_00FF00FF; //0xFF00FF;
23
24    int scale = 256 - 16*y - 16*x + xy;
25    uint32_t lo = (a00 & mask) * scale;
26    uint32_t hi = ((a00 >> 8) & mask) * scale;
27
28    scale = 16*x - xy;
29    lo += (a01 & mask) * scale;
30    hi += ((a01 >> 8) & mask) * scale;
31
32    scale = 16*y - xy;
33    lo += (a10 & mask) * scale;
34    hi += ((a10 >> 8) & mask) * scale;
35
36    lo += (a11 & mask) * xy;
37    hi += ((a11 >> 8) & mask) * xy;
38
39    return ((lo >> 8) & mask) | (hi & ~mask);
40}
41
42// returns expanded * 5bits
43static inline uint32_t Filter_565_Expanded(unsigned x, unsigned y,
44                                           uint32_t a00, uint32_t a01,
45                                           uint32_t a10, uint32_t a11) {
46    SkASSERT((unsigned)x <= 0xF);
47    SkASSERT((unsigned)y <= 0xF);
48
49    a00 = SkExpand_rgb_16(a00);
50    a01 = SkExpand_rgb_16(a01);
51    a10 = SkExpand_rgb_16(a10);
52    a11 = SkExpand_rgb_16(a11);
53
54    int xy = x * y >> 3;
55    return  a00 * (32 - 2*y - 2*x + xy) +
56            a01 * (2*x - xy) +
57            a10 * (2*y - xy) +
58            a11 * xy;
59}
60
61// turn an expanded 565 * 5bits into SkPMColor
62// g:11 | r:10 | x:1 | b:10
63static inline SkPMColor SkExpanded_565_To_PMColor(uint32_t c) {
64    unsigned r = (c >> 13) & 0xFF;
65    unsigned g = (c >> 24);
66    unsigned b = (c >> 2) & 0xFF;
67    return SkPackARGB32(0xFF, r, g, b);
68}
69
70// returns answer in SkPMColor format
71static inline SkPMColor Filter_4444_D32(unsigned x, unsigned y,
72                                        uint32_t a00, uint32_t a01,
73                                        uint32_t a10, uint32_t a11) {
74    SkASSERT((unsigned)x <= 0xF);
75    SkASSERT((unsigned)y <= 0xF);
76
77    a00 = SkExpand_4444(a00);
78    a01 = SkExpand_4444(a01);
79    a10 = SkExpand_4444(a10);
80    a11 = SkExpand_4444(a11);
81
82    int xy = x * y >> 4;
83    uint32_t result =   a00 * (16 - y - x + xy) +
84                        a01 * (x - xy) +
85                        a10 * (y - xy) +
86                        a11 * xy;
87
88    return SkCompact_8888(result);
89}
90
91static inline U8CPU Filter_8(unsigned x, unsigned y,
92                             U8CPU a00, U8CPU a01,
93                             U8CPU a10, U8CPU a11) {
94    SkASSERT((unsigned)x <= 0xF);
95    SkASSERT((unsigned)y <= 0xF);
96
97    int xy = x * y;
98    unsigned result =   a00 * (256 - 16*y - 16*x + xy) +
99                        a01 * (16*x - xy) +
100                        a10 * (16*y - xy) +
101                        a11 * xy;
102
103    return result >> 8;
104}
105
106/*****************************************************************************
107 *
108 *  D32 functions
109 *
110 */
111
112// SRC == 8888
113
114#define FILTER_PROC(x, y, a, b, c, d)   Filter_32(x, y, a, b, c, d)
115
116#define MAKENAME(suffix)        S32_opaque_D32 ## suffix
117#define DSTSIZE                 32
118#define SRCTYPE                 SkPMColor
119#define CHECKSTATE(state)       SkASSERT(state.fBitmap->config() == SkBitmap::kARGB_8888_Config); \
120                                SkASSERT(state.fAlphaScale == 256)
121#define RETURNDST(src)          src
122#define SRC_TO_FILTER(src)      src
123#define FILTER_TO_DST(c)        c
124#include "SkBitmapProcState_sample.h"
125
126#define MAKENAME(suffix)        S32_alpha_D32 ## suffix
127#define DSTSIZE                 32
128#define SRCTYPE                 SkPMColor
129#define CHECKSTATE(state)       SkASSERT(state.fBitmap->config() == SkBitmap::kARGB_8888_Config); \
130                                SkASSERT(state.fAlphaScale < 256)
131#define PREAMBLE(state)         unsigned scale = state.fAlphaScale
132#define RETURNDST(src)          SkAlphaMulQ(src, scale)
133#define SRC_TO_FILTER(src)      src
134#define FILTER_TO_DST(c)        SkAlphaMulQ(c, scale)
135#include "SkBitmapProcState_sample.h"
136
137// SRC == 565
138
139#undef FILTER_PROC
140#define FILTER_PROC(x, y, a, b, c, d)   Filter_565_Expanded(x, y, a, b, c, d)
141
142#define MAKENAME(suffix)        S16_opaque_D32 ## suffix
143#define DSTSIZE                 32
144#define SRCTYPE                 uint16_t
145#define CHECKSTATE(state)       SkASSERT(state.fBitmap->config() == SkBitmap::kRGB_565_Config); \
146                                SkASSERT(state.fAlphaScale == 256)
147#define RETURNDST(src)          SkPixel16ToPixel32(src)
148#define SRC_TO_FILTER(src)      src
149#define FILTER_TO_DST(c)        SkExpanded_565_To_PMColor(c)
150#include "SkBitmapProcState_sample.h"
151
152#define MAKENAME(suffix)        S16_alpha_D32 ## suffix
153#define DSTSIZE                 32
154#define SRCTYPE                 uint16_t
155#define CHECKSTATE(state)       SkASSERT(state.fBitmap->config() == SkBitmap::kRGB_565_Config); \
156                                SkASSERT(state.fAlphaScale < 256)
157#define PREAMBLE(state)         unsigned scale = state.fAlphaScale
158#define RETURNDST(src)          SkAlphaMulQ(SkPixel16ToPixel32(src), scale)
159#define SRC_TO_FILTER(src)      src
160#define FILTER_TO_DST(c)        SkAlphaMulQ(SkExpanded_565_To_PMColor(c), scale)
161#include "SkBitmapProcState_sample.h"
162
163// SRC == Index8
164
165#undef FILTER_PROC
166#define FILTER_PROC(x, y, a, b, c, d)   Filter_32(x, y, a, b, c, d)
167
168#define MAKENAME(suffix)        SI8_opaque_D32 ## suffix
169#define DSTSIZE                 32
170#define SRCTYPE                 uint8_t
171#define CHECKSTATE(state)       SkASSERT(state.fBitmap->config() == SkBitmap::kIndex8_Config); \
172                                SkASSERT(state.fAlphaScale == 256)
173#define PREAMBLE(state)         const SkPMColor* SK_RESTRICT table = state.fBitmap->getColorTable()->lockColors()
174#define RETURNDST(src)          table[src]
175#define SRC_TO_FILTER(src)      table[src]
176#define FILTER_TO_DST(c)        c
177#define POSTAMBLE(state)        state.fBitmap->getColorTable()->unlockColors(false)
178#include "SkBitmapProcState_sample.h"
179
180#define MAKENAME(suffix)        SI8_alpha_D32 ## suffix
181#define DSTSIZE                 32
182#define SRCTYPE                 uint8_t
183#define CHECKSTATE(state)       SkASSERT(state.fBitmap->config() == SkBitmap::kIndex8_Config); \
184                                SkASSERT(state.fAlphaScale < 256)
185#define PREAMBLE(state)         unsigned scale = state.fAlphaScale; \
186                                const SkPMColor* SK_RESTRICT table = state.fBitmap->getColorTable()->lockColors()
187#define RETURNDST(src)          SkAlphaMulQ(table[src], scale)
188#define SRC_TO_FILTER(src)      table[src]
189#define FILTER_TO_DST(c)        SkAlphaMulQ(c, scale)
190#define POSTAMBLE(state)        state.fBitmap->getColorTable()->unlockColors(false)
191#include "SkBitmapProcState_sample.h"
192
193// SRC == 4444
194
195#undef FILTER_PROC
196#define FILTER_PROC(x, y, a, b, c, d)   Filter_4444_D32(x, y, a, b, c, d)
197
198#define MAKENAME(suffix)        S4444_opaque_D32 ## suffix
199#define DSTSIZE                 32
200#define SRCTYPE                 SkPMColor16
201#define CHECKSTATE(state)       SkASSERT(state.fBitmap->config() == SkBitmap::kARGB_4444_Config); \
202SkASSERT(state.fAlphaScale == 256)
203#define RETURNDST(src)          SkPixel4444ToPixel32(src)
204#define SRC_TO_FILTER(src)      src
205#define FILTER_TO_DST(c)        c
206#include "SkBitmapProcState_sample.h"
207
208#define MAKENAME(suffix)        S4444_alpha_D32 ## suffix
209#define DSTSIZE                 32
210#define SRCTYPE                 SkPMColor16
211#define CHECKSTATE(state)       SkASSERT(state.fBitmap->config() == SkBitmap::kARGB_4444_Config); \
212SkASSERT(state.fAlphaScale < 256)
213#define PREAMBLE(state)         unsigned scale = state.fAlphaScale
214#define RETURNDST(src)          SkAlphaMulQ(SkPixel4444ToPixel32(src), scale)
215#define SRC_TO_FILTER(src)      src
216#define FILTER_TO_DST(c)        SkAlphaMulQ(c, scale)
217#include "SkBitmapProcState_sample.h"
218
219// SRC == A8
220
221#undef FILTER_PROC
222#define FILTER_PROC(x, y, a, b, c, d)   Filter_8(x, y, a, b, c, d)
223
224#define MAKENAME(suffix)        SA8_alpha_D32 ## suffix
225#define DSTSIZE                 32
226#define SRCTYPE                 uint8_t
227#define CHECKSTATE(state)       SkASSERT(state.fBitmap->config() == SkBitmap::kA8_Config); \
228                                SkASSERT(state.fAlphaScale == 256)
229#define PREAMBLE(state)         const SkPMColor pmColor = state.fPaintPMColor;
230#define RETURNDST(src)          SkAlphaMulQ(pmColor, SkAlpha255To256(src))
231#define SRC_TO_FILTER(src)      src
232#define FILTER_TO_DST(c)        SkAlphaMulQ(pmColor, SkAlpha255To256(c))
233#include "SkBitmapProcState_sample.h"
234
235/*****************************************************************************
236 *
237 *  D16 functions
238 *
239 */
240
241// SRC == 8888
242
243#undef FILTER_PROC
244#define FILTER_PROC(x, y, a, b, c, d)   Filter_32(x, y, a, b, c, d)
245
246#define MAKENAME(suffix)        S32_D16 ## suffix
247#define DSTSIZE                 16
248#define SRCTYPE                 SkPMColor
249#define CHECKSTATE(state)       SkASSERT(state.fBitmap->config() == SkBitmap::kARGB_8888_Config); \
250                                SkASSERT(state.fBitmap->isOpaque())
251#define RETURNDST(src)          SkPixel32ToPixel16(src)
252#define SRC_TO_FILTER(src)      src
253#define FILTER_TO_DST(c)        SkPixel32ToPixel16(c)
254#include "SkBitmapProcState_sample.h"
255
256// SRC == 565
257
258#undef FILTER_PROC
259#define FILTER_PROC(x, y, a, b, c, d)   Filter_565_Expanded(x, y, a, b, c, d)
260
261#define MAKENAME(suffix)        S16_D16 ## suffix
262#define DSTSIZE                 16
263#define SRCTYPE                 uint16_t
264#define CHECKSTATE(state)       SkASSERT(state.fBitmap->config() == SkBitmap::kRGB_565_Config)
265#define RETURNDST(src)          src
266#define SRC_TO_FILTER(src)      src
267#define FILTER_TO_DST(c)        SkCompact_rgb_16((c) >> 5)
268#include "SkBitmapProcState_sample.h"
269
270// SRC == Index8
271
272#undef FILTER_PROC
273#define FILTER_PROC(x, y, a, b, c, d)   Filter_565_Expanded(x, y, a, b, c, d)
274
275#define MAKENAME(suffix)        SI8_D16 ## suffix
276#define DSTSIZE                 16
277#define SRCTYPE                 uint8_t
278#define CHECKSTATE(state)       SkASSERT(state.fBitmap->config() == SkBitmap::kIndex8_Config); \
279                                SkASSERT(state.fBitmap->isOpaque())
280#define PREAMBLE(state)         const uint16_t* SK_RESTRICT table = state.fBitmap->getColorTable()->lock16BitCache()
281#define RETURNDST(src)          table[src]
282#define SRC_TO_FILTER(src)      table[src]
283#define FILTER_TO_DST(c)        SkCompact_rgb_16(c >> 5)
284#define POSTAMBLE(state)        state.fBitmap->getColorTable()->unlock16BitCache()
285#include "SkBitmapProcState_sample.h"
286
287static bool valid_for_filtering(unsigned dimension) {
288    // for filtering, width and height must fit in 14bits, since we use steal
289    // 2 bits from each to store our 4bit subpixel data
290    return (dimension & ~0x3FFF) == 0;
291}
292
293bool SkBitmapProcState::chooseProcs(const SkMatrix& inv, const SkPaint& paint) {
294    if (fOrigBitmap.width() == 0 || fOrigBitmap.height() == 0) {
295        return false;
296    }
297    const SkMatrix* m;
298
299    if (SkShader::kClamp_TileMode == fTileModeX &&
300            SkShader::kClamp_TileMode == fTileModeY) {
301        m = &inv;
302    } else {
303        fUnitInvMatrix = inv;
304        fUnitInvMatrix.postIDiv(fOrigBitmap.width(), fOrigBitmap.height());
305        m = &fUnitInvMatrix;
306    }
307
308    fBitmap = &fOrigBitmap;
309#ifdef SK_SUPPORT_MIPMAP
310    if (fOrigBitmap.hasMipMap()) {
311        int shift = fOrigBitmap.extractMipLevel(&fMipBitmap,
312                                                SkScalarToFixed(m->getScaleX()),
313                                                SkScalarToFixed(m->getSkewY()));
314
315        if (shift > 0) {
316            if (m != &fUnitInvMatrix) {
317                fUnitInvMatrix = *m;
318                m = &fUnitInvMatrix;
319            }
320
321            SkScalar scale = SkFixedToScalar(SK_Fixed1 >> shift);
322            fUnitInvMatrix.postScale(scale, scale);
323
324            // now point here instead of fOrigBitmap
325            fBitmap = &fMipBitmap;
326        }
327    }
328#endif
329
330    fInvMatrix      = m;
331    fInvProc        = m->getMapXYProc();
332    fInvType        = m->getType();
333    fInvSx          = SkScalarToFixed(m->getScaleX());
334    fInvSy          = SkScalarToFixed(m->getScaleY());
335    fInvKy          = SkScalarToFixed(m->getSkewY());
336
337    fAlphaScale = SkAlpha255To256(paint.getAlpha());
338
339    // pick-up filtering from the paint, but only if the matrix is
340    // more complex than identity/translate (i.e. no need to pay the cost
341    // of filtering if we're not scaled etc.).
342    // note: we explicitly check inv, since m might be scaled due to unitinv
343    //       trickery, but we don't want to see that for this test
344    fDoFilter = paint.isFilterBitmap() &&
345                (inv.getType() > SkMatrix::kTranslate_Mask &&
346                 valid_for_filtering(fBitmap->width() | fBitmap->height()));
347
348    fMatrixProc = this->chooseMatrixProc();
349    if (NULL == fMatrixProc) {
350        return false;
351    }
352
353    ///////////////////////////////////////////////////////////////////////
354
355    int index = 0;
356    if (fAlphaScale < 256) {  // note: this distinction is not used for D16
357        index |= 1;
358    }
359    if (fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) {
360        index |= 2;
361    }
362    if (fDoFilter) {
363        index |= 4;
364    }
365    // bits 3,4,5 encoding the source bitmap format
366    switch (fBitmap->config()) {
367        case SkBitmap::kARGB_8888_Config:
368            index |= 0;
369            break;
370        case SkBitmap::kRGB_565_Config:
371            index |= 8;
372            break;
373        case SkBitmap::kIndex8_Config:
374            index |= 16;
375            break;
376        case SkBitmap::kARGB_4444_Config:
377            index |= 24;
378            break;
379        case SkBitmap::kA8_Config:
380            index |= 32;
381            fPaintPMColor = SkPreMultiplyColor(paint.getColor());
382            break;
383        default:
384            return false;
385    }
386
387    static const SampleProc32 gSample32[] = {
388        S32_opaque_D32_nofilter_DXDY,
389        S32_alpha_D32_nofilter_DXDY,
390        S32_opaque_D32_nofilter_DX,
391        S32_alpha_D32_nofilter_DX,
392        S32_opaque_D32_filter_DXDY,
393        S32_alpha_D32_filter_DXDY,
394        S32_opaque_D32_filter_DX,
395        S32_alpha_D32_filter_DX,
396
397        S16_opaque_D32_nofilter_DXDY,
398        S16_alpha_D32_nofilter_DXDY,
399        S16_opaque_D32_nofilter_DX,
400        S16_alpha_D32_nofilter_DX,
401        S16_opaque_D32_filter_DXDY,
402        S16_alpha_D32_filter_DXDY,
403        S16_opaque_D32_filter_DX,
404        S16_alpha_D32_filter_DX,
405
406        SI8_opaque_D32_nofilter_DXDY,
407        SI8_alpha_D32_nofilter_DXDY,
408        SI8_opaque_D32_nofilter_DX,
409        SI8_alpha_D32_nofilter_DX,
410        SI8_opaque_D32_filter_DXDY,
411        SI8_alpha_D32_filter_DXDY,
412        SI8_opaque_D32_filter_DX,
413        SI8_alpha_D32_filter_DX,
414
415        S4444_opaque_D32_nofilter_DXDY,
416        S4444_alpha_D32_nofilter_DXDY,
417        S4444_opaque_D32_nofilter_DX,
418        S4444_alpha_D32_nofilter_DX,
419        S4444_opaque_D32_filter_DXDY,
420        S4444_alpha_D32_filter_DXDY,
421        S4444_opaque_D32_filter_DX,
422        S4444_alpha_D32_filter_DX,
423
424        // A8 treats alpha/opauqe the same (equally efficient)
425        SA8_alpha_D32_nofilter_DXDY,
426        SA8_alpha_D32_nofilter_DXDY,
427        SA8_alpha_D32_nofilter_DX,
428        SA8_alpha_D32_nofilter_DX,
429        SA8_alpha_D32_filter_DXDY,
430        SA8_alpha_D32_filter_DXDY,
431        SA8_alpha_D32_filter_DX,
432        SA8_alpha_D32_filter_DX
433    };
434
435    static const SampleProc16 gSample16[] = {
436        S32_D16_nofilter_DXDY,
437        S32_D16_nofilter_DX,
438        S32_D16_filter_DXDY,
439        S32_D16_filter_DX,
440
441        S16_D16_nofilter_DXDY,
442        S16_D16_nofilter_DX,
443        S16_D16_filter_DXDY,
444        S16_D16_filter_DX,
445
446        SI8_D16_nofilter_DXDY,
447        SI8_D16_nofilter_DX,
448        SI8_D16_filter_DXDY,
449        SI8_D16_filter_DX,
450
451        // Don't support 4444 -> 565
452        NULL, NULL, NULL, NULL,
453        // Don't support A8 -> 565
454        NULL, NULL, NULL, NULL
455    };
456
457    fSampleProc32 = gSample32[index];
458    index >>= 1;    // shift away any opaque/alpha distinction
459    fSampleProc16 = gSample16[index];
460
461    return true;
462}
463
464