Home | History | Annotate | Download | only in core
      1 #include "SkPackBits.h"
      2 
      3 #define GATHER_STATSx
      4 
      5 static inline void small_memcpy(void* SK_RESTRICT dst,
      6                                 const void* SK_RESTRICT src, int n) {
      7     SkASSERT(n > 0 && n <= 15);
      8     uint8_t* d = (uint8_t*)dst;
      9     const uint8_t* s = (const uint8_t*)src;
     10     switch (n) {
     11         case 15: *d++ = *s++;
     12         case 14: *d++ = *s++;
     13         case 13: *d++ = *s++;
     14         case 12: *d++ = *s++;
     15         case 11: *d++ = *s++;
     16         case 10: *d++ = *s++;
     17         case  9: *d++ = *s++;
     18         case  8: *d++ = *s++;
     19         case  7: *d++ = *s++;
     20         case  6: *d++ = *s++;
     21         case  5: *d++ = *s++;
     22         case  4: *d++ = *s++;
     23         case  3: *d++ = *s++;
     24         case  2: *d++ = *s++;
     25         case  1: *d++ = *s++;
     26         case  0: break;
     27     }
     28 }
     29 
     30 static inline void small_memset(void* dst, uint8_t value, int n) {
     31     SkASSERT(n > 0 && n <= 15);
     32     uint8_t* d = (uint8_t*)dst;
     33     switch (n) {
     34         case 15: *d++ = value;
     35         case 14: *d++ = value;
     36         case 13: *d++ = value;
     37         case 12: *d++ = value;
     38         case 11: *d++ = value;
     39         case 10: *d++ = value;
     40         case  9: *d++ = value;
     41         case  8: *d++ = value;
     42         case  7: *d++ = value;
     43         case  6: *d++ = value;
     44         case  5: *d++ = value;
     45         case  4: *d++ = value;
     46         case  3: *d++ = value;
     47         case  2: *d++ = value;
     48         case  1: *d++ = value;
     49         case  0: break;
     50     }
     51 }
     52 
     53 // can we do better for small counts with our own inlined memcpy/memset?
     54 
     55 #define PB_MEMSET(addr, value, count)       \
     56 do {                                        \
     57 if ((count) > 15) {                     \
     58 memset(addr, value, count);         \
     59 } else {                                \
     60 small_memset(addr, value, count);   \
     61 }                                       \
     62 } while (0)
     63 
     64 #define PB_MEMCPY(dst, src, count)      \
     65 do {                                    \
     66     if ((count) > 15) {                 \
     67         memcpy(dst, src, count);        \
     68     } else {                            \
     69         small_memcpy(dst, src, count);  \
     70     }                                   \
     71 } while (0)
     72 
     73 ///////////////////////////////////////////////////////////////////////////////
     74 
     75 #ifdef GATHER_STATS
     76     static int gMemSetBuckets[129];
     77     static int gMemCpyBuckets[129];
     78     static int gCounter;
     79 
     80 static void register_memset_count(int n) {
     81     SkASSERT((unsigned)n <= 128);
     82     gMemSetBuckets[n] += 1;
     83     gCounter += 1;
     84 
     85     if ((gCounter & 0xFF) == 0) {
     86         SkDebugf("----- packbits memset stats: ");
     87         for (size_t i = 0; i < SK_ARRAY_COUNT(gMemSetBuckets); i++) {
     88             if (gMemSetBuckets[i]) {
     89                 SkDebugf(" %d:%d", i, gMemSetBuckets[i]);
     90             }
     91         }
     92     }
     93 }
     94 static void register_memcpy_count(int n) {
     95     SkASSERT((unsigned)n <= 128);
     96     gMemCpyBuckets[n] += 1;
     97     gCounter += 1;
     98 
     99     if ((gCounter & 0x1FF) == 0) {
    100         SkDebugf("----- packbits memcpy stats: ");
    101         for (size_t i = 0; i < SK_ARRAY_COUNT(gMemCpyBuckets); i++) {
    102             if (gMemCpyBuckets[i]) {
    103                 SkDebugf(" %d:%d", i, gMemCpyBuckets[i]);
    104             }
    105         }
    106     }
    107 }
    108 #else
    109 #define register_memset_count(n)
    110 #define register_memcpy_count(n)
    111 #endif
    112 
    113 
    114 ///////////////////////////////////////////////////////////////////////////////
    115 
    116 size_t SkPackBits::ComputeMaxSize16(int count) {
    117     // worst case is the number of 16bit values (times 2) +
    118     // 1 byte per (up to) 128 entries.
    119     return ((count + 127) >> 7) + (count << 1);
    120 }
    121 
    122 size_t SkPackBits::ComputeMaxSize8(int count) {
    123     // worst case is the number of 8bit values + 1 byte per (up to) 128 entries.
    124     return ((count + 127) >> 7) + count;
    125 }
    126 
    127 static uint8_t* flush_same16(uint8_t dst[], uint16_t value, int count) {
    128     while (count > 0) {
    129         int n = count;
    130         if (n > 128) {
    131             n = 128;
    132         }
    133         *dst++ = (uint8_t)(n - 1);
    134         *dst++ = (uint8_t)(value >> 8);
    135         *dst++ = (uint8_t)value;
    136         count -= n;
    137     }
    138     return dst;
    139 }
    140 
    141 static uint8_t* flush_same8(uint8_t dst[], uint8_t value, int count) {
    142     while (count > 0) {
    143         int n = count;
    144         if (n > 128) {
    145             n = 128;
    146         }
    147         *dst++ = (uint8_t)(n - 1);
    148         *dst++ = (uint8_t)value;
    149         count -= n;
    150     }
    151     return dst;
    152 }
    153 
    154 static uint8_t* flush_diff16(uint8_t SK_RESTRICT dst[],
    155                              const uint16_t SK_RESTRICT src[], int count) {
    156     while (count > 0) {
    157         int n = count;
    158         if (n > 128) {
    159             n = 128;
    160         }
    161         *dst++ = (uint8_t)(n + 127);
    162         PB_MEMCPY(dst, src, n * sizeof(uint16_t));
    163         src += n;
    164         dst += n * sizeof(uint16_t);
    165         count -= n;
    166     }
    167     return dst;
    168 }
    169 
    170 static uint8_t* flush_diff8(uint8_t SK_RESTRICT dst[],
    171                             const uint8_t SK_RESTRICT src[], int count) {
    172     while (count > 0) {
    173         int n = count;
    174         if (n > 128) {
    175             n = 128;
    176         }
    177         *dst++ = (uint8_t)(n + 127);
    178         PB_MEMCPY(dst, src, n);
    179         src += n;
    180         dst += n;
    181         count -= n;
    182     }
    183     return dst;
    184 }
    185 
    186 size_t SkPackBits::Pack16(const uint16_t SK_RESTRICT src[], int count,
    187                           uint8_t SK_RESTRICT dst[]) {
    188     uint8_t* origDst = dst;
    189     const uint16_t* stop = src + count;
    190 
    191     for (;;) {
    192         count = stop - src;
    193         SkASSERT(count >= 0);
    194         if (count == 0) {
    195             return dst - origDst;
    196         }
    197         if (1 == count) {
    198             *dst++ = 0;
    199             *dst++ = (uint8_t)(*src >> 8);
    200             *dst++ = (uint8_t)*src;
    201             return dst - origDst;
    202         }
    203 
    204         unsigned value = *src;
    205         const uint16_t* s = src + 1;
    206 
    207         if (*s == value) { // accumulate same values...
    208             do {
    209                 s++;
    210                 if (s == stop) {
    211                     break;
    212                 }
    213             } while (*s == value);
    214             dst = flush_same16(dst, value, s - src);
    215         } else {    // accumulate diff values...
    216             do {
    217                 if (++s == stop) {
    218                     goto FLUSH_DIFF;
    219                 }
    220             } while (*s != s[-1]);
    221             s -= 1; // back up so we don't grab one of the "same" values that follow
    222         FLUSH_DIFF:
    223             dst = flush_diff16(dst, src, s - src);
    224         }
    225         src = s;
    226     }
    227 }
    228 
    229 size_t SkPackBits::Pack8(const uint8_t SK_RESTRICT src[], int count,
    230                          uint8_t SK_RESTRICT dst[]) {
    231     uint8_t* origDst = dst;
    232     const uint8_t* stop = src + count;
    233 
    234     for (;;) {
    235         count = stop - src;
    236         SkASSERT(count >= 0);
    237         if (count == 0) {
    238             return dst - origDst;
    239         }
    240         if (1 == count) {
    241             *dst++ = 0;
    242             *dst++ = *src;
    243             return dst - origDst;
    244         }
    245 
    246         unsigned value = *src;
    247         const uint8_t* s = src + 1;
    248 
    249         if (*s == value) { // accumulate same values...
    250             do {
    251                 s++;
    252                 if (s == stop) {
    253                     break;
    254                 }
    255             } while (*s == value);
    256             dst = flush_same8(dst, value, s - src);
    257         } else {    // accumulate diff values...
    258             do {
    259                 if (++s == stop) {
    260                     goto FLUSH_DIFF;
    261                 }
    262                 // only stop if we hit 3 in a row,
    263                 // otherwise we get bigger than compuatemax
    264             } while (*s != s[-1] || s[-1] != s[-2]);
    265             s -= 2; // back up so we don't grab the "same" values that follow
    266         FLUSH_DIFF:
    267             dst = flush_diff8(dst, src, s - src);
    268         }
    269         src = s;
    270     }
    271 }
    272 
    273 #include "SkUtils.h"
    274 
    275 int SkPackBits::Unpack16(const uint8_t SK_RESTRICT src[], size_t srcSize,
    276                          uint16_t SK_RESTRICT dst[]) {
    277     uint16_t* origDst = dst;
    278     const uint8_t* stop = src + srcSize;
    279 
    280     while (src < stop) {
    281         unsigned n = *src++;
    282         if (n <= 127) {   // repeat count (n + 1)
    283             n += 1;
    284             sk_memset16(dst, (src[0] << 8) | src[1], n);
    285             src += 2;
    286         } else {    // same count (n - 127)
    287             n -= 127;
    288             PB_MEMCPY(dst, src, n * sizeof(uint16_t));
    289             src += n * sizeof(uint16_t);
    290         }
    291         dst += n;
    292     }
    293     SkASSERT(src == stop);
    294     return dst - origDst;
    295 }
    296 
    297 int SkPackBits::Unpack8(const uint8_t SK_RESTRICT src[], size_t srcSize,
    298                         uint8_t SK_RESTRICT dst[]) {
    299     uint8_t* origDst = dst;
    300     const uint8_t* stop = src + srcSize;
    301 
    302     while (src < stop) {
    303         unsigned n = *src++;
    304         if (n <= 127) {   // repeat count (n + 1)
    305             n += 1;
    306             PB_MEMSET(dst, *src++, n);
    307         } else {    // same count (n - 127)
    308             n -= 127;
    309             PB_MEMCPY(dst, src, n);
    310             src += n;
    311         }
    312         dst += n;
    313     }
    314     SkASSERT(src == stop);
    315     return dst - origDst;
    316 }
    317 
    318 enum UnpackState {
    319     CLEAN_STATE,
    320     REPEAT_BYTE_STATE,
    321     COPY_SRC_STATE
    322 };
    323 
    324 void SkPackBits::Unpack8(uint8_t SK_RESTRICT dst[], size_t dstSkip,
    325                          size_t dstWrite, const uint8_t SK_RESTRICT src[]) {
    326     if (dstWrite == 0) {
    327         return;
    328     }
    329 
    330     UnpackState state = CLEAN_STATE;
    331     size_t      stateCount = 0;
    332 
    333     // state 1: do the skip-loop
    334     while (dstSkip > 0) {
    335         unsigned n = *src++;
    336         if (n <= 127) {   // repeat count (n + 1)
    337             n += 1;
    338             if (n > dstSkip) {
    339                 state = REPEAT_BYTE_STATE;
    340                 stateCount = n - dstSkip;
    341                 n = dstSkip;
    342                 // we don't increment src here, since its needed in stage 2
    343             } else {
    344                 src++;  // skip the src byte
    345             }
    346         } else {    // same count (n - 127)
    347             n -= 127;
    348             if (n > dstSkip) {
    349                 state = COPY_SRC_STATE;
    350                 stateCount = n - dstSkip;
    351                 n = dstSkip;
    352             }
    353             src += n;
    354         }
    355         dstSkip -= n;
    356     }
    357 
    358     // stage 2: perform any catchup from the skip-stage
    359     if (stateCount > dstWrite) {
    360         stateCount = dstWrite;
    361     }
    362     switch (state) {
    363         case REPEAT_BYTE_STATE:
    364             SkASSERT(stateCount > 0);
    365             register_memset_count(stateCount);
    366             PB_MEMSET(dst, *src++, stateCount);
    367             break;
    368         case COPY_SRC_STATE:
    369             SkASSERT(stateCount > 0);
    370             register_memcpy_count(stateCount);
    371             PB_MEMCPY(dst, src, stateCount);
    372             src += stateCount;
    373             break;
    374         default:
    375             SkASSERT(stateCount == 0);
    376             break;
    377     }
    378     dst += stateCount;
    379     dstWrite -= stateCount;
    380 
    381     // copy at most dstWrite bytes into dst[]
    382     while (dstWrite > 0) {
    383         unsigned n = *src++;
    384         if (n <= 127) {   // repeat count (n + 1)
    385             n += 1;
    386             if (n > dstWrite) {
    387                 n = dstWrite;
    388             }
    389             register_memset_count(n);
    390             PB_MEMSET(dst, *src++, n);
    391         } else {    // same count (n - 127)
    392             n -= 127;
    393             if (n > dstWrite) {
    394                 n = dstWrite;
    395             }
    396             register_memcpy_count(n);
    397             PB_MEMCPY(dst, src, n);
    398             src += n;
    399         }
    400         dst += n;
    401         dstWrite -= n;
    402     }
    403     SkASSERT(0 == dstWrite);
    404 }
    405 
    406 
    407 
    408