SkSwizzler.cpp revision 9552662e9fee5eb0ef435e52ab9db505d7ebe4ad
1/*
2 * Copyright 2015 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "SkCodecPriv.h"
9#include "SkColorPriv.h"
10#include "SkSwizzler.h"
11#include "SkTemplates.h"
12
13SkSwizzler::ResultAlpha SkSwizzler::GetResult(uint8_t zeroAlpha,
14                                              uint8_t maxAlpha) {
15    // In the transparent case, this returns 0x0000
16    // In the opaque case, this returns 0xFFFF
17    // If the row is neither transparent nor opaque, returns something else
18    return (((uint16_t) maxAlpha) << 8) | zeroAlpha;
19}
20
21// kIndex1, kIndex2, kIndex4
22
23static SkSwizzler::ResultAlpha swizzle_small_index_to_n32(
24        void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int width,
25        int bitsPerPixel, int y, const SkPMColor ctable[]) {
26
27    SkPMColor* SK_RESTRICT dst = (SkPMColor*) dstRow;
28    INIT_RESULT_ALPHA;
29    const uint32_t pixelsPerByte = 8 / bitsPerPixel;
30    const size_t rowBytes = compute_row_bytes_ppb(width, pixelsPerByte);
31    const uint8_t mask = (1 << bitsPerPixel) - 1;
32    int x = 0;
33    for (uint32_t byte = 0; byte < rowBytes; byte++) {
34        uint8_t pixelData = src[byte];
35        for (uint32_t p = 0; p < pixelsPerByte && x < width; p++) {
36            uint8_t index = (pixelData >> (8 - bitsPerPixel)) & mask;
37            SkPMColor c = ctable[index];
38            UPDATE_RESULT_ALPHA(c >> SK_A32_SHIFT);
39            dst[x] = c;
40            pixelData <<= bitsPerPixel;
41            x++;
42        }
43    }
44    return COMPUTE_RESULT_ALPHA;
45}
46
47// kIndex
48
49static SkSwizzler::ResultAlpha swizzle_index_to_n32(
50        void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int width,
51        int bytesPerPixel, int y, const SkPMColor ctable[]) {
52
53    SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow;
54    INIT_RESULT_ALPHA;
55    for (int x = 0; x < width; x++) {
56        SkPMColor c = ctable[*src];
57        UPDATE_RESULT_ALPHA(c >> SK_A32_SHIFT);
58        dst[x] = c;
59        src++;
60    }
61    return COMPUTE_RESULT_ALPHA;
62}
63
64static SkSwizzler::ResultAlpha swizzle_index_to_n32_skipZ(
65        void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int width,
66        int bytesPerPixel, int y, const SkPMColor ctable[]) {
67
68    SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow;
69    INIT_RESULT_ALPHA;
70    for (int x = 0; x < width; x++) {
71        SkPMColor c = ctable[*src];
72        UPDATE_RESULT_ALPHA(c >> SK_A32_SHIFT);
73        if (c != 0) {
74            dst[x] = c;
75        }
76        src++;
77    }
78    return COMPUTE_RESULT_ALPHA;
79}
80
81#undef A32_MASK_IN_PLACE
82
83static SkSwizzler::ResultAlpha swizzle_bgrx_to_n32(
84        void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int width,
85        int bytesPerPixel, int y, const SkPMColor ctable[]) {
86
87    SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow;
88    for (int x = 0; x < width; x++) {
89        dst[x] = SkPackARGB32NoCheck(0xFF, src[2], src[1], src[0]);
90        src += bytesPerPixel;
91    }
92    return SkSwizzler::kOpaque_ResultAlpha;
93}
94
95// kBGRA
96
97static SkSwizzler::ResultAlpha swizzle_bgra_to_n32(
98        void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int width,
99        int bytesPerPixel, int y, const SkPMColor ctable[]) {
100
101    SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow;
102    INIT_RESULT_ALPHA;
103    for (int x = 0; x < width; x++) {
104        uint8_t alpha = src[3];
105        UPDATE_RESULT_ALPHA(alpha);
106        dst[x] = SkPackARGB32NoCheck(alpha, src[2], src[1], src[0]);
107        src += bytesPerPixel;
108    }
109    return COMPUTE_RESULT_ALPHA;
110}
111
112// n32
113static SkSwizzler::ResultAlpha swizzle_rgbx_to_n32(
114        void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int width,
115        int bytesPerPixel, int y, const SkPMColor ctable[]) {
116
117    SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow;
118    for (int x = 0; x < width; x++) {
119        dst[x] = SkPackARGB32(0xFF, src[0], src[1], src[2]);
120        src += bytesPerPixel;
121    }
122    return SkSwizzler::kOpaque_ResultAlpha;
123}
124
125static SkSwizzler::ResultAlpha swizzle_rgba_to_n32_premul(
126        void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int width,
127        int bytesPerPixel, int y, const SkPMColor ctable[]) {
128
129    SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow;
130    INIT_RESULT_ALPHA;
131    for (int x = 0; x < width; x++) {
132        unsigned alpha = src[3];
133        UPDATE_RESULT_ALPHA(alpha);
134        dst[x] = SkPreMultiplyARGB(alpha, src[0], src[1], src[2]);
135        src += bytesPerPixel;
136    }
137    return COMPUTE_RESULT_ALPHA;
138}
139
140static SkSwizzler::ResultAlpha swizzle_rgba_to_n32_unpremul(
141        void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int width,
142        int bytesPerPixel, int y, const SkPMColor ctable[]) {
143
144    uint32_t* SK_RESTRICT dst = reinterpret_cast<uint32_t*>(dstRow);
145    INIT_RESULT_ALPHA;
146    for (int x = 0; x < width; x++) {
147        unsigned alpha = src[3];
148        UPDATE_RESULT_ALPHA(alpha);
149        dst[x] = SkPackARGB32NoCheck(alpha, src[0], src[1], src[2]);
150        src += bytesPerPixel;
151    }
152    return COMPUTE_RESULT_ALPHA;
153}
154
155static SkSwizzler::ResultAlpha swizzle_rgba_to_n32_premul_skipZ(
156        void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int width,
157        int bytesPerPixel, int y, const SkPMColor ctable[]) {
158
159    SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow;
160    INIT_RESULT_ALPHA;
161    for (int x = 0; x < width; x++) {
162        unsigned alpha = src[3];
163        UPDATE_RESULT_ALPHA(alpha);
164        if (0 != alpha) {
165            dst[x] = SkPreMultiplyARGB(alpha, src[0], src[1], src[2]);
166        }
167        src += bytesPerPixel;
168    }
169    return COMPUTE_RESULT_ALPHA;
170}
171
172/**
173    FIXME: This was my idea to cheat in order to continue taking advantage of skipping zeroes.
174    This would be fine for drawing normally, but not for drawing with transfer modes. Being
175    honest means we can draw correctly with transfer modes, with the cost of not being able
176    to take advantage of Android's free unwritten pages. Something to keep in mind when we
177    decide whether to switch to unpremul default.
178static bool swizzle_rgba_to_n32_unpremul_skipZ(void* SK_RESTRICT dstRow,
179                                               const uint8_t* SK_RESTRICT src,
180                                               int width, int bitsPerPixel,
181                                               const SkPMColor[]) {
182    SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow;
183    unsigned alphaMask = 0xFF;
184    for (int x = 0; x < width; x++) {
185        unsigned alpha = src[3];
186        // NOTE: We cheat here. The caller requested unpremul and skip zeroes. It's possible
187        // the color components are not zero, but we skip them anyway, meaning they'll remain
188        // zero (implied by the request to skip zeroes).
189        if (0 != alpha) {
190            dst[x] = SkPackARGB32NoCheck(alpha, src[0], src[1], src[2]);
191        }
192        src += deltaSrc;
193        alphaMask &= alpha;
194    }
195    return alphaMask != 0xFF;
196}
197*/
198
199SkSwizzler* SkSwizzler::CreateSwizzler(SkSwizzler::SrcConfig sc,
200                                       const SkPMColor* ctable,
201                                       const SkImageInfo& info, void* dst,
202                                       size_t dstRowBytes,
203                                       SkImageGenerator::ZeroInitialized zeroInit) {
204    if (kUnknown_SkColorType == info.colorType()) {
205        return NULL;
206    }
207    if (info.minRowBytes() > dstRowBytes) {
208        return  NULL;
209    }
210    if ((kIndex == sc || kIndex4 == sc || kIndex2 == sc || kIndex1 == sc)
211            && NULL == ctable) {
212        return NULL;
213    }
214    RowProc proc = NULL;
215    switch (sc) {
216        case kIndex1:
217        case kIndex2:
218        case kIndex4:
219            switch (info.colorType()) {
220                case kN32_SkColorType:
221                    proc = &swizzle_small_index_to_n32;
222                    break;
223                default:
224                    break;
225            }
226            break;
227        case kIndex:
228            switch (info.colorType()) {
229                case kN32_SkColorType:
230                    // We assume the color premultiplied ctable (or not) as desired.
231                    if (SkImageGenerator::kYes_ZeroInitialized == zeroInit) {
232                        proc = &swizzle_index_to_n32_skipZ;
233                    } else {
234                        proc = &swizzle_index_to_n32;
235                    }
236                    break;
237                default:
238                    break;
239            }
240            break;
241        case kBGR:
242        case kBGRX:
243            switch (info.colorType()) {
244                case kN32_SkColorType:
245                    proc = &swizzle_bgrx_to_n32;
246                    break;
247                default:
248                    break;
249            }
250            break;
251        case kBGRA:
252            switch (info.colorType()) {
253                case kN32_SkColorType:
254                    proc = &swizzle_bgra_to_n32;
255                    break;
256                default:
257                    break;
258            }
259            break;
260        case kRGBX:
261            // TODO: Support other swizzles.
262            switch (info.colorType()) {
263                case kN32_SkColorType:
264                    proc = &swizzle_rgbx_to_n32;
265                    break;
266                default:
267                    break;
268            }
269            break;
270        case kRGBA:
271            switch (info.colorType()) {
272                case kN32_SkColorType:
273                    if (info.alphaType() == kUnpremul_SkAlphaType) {
274                        // Respect zeroInit?
275                        proc = &swizzle_rgba_to_n32_unpremul;
276                    } else {
277                        if (SkImageGenerator::kYes_ZeroInitialized == zeroInit) {
278                            proc = &swizzle_rgba_to_n32_premul_skipZ;
279                        } else {
280                            proc = &swizzle_rgba_to_n32_premul;
281                        }
282                    }
283                    break;
284                default:
285                    break;
286            }
287            break;
288        case kRGB:
289            switch (info.colorType()) {
290                case kN32_SkColorType:
291                    proc = &swizzle_rgbx_to_n32;
292                    break;
293                default:
294                    break;
295            }
296            break;
297        default:
298            break;
299    }
300    if (NULL == proc) {
301        return NULL;
302    }
303
304    // Store deltaSrc in bytes if it is an even multiple, otherwise use bits
305    int deltaSrc = SkIsAlign8(BitsPerPixel(sc)) ? BytesPerPixel(sc) :
306            BitsPerPixel(sc);
307    return SkNEW_ARGS(SkSwizzler, (proc, ctable, deltaSrc, info, dst,
308                                   dstRowBytes));
309}
310
311SkSwizzler::SkSwizzler(RowProc proc, const SkPMColor* ctable,
312                       int deltaSrc, const SkImageInfo& info, void* dst,
313                       size_t rowBytes)
314    : fRowProc(proc)
315    , fColorTable(ctable)
316    , fDeltaSrc(deltaSrc)
317    , fDstInfo(info)
318    , fDstRow(dst)
319    , fDstRowBytes(rowBytes)
320    , fCurrY(0)
321{
322    SkDEBUGCODE(fNextMode = kUninitialized_NextMode);
323}
324
325SkSwizzler::ResultAlpha SkSwizzler::next(const uint8_t* SK_RESTRICT src) {
326    SkASSERT(0 <= fCurrY && fCurrY < fDstInfo.height());
327    SkASSERT(kDesignateRow_NextMode != fNextMode);
328    SkDEBUGCODE(fNextMode = kConsecutive_NextMode);
329
330    // Decode a row
331    const ResultAlpha result = fRowProc(fDstRow, src, fDstInfo.width(),
332            fDeltaSrc, fCurrY, fColorTable);
333
334    // Move to the next row and return the result
335    fDstRow = SkTAddOffset<void>(fDstRow, fDstRowBytes);
336    return result;
337}
338
339SkSwizzler::ResultAlpha SkSwizzler::next(const uint8_t* SK_RESTRICT src,
340        int y) {
341    SkASSERT(0 <= y && y < fDstInfo.height());
342    SkASSERT(kConsecutive_NextMode != fNextMode);
343    SkDEBUGCODE(fNextMode = kDesignateRow_NextMode);
344
345    // Choose the row
346    void* row = SkTAddOffset<void>(fDstRow, y*fDstRowBytes);
347
348    // Decode the row
349    return fRowProc(row, src, fDstInfo.width(), fDeltaSrc, fCurrY,
350            fColorTable);
351}
352