180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru/*
380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * Copyright 2011 Google Inc.
480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru *
580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * Use of this source code is governed by a BSD-style license that can be
680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * found in the LICENSE file.
780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru */
880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "SkPackBits.h"
980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
1080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#define GATHER_STATSx
1180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
1280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustatic inline void small_memcpy(void* SK_RESTRICT dst,
1380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                                const void* SK_RESTRICT src, int n) {
1480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkASSERT(n > 0 && n <= 15);
1580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    uint8_t* d = (uint8_t*)dst;
1680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    const uint8_t* s = (const uint8_t*)src;
1780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    switch (n) {
1880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        case 15: *d++ = *s++;
1980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        case 14: *d++ = *s++;
2080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        case 13: *d++ = *s++;
2180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        case 12: *d++ = *s++;
2280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        case 11: *d++ = *s++;
2380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        case 10: *d++ = *s++;
2480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        case  9: *d++ = *s++;
2580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        case  8: *d++ = *s++;
2680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        case  7: *d++ = *s++;
2780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        case  6: *d++ = *s++;
2880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        case  5: *d++ = *s++;
2980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        case  4: *d++ = *s++;
3080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        case  3: *d++ = *s++;
3180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        case  2: *d++ = *s++;
3280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        case  1: *d++ = *s++;
3380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        case  0: break;
3480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
3580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
3680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
3780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustatic inline void small_memset(void* dst, uint8_t value, int n) {
3880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkASSERT(n > 0 && n <= 15);
3980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    uint8_t* d = (uint8_t*)dst;
4080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    switch (n) {
4180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        case 15: *d++ = value;
4280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        case 14: *d++ = value;
4380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        case 13: *d++ = value;
4480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        case 12: *d++ = value;
4580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        case 11: *d++ = value;
4680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        case 10: *d++ = value;
4780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        case  9: *d++ = value;
4880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        case  8: *d++ = value;
4980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        case  7: *d++ = value;
5080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        case  6: *d++ = value;
5180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        case  5: *d++ = value;
5280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        case  4: *d++ = value;
5380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        case  3: *d++ = value;
5480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        case  2: *d++ = value;
5580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        case  1: *d++ = value;
5680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        case  0: break;
5780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
5880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
5980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
6080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru// can we do better for small counts with our own inlined memcpy/memset?
6180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
6280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#define PB_MEMSET(addr, value, count)       \
6380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querudo {                                        \
6480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruif ((count) > 15) {                     \
6580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querumemset(addr, value, count);         \
6680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} else {                                \
6780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querusmall_memset(addr, value, count);   \
6880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}                                       \
6980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} while (0)
7080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
7180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#define PB_MEMCPY(dst, src, count)      \
7280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querudo {                                    \
7380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if ((count) > 15) {                 \
7480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        memcpy(dst, src, count);        \
7580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    } else {                            \
7680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        small_memcpy(dst, src, count);  \
7780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }                                   \
7880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} while (0)
7980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
8080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru///////////////////////////////////////////////////////////////////////////////
8180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
8280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#ifdef GATHER_STATS
8380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    static int gMemSetBuckets[129];
8480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    static int gMemCpyBuckets[129];
8580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    static int gCounter;
8680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
8780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustatic void register_memset_count(int n) {
8880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkASSERT((unsigned)n <= 128);
8980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    gMemSetBuckets[n] += 1;
9080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    gCounter += 1;
9180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
9280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if ((gCounter & 0xFF) == 0) {
9380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        SkDebugf("----- packbits memset stats: ");
9480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        for (size_t i = 0; i < SK_ARRAY_COUNT(gMemSetBuckets); i++) {
9580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            if (gMemSetBuckets[i]) {
9680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                SkDebugf(" %d:%d", i, gMemSetBuckets[i]);
9780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            }
9880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        }
9980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
10080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
10180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustatic void register_memcpy_count(int n) {
10280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkASSERT((unsigned)n <= 128);
10380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    gMemCpyBuckets[n] += 1;
10480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    gCounter += 1;
10580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
10680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if ((gCounter & 0x1FF) == 0) {
10780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        SkDebugf("----- packbits memcpy stats: ");
10880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        for (size_t i = 0; i < SK_ARRAY_COUNT(gMemCpyBuckets); i++) {
10980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            if (gMemCpyBuckets[i]) {
11080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                SkDebugf(" %d:%d", i, gMemCpyBuckets[i]);
11180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            }
11280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        }
11380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
11480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
11580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#else
11680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#define register_memset_count(n)
11780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#define register_memcpy_count(n)
11880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#endif
11980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
12080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
12180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru///////////////////////////////////////////////////////////////////////////////
12280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
12380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querusize_t SkPackBits::ComputeMaxSize16(int count) {
12480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    // worst case is the number of 16bit values (times 2) +
12580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    // 1 byte per (up to) 128 entries.
12680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    return ((count + 127) >> 7) + (count << 1);
12780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
12880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
12980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querusize_t SkPackBits::ComputeMaxSize8(int count) {
13080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    // worst case is the number of 8bit values + 1 byte per (up to) 128 entries.
13180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    return ((count + 127) >> 7) + count;
13280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
13380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
13480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustatic uint8_t* flush_same16(uint8_t dst[], uint16_t value, int count) {
13580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    while (count > 0) {
13680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        int n = count;
13780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        if (n > 128) {
13880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            n = 128;
13980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        }
14080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        *dst++ = (uint8_t)(n - 1);
14180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        *dst++ = (uint8_t)(value >> 8);
14280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        *dst++ = (uint8_t)value;
14380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        count -= n;
14480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
14580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    return dst;
14680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
14780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
14880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustatic uint8_t* flush_same8(uint8_t dst[], uint8_t value, int count) {
14980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    while (count > 0) {
15080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        int n = count;
15180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        if (n > 128) {
15280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            n = 128;
15380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        }
15480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        *dst++ = (uint8_t)(n - 1);
15580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        *dst++ = (uint8_t)value;
15680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        count -= n;
15780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
15880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    return dst;
15980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
16080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
16180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustatic uint8_t* flush_diff16(uint8_t* SK_RESTRICT dst,
16280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                             const uint16_t* SK_RESTRICT src, int count) {
16380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    while (count > 0) {
16480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        int n = count;
16580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        if (n > 128) {
16680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            n = 128;
16780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        }
16880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        *dst++ = (uint8_t)(n + 127);
16980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        PB_MEMCPY(dst, src, n * sizeof(uint16_t));
17080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        src += n;
17180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        dst += n * sizeof(uint16_t);
17280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        count -= n;
17380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
17480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    return dst;
17580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
17680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
17780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustatic uint8_t* flush_diff8(uint8_t* SK_RESTRICT dst,
17880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                            const uint8_t* SK_RESTRICT src, int count) {
17980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    while (count > 0) {
18080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        int n = count;
18180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        if (n > 128) {
18280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            n = 128;
18380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        }
18480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        *dst++ = (uint8_t)(n + 127);
18580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        PB_MEMCPY(dst, src, n);
18680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        src += n;
18780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        dst += n;
18880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        count -= n;
18980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
19080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    return dst;
19180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
19280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
19380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querusize_t SkPackBits::Pack16(const uint16_t* SK_RESTRICT src, int count,
19480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                          uint8_t* SK_RESTRICT dst) {
19580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    uint8_t* origDst = dst;
19680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    const uint16_t* stop = src + count;
19780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
19880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    for (;;) {
19980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        count = stop - src;
20080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        SkASSERT(count >= 0);
20180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        if (count == 0) {
20280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            return dst - origDst;
20380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        }
20480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        if (1 == count) {
20580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            *dst++ = 0;
20680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            *dst++ = (uint8_t)(*src >> 8);
20780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            *dst++ = (uint8_t)*src;
20880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            return dst - origDst;
20980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        }
21080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
21180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        unsigned value = *src;
21280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        const uint16_t* s = src + 1;
21380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
21480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        if (*s == value) { // accumulate same values...
21580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            do {
21680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                s++;
21780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                if (s == stop) {
21880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                    break;
21980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                }
22080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            } while (*s == value);
22180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            dst = flush_same16(dst, value, s - src);
22280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        } else {    // accumulate diff values...
22380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            do {
22480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                if (++s == stop) {
22580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                    goto FLUSH_DIFF;
22680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                }
22780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            } while (*s != s[-1]);
22880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            s -= 1; // back up so we don't grab one of the "same" values that follow
22980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        FLUSH_DIFF:
23080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            dst = flush_diff16(dst, src, s - src);
23180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        }
23280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        src = s;
23380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
23480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
23580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
23680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querusize_t SkPackBits::Pack8(const uint8_t* SK_RESTRICT src, int count,
23780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                         uint8_t* SK_RESTRICT dst) {
23880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    uint8_t* origDst = dst;
23980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    const uint8_t* stop = src + count;
24080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
24180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    for (;;) {
24280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        count = stop - src;
24380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        SkASSERT(count >= 0);
24480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        if (count == 0) {
24580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            return dst - origDst;
24680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        }
24780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        if (1 == count) {
24880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            *dst++ = 0;
24980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            *dst++ = *src;
25080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            return dst - origDst;
25180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        }
25280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
25380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        unsigned value = *src;
25480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        const uint8_t* s = src + 1;
25580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
25680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        if (*s == value) { // accumulate same values...
25780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            do {
25880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                s++;
25980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                if (s == stop) {
26080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                    break;
26180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                }
26280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            } while (*s == value);
26380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            dst = flush_same8(dst, value, s - src);
26480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        } else {    // accumulate diff values...
26580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            do {
26680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                if (++s == stop) {
26780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                    goto FLUSH_DIFF;
26880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                }
26980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                // only stop if we hit 3 in a row,
27080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                // otherwise we get bigger than compuatemax
27180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            } while (*s != s[-1] || s[-1] != s[-2]);
27280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            s -= 2; // back up so we don't grab the "same" values that follow
27380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        FLUSH_DIFF:
27480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            dst = flush_diff8(dst, src, s - src);
27580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        }
27680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        src = s;
27780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
27880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
27980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
28080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "SkUtils.h"
28180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
28280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruint SkPackBits::Unpack16(const uint8_t* SK_RESTRICT src, size_t srcSize,
28380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                         uint16_t* SK_RESTRICT dst) {
28480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    uint16_t* origDst = dst;
28580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    const uint8_t* stop = src + srcSize;
28680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
28780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    while (src < stop) {
28880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        unsigned n = *src++;
28980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        if (n <= 127) {   // repeat count (n + 1)
29080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            n += 1;
29180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            sk_memset16(dst, (src[0] << 8) | src[1], n);
29280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            src += 2;
29380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        } else {    // same count (n - 127)
29480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            n -= 127;
29580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            PB_MEMCPY(dst, src, n * sizeof(uint16_t));
29680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            src += n * sizeof(uint16_t);
29780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        }
29880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        dst += n;
29980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
30080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkASSERT(src == stop);
30180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    return dst - origDst;
30280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
30380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
30480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruint SkPackBits::Unpack8(const uint8_t* SK_RESTRICT src, size_t srcSize,
30580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                        uint8_t* SK_RESTRICT dst) {
30680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    uint8_t* origDst = dst;
30780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    const uint8_t* stop = src + srcSize;
30880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
30980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    while (src < stop) {
31080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        unsigned n = *src++;
31180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        if (n <= 127) {   // repeat count (n + 1)
31280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            n += 1;
31380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            PB_MEMSET(dst, *src++, n);
31480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        } else {    // same count (n - 127)
31580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            n -= 127;
31680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            PB_MEMCPY(dst, src, n);
31780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            src += n;
31880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        }
31980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        dst += n;
32080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
32180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkASSERT(src == stop);
32280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    return dst - origDst;
32380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
32480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
32580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruenum UnpackState {
32680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    CLEAN_STATE,
32780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    REPEAT_BYTE_STATE,
32880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    COPY_SRC_STATE
32980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru};
33080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
33180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid SkPackBits::Unpack8(uint8_t* SK_RESTRICT dst, size_t dstSkip,
33280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                         size_t dstWrite, const uint8_t* SK_RESTRICT src) {
33380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (dstWrite == 0) {
33480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        return;
33580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
33680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
33780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    UnpackState state = CLEAN_STATE;
33880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    size_t      stateCount = 0;
33980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
34080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    // state 1: do the skip-loop
34180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    while (dstSkip > 0) {
34280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        unsigned n = *src++;
34380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        if (n <= 127) {   // repeat count (n + 1)
34480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            n += 1;
34580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            if (n > dstSkip) {
34680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                state = REPEAT_BYTE_STATE;
34780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                stateCount = n - dstSkip;
34880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                n = dstSkip;
34980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                // we don't increment src here, since its needed in stage 2
35080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            } else {
35180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                src++;  // skip the src byte
35280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            }
35380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        } else {    // same count (n - 127)
35480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            n -= 127;
35580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            if (n > dstSkip) {
35680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                state = COPY_SRC_STATE;
35780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                stateCount = n - dstSkip;
35880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                n = dstSkip;
35980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            }
36080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            src += n;
36180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        }
36280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        dstSkip -= n;
36380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
36480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
36580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    // stage 2: perform any catchup from the skip-stage
36680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (stateCount > dstWrite) {
36780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        stateCount = dstWrite;
36880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
36980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    switch (state) {
37080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        case REPEAT_BYTE_STATE:
37180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            SkASSERT(stateCount > 0);
37280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            register_memset_count(stateCount);
37380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            PB_MEMSET(dst, *src++, stateCount);
37480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            break;
37580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        case COPY_SRC_STATE:
37680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            SkASSERT(stateCount > 0);
37780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            register_memcpy_count(stateCount);
37880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            PB_MEMCPY(dst, src, stateCount);
37980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            src += stateCount;
38080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            break;
38180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        default:
38280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            SkASSERT(stateCount == 0);
38380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            break;
38480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
38580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    dst += stateCount;
38680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    dstWrite -= stateCount;
38780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
38880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    // copy at most dstWrite bytes into dst[]
38980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    while (dstWrite > 0) {
39080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        unsigned n = *src++;
39180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        if (n <= 127) {   // repeat count (n + 1)
39280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            n += 1;
39380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            if (n > dstWrite) {
39480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                n = dstWrite;
39580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            }
39680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            register_memset_count(n);
39780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            PB_MEMSET(dst, *src++, n);
39880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        } else {    // same count (n - 127)
39980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            n -= 127;
40080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            if (n > dstWrite) {
40180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                n = dstWrite;
40280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            }
40380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            register_memcpy_count(n);
40480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            PB_MEMCPY(dst, src, n);
40580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            src += n;
40680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        }
40780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        dst += n;
40880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        dstWrite -= n;
40980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
41080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkASSERT(0 == dstWrite);
41180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
412