SkSwizzler.cpp revision 741143878b23d22cd9cb7b9cba8055179115ce17
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, bool skipZeroes) {
203    if (kUnknown_SkColorType == info.colorType()) {
204        return NULL;
205    }
206    if (info.minRowBytes() > dstRowBytes) {
207        return  NULL;
208    }
209    if ((kIndex == sc || kIndex4 == sc || kIndex2 == sc || kIndex1 == sc)
210            && NULL == ctable) {
211        return NULL;
212    }
213    RowProc proc = NULL;
214    switch (sc) {
215        case kIndex1:
216        case kIndex2:
217        case kIndex4:
218            switch (info.colorType()) {
219                case kN32_SkColorType:
220                    proc = &swizzle_small_index_to_n32;
221                    break;
222                default:
223                    break;
224            }
225            break;
226        case kIndex:
227            switch (info.colorType()) {
228                case kN32_SkColorType:
229                    if (skipZeroes) {
230                        proc = &swizzle_index_to_n32_skipZ;
231                    } else {
232                        proc = &swizzle_index_to_n32;
233                    }
234                    break;
235                default:
236                    break;
237            }
238            break;
239        case kBGR:
240        case kBGRX:
241            switch (info.colorType()) {
242                case kN32_SkColorType:
243                    proc = &swizzle_bgrx_to_n32;
244                    break;
245                default:
246                    break;
247            }
248            break;
249        case kBGRA:
250            switch (info.colorType()) {
251                case kN32_SkColorType:
252                    proc = &swizzle_bgra_to_n32;
253                    break;
254                default:
255                    break;
256            }
257            break;
258        case kRGBX:
259            // TODO: Support other swizzles.
260            switch (info.colorType()) {
261                case kN32_SkColorType:
262                    proc = &swizzle_rgbx_to_n32;
263                    break;
264                default:
265                    break;
266            }
267            break;
268        case kRGBA:
269            switch (info.colorType()) {
270                case kN32_SkColorType:
271                    if (info.alphaType() == kUnpremul_SkAlphaType) {
272                        // Respect skipZeroes?
273                        proc = &swizzle_rgba_to_n32_unpremul;
274                    } else {
275                        if (skipZeroes) {
276                            proc = &swizzle_rgba_to_n32_premul_skipZ;
277                        } else {
278                            proc = &swizzle_rgba_to_n32_premul;
279                        }
280                    }
281                    break;
282                default:
283                    break;
284            }
285            break;
286        case kRGB:
287            switch (info.colorType()) {
288                case kN32_SkColorType:
289                    proc = &swizzle_rgbx_to_n32;
290                    break;
291                default:
292                    break;
293            }
294            break;
295        default:
296            break;
297    }
298    if (NULL == proc) {
299        return NULL;
300    }
301
302    // Store deltaSrc in bytes if it is an even multiple, otherwise use bits
303    int deltaSrc = SkIsAlign8(BitsPerPixel(sc)) ? BytesPerPixel(sc) :
304            BitsPerPixel(sc);
305    return SkNEW_ARGS(SkSwizzler, (proc, ctable, deltaSrc, info, dst,
306                                   dstRowBytes));
307}
308
309SkSwizzler::SkSwizzler(RowProc proc, const SkPMColor* ctable,
310                       int deltaSrc, const SkImageInfo& info, void* dst,
311                       size_t rowBytes)
312    : fRowProc(proc)
313    , fColorTable(ctable)
314    , fDeltaSrc(deltaSrc)
315    , fDstInfo(info)
316    , fDstRow(dst)
317    , fDstRowBytes(rowBytes)
318    , fCurrY(0)
319{
320    SkDEBUGCODE(fNextMode = kUninitialized_NextMode);
321}
322
323SkSwizzler::ResultAlpha SkSwizzler::next(const uint8_t* SK_RESTRICT src) {
324    SkASSERT(0 <= fCurrY && fCurrY < fDstInfo.height());
325    SkASSERT(kDesignateRow_NextMode != fNextMode);
326    SkDEBUGCODE(fNextMode = kConsecutive_NextMode);
327
328    // Decode a row
329    const ResultAlpha result = fRowProc(fDstRow, src, fDstInfo.width(),
330            fDeltaSrc, fCurrY, fColorTable);
331
332    // Move to the next row and return the result
333    fDstRow = SkTAddOffset<void>(fDstRow, fDstRowBytes);
334    return result;
335}
336
337SkSwizzler::ResultAlpha SkSwizzler::next(const uint8_t* SK_RESTRICT src,
338        int y) {
339    SkASSERT(0 <= y && y < fDstInfo.height());
340    SkASSERT(kConsecutive_NextMode != fNextMode);
341    SkDEBUGCODE(fNextMode = kDesignateRow_NextMode);
342
343    // Choose the row
344    void* row = SkTAddOffset<void>(fDstRow, y*fDstRowBytes);
345
346    // Decode the row
347    return fRowProc(row, src, fDstInfo.width(), fDeltaSrc, fCurrY,
348            fColorTable);
349}
350