11cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
21cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger/*
31cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger * Copyright 2011 Google Inc.
41cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger *
51cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger * Use of this source code is governed by a BSD-style license that can be
61cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger * found in the LICENSE file.
71cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger */
80910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkPackBits.h"
90910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#define GATHER_STATSx
110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic inline void small_memcpy(void* SK_RESTRICT dst,
130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                                const void* SK_RESTRICT src, int n) {
140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(n > 0 && n <= 15);
150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    uint8_t* d = (uint8_t*)dst;
160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    const uint8_t* s = (const uint8_t*)src;
170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    switch (n) {
180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        case 15: *d++ = *s++;
190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        case 14: *d++ = *s++;
200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        case 13: *d++ = *s++;
210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        case 12: *d++ = *s++;
220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        case 11: *d++ = *s++;
230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        case 10: *d++ = *s++;
240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        case  9: *d++ = *s++;
250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        case  8: *d++ = *s++;
260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        case  7: *d++ = *s++;
270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        case  6: *d++ = *s++;
280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        case  5: *d++ = *s++;
290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        case  4: *d++ = *s++;
300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        case  3: *d++ = *s++;
310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        case  2: *d++ = *s++;
320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        case  1: *d++ = *s++;
330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        case  0: break;
340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic inline void small_memset(void* dst, uint8_t value, int n) {
380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(n > 0 && n <= 15);
390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    uint8_t* d = (uint8_t*)dst;
400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    switch (n) {
410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        case 15: *d++ = value;
420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        case 14: *d++ = value;
430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        case 13: *d++ = value;
440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        case 12: *d++ = value;
450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        case 11: *d++ = value;
460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        case 10: *d++ = value;
470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        case  9: *d++ = value;
480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        case  8: *d++ = value;
490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        case  7: *d++ = value;
500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        case  6: *d++ = value;
510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        case  5: *d++ = value;
520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        case  4: *d++ = value;
530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        case  3: *d++ = value;
540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        case  2: *d++ = value;
550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        case  1: *d++ = value;
560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        case  0: break;
570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project// can we do better for small counts with our own inlined memcpy/memset?
610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#define PB_MEMSET(addr, value, count)       \
630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectdo {                                        \
640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectif ((count) > 15) {                     \
650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectmemset(addr, value, count);         \
660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project} else {                                \
670910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectsmall_memset(addr, value, count);   \
680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}                                       \
690910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project} while (0)
700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#define PB_MEMCPY(dst, src, count)      \
720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectdo {                                    \
730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if ((count) > 15) {                 \
740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        memcpy(dst, src, count);        \
750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    } else {                            \
760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        small_memcpy(dst, src, count);  \
770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }                                   \
780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project} while (0)
790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project///////////////////////////////////////////////////////////////////////////////
810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#ifdef GATHER_STATS
830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    static int gMemSetBuckets[129];
840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    static int gMemCpyBuckets[129];
850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    static int gCounter;
860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic void register_memset_count(int n) {
880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT((unsigned)n <= 128);
890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    gMemSetBuckets[n] += 1;
900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    gCounter += 1;
910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if ((gCounter & 0xFF) == 0) {
930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkDebugf("----- packbits memset stats: ");
940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        for (size_t i = 0; i < SK_ARRAY_COUNT(gMemSetBuckets); i++) {
950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            if (gMemSetBuckets[i]) {
960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                SkDebugf(" %d:%d", i, gMemSetBuckets[i]);
970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            }
980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
1000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
1010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic void register_memcpy_count(int n) {
1020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT((unsigned)n <= 128);
1030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    gMemCpyBuckets[n] += 1;
1040910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    gCounter += 1;
1050910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if ((gCounter & 0x1FF) == 0) {
1070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkDebugf("----- packbits memcpy stats: ");
1080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        for (size_t i = 0; i < SK_ARRAY_COUNT(gMemCpyBuckets); i++) {
1090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            if (gMemCpyBuckets[i]) {
1100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                SkDebugf(" %d:%d", i, gMemCpyBuckets[i]);
1110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            }
1120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
1130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
1140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
1150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#else
1160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#define register_memset_count(n)
1170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#define register_memcpy_count(n)
1180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#endif
1190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project///////////////////////////////////////////////////////////////////////////////
1220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectsize_t SkPackBits::ComputeMaxSize16(int count) {
1240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    // worst case is the number of 16bit values (times 2) +
1250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    // 1 byte per (up to) 128 entries.
1260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return ((count + 127) >> 7) + (count << 1);
1270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
1280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectsize_t SkPackBits::ComputeMaxSize8(int count) {
1300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    // worst case is the number of 8bit values + 1 byte per (up to) 128 entries.
1310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return ((count + 127) >> 7) + count;
1320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
1330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic uint8_t* flush_same16(uint8_t dst[], uint16_t value, int count) {
1350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    while (count > 0) {
1360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        int n = count;
1370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        if (n > 128) {
1380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            n = 128;
1390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
1400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        *dst++ = (uint8_t)(n - 1);
1410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        *dst++ = (uint8_t)(value >> 8);
1420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        *dst++ = (uint8_t)value;
1430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        count -= n;
1440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
1450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return dst;
1460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
1470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic uint8_t* flush_same8(uint8_t dst[], uint8_t value, int count) {
1490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    while (count > 0) {
1500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        int n = count;
1510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        if (n > 128) {
1520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            n = 128;
1530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
1540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        *dst++ = (uint8_t)(n - 1);
1550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        *dst++ = (uint8_t)value;
1560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        count -= n;
1570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
1580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return dst;
1590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
1600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1611cab2921ab279367f8206cdadc9259d12e603548Derek Sollenbergerstatic uint8_t* flush_diff16(uint8_t* SK_RESTRICT dst,
1621cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                             const uint16_t* SK_RESTRICT src, int count) {
1630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    while (count > 0) {
1640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        int n = count;
1650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        if (n > 128) {
1660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            n = 128;
1670910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
1680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        *dst++ = (uint8_t)(n + 127);
1690910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        PB_MEMCPY(dst, src, n * sizeof(uint16_t));
1700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        src += n;
1710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        dst += n * sizeof(uint16_t);
1720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        count -= n;
1730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
1740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return dst;
1750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
1760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1771cab2921ab279367f8206cdadc9259d12e603548Derek Sollenbergerstatic uint8_t* flush_diff8(uint8_t* SK_RESTRICT dst,
1781cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                            const uint8_t* SK_RESTRICT src, int count) {
1790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    while (count > 0) {
1800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        int n = count;
1810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        if (n > 128) {
1820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            n = 128;
1830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
1840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        *dst++ = (uint8_t)(n + 127);
1850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        PB_MEMCPY(dst, src, n);
1860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        src += n;
1870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        dst += n;
1880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        count -= n;
1890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
1900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return dst;
1910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
1920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1931cab2921ab279367f8206cdadc9259d12e603548Derek Sollenbergersize_t SkPackBits::Pack16(const uint16_t* SK_RESTRICT src, int count,
1941cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                          uint8_t* SK_RESTRICT dst) {
1950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    uint8_t* origDst = dst;
1960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    const uint16_t* stop = src + count;
1970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    for (;;) {
1990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        count = stop - src;
2000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkASSERT(count >= 0);
2010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        if (count == 0) {
2020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            return dst - origDst;
2030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
2040910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        if (1 == count) {
2050910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            *dst++ = 0;
2060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            *dst++ = (uint8_t)(*src >> 8);
2070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            *dst++ = (uint8_t)*src;
2080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            return dst - origDst;
2090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
2100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        unsigned value = *src;
2120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        const uint16_t* s = src + 1;
2130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        if (*s == value) { // accumulate same values...
2150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            do {
2160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                s++;
2170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                if (s == stop) {
2180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    break;
2190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                }
2200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            } while (*s == value);
2210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            dst = flush_same16(dst, value, s - src);
2220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        } else {    // accumulate diff values...
2230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            do {
2240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                if (++s == stop) {
2250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    goto FLUSH_DIFF;
2260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                }
2270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            } while (*s != s[-1]);
2280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            s -= 1; // back up so we don't grab one of the "same" values that follow
2290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        FLUSH_DIFF:
2300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            dst = flush_diff16(dst, src, s - src);
2310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
2320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        src = s;
2330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
2340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
2350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2361cab2921ab279367f8206cdadc9259d12e603548Derek Sollenbergersize_t SkPackBits::Pack8(const uint8_t* SK_RESTRICT src, int count,
2371cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                         uint8_t* SK_RESTRICT dst) {
2380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    uint8_t* origDst = dst;
2390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    const uint8_t* stop = src + count;
2400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    for (;;) {
2420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        count = stop - src;
2430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkASSERT(count >= 0);
2440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        if (count == 0) {
2450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            return dst - origDst;
2460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
2470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        if (1 == count) {
2480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            *dst++ = 0;
2490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            *dst++ = *src;
2500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            return dst - origDst;
2510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
2520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        unsigned value = *src;
2540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        const uint8_t* s = src + 1;
2550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        if (*s == value) { // accumulate same values...
2570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            do {
2580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                s++;
2590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                if (s == stop) {
2600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    break;
2610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                }
2620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            } while (*s == value);
2630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            dst = flush_same8(dst, value, s - src);
2640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        } else {    // accumulate diff values...
2650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            do {
2660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                if (++s == stop) {
2670910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    goto FLUSH_DIFF;
2680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                }
2690910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                // only stop if we hit 3 in a row,
2700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                // otherwise we get bigger than compuatemax
2710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            } while (*s != s[-1] || s[-1] != s[-2]);
2720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            s -= 2; // back up so we don't grab the "same" values that follow
2730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        FLUSH_DIFF:
2740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            dst = flush_diff8(dst, src, s - src);
2750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
2760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        src = s;
2770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
2780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
2790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkUtils.h"
2810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2821cab2921ab279367f8206cdadc9259d12e603548Derek Sollenbergerint SkPackBits::Unpack16(const uint8_t* SK_RESTRICT src, size_t srcSize,
2831cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                         uint16_t* SK_RESTRICT dst) {
2840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    uint16_t* origDst = dst;
2850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    const uint8_t* stop = src + srcSize;
2860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    while (src < stop) {
2880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        unsigned n = *src++;
2890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        if (n <= 127) {   // repeat count (n + 1)
2900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            n += 1;
2910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            sk_memset16(dst, (src[0] << 8) | src[1], n);
2920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            src += 2;
2930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        } else {    // same count (n - 127)
2940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            n -= 127;
2950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            PB_MEMCPY(dst, src, n * sizeof(uint16_t));
2960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            src += n * sizeof(uint16_t);
2970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
2980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        dst += n;
2990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
3000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(src == stop);
3010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return dst - origDst;
3020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
3030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3041cab2921ab279367f8206cdadc9259d12e603548Derek Sollenbergerint SkPackBits::Unpack8(const uint8_t* SK_RESTRICT src, size_t srcSize,
3051cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                        uint8_t* SK_RESTRICT dst) {
3060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    uint8_t* origDst = dst;
3070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    const uint8_t* stop = src + srcSize;
3080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    while (src < stop) {
3100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        unsigned n = *src++;
3110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        if (n <= 127) {   // repeat count (n + 1)
3120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            n += 1;
3130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            PB_MEMSET(dst, *src++, n);
3140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        } else {    // same count (n - 127)
3150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            n -= 127;
3160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            PB_MEMCPY(dst, src, n);
3170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            src += n;
3180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
3190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        dst += n;
3200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
3210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(src == stop);
3220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return dst - origDst;
3230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
3240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectenum UnpackState {
3260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    CLEAN_STATE,
3270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    REPEAT_BYTE_STATE,
3280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    COPY_SRC_STATE
3290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project};
3300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3311cab2921ab279367f8206cdadc9259d12e603548Derek Sollenbergervoid SkPackBits::Unpack8(uint8_t* SK_RESTRICT dst, size_t dstSkip,
3321cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                         size_t dstWrite, const uint8_t* SK_RESTRICT src) {
3330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (dstWrite == 0) {
3340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return;
3350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
3360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    UnpackState state = CLEAN_STATE;
3380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    size_t      stateCount = 0;
3390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    // state 1: do the skip-loop
3410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    while (dstSkip > 0) {
3420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        unsigned n = *src++;
3430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        if (n <= 127) {   // repeat count (n + 1)
3440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            n += 1;
3450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            if (n > dstSkip) {
3460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                state = REPEAT_BYTE_STATE;
3470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                stateCount = n - dstSkip;
3480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                n = dstSkip;
3490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                // we don't increment src here, since its needed in stage 2
3500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            } else {
3510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                src++;  // skip the src byte
3520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            }
3530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        } else {    // same count (n - 127)
3540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            n -= 127;
3550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            if (n > dstSkip) {
3560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                state = COPY_SRC_STATE;
3570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                stateCount = n - dstSkip;
3580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                n = dstSkip;
3590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            }
3600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            src += n;
3610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
3620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        dstSkip -= n;
3630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
3640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    // stage 2: perform any catchup from the skip-stage
3660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (stateCount > dstWrite) {
3670910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        stateCount = dstWrite;
3680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
3690910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    switch (state) {
3700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        case REPEAT_BYTE_STATE:
3710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkASSERT(stateCount > 0);
3720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            register_memset_count(stateCount);
3730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            PB_MEMSET(dst, *src++, stateCount);
3740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            break;
3750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        case COPY_SRC_STATE:
3760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkASSERT(stateCount > 0);
3770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            register_memcpy_count(stateCount);
3780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            PB_MEMCPY(dst, src, stateCount);
3790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            src += stateCount;
3800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            break;
3810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        default:
3820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkASSERT(stateCount == 0);
3830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            break;
3840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
3850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    dst += stateCount;
3860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    dstWrite -= stateCount;
3870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    // copy at most dstWrite bytes into dst[]
3890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    while (dstWrite > 0) {
3900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        unsigned n = *src++;
3910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        if (n <= 127) {   // repeat count (n + 1)
3920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            n += 1;
3930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            if (n > dstWrite) {
3940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                n = dstWrite;
3950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            }
3960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            register_memset_count(n);
3970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            PB_MEMSET(dst, *src++, n);
3980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        } else {    // same count (n - 127)
3990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            n -= 127;
4000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            if (n > dstWrite) {
4010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                n = dstWrite;
4020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            }
4030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            register_memcpy_count(n);
4040910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            PB_MEMCPY(dst, src, n);
4050910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            src += n;
4060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
4070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        dst += n;
4080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        dstWrite -= n;
4090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
4100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(0 == dstWrite);
4110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
412