gfx/skia/trunk/src/core/SkPackBits.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/skia/trunk/src/core/SkPackBits.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,411 @@
     1.4 +
     1.5 +/*
     1.6 + * Copyright 2011 Google Inc.
     1.7 + *
     1.8 + * Use of this source code is governed by a BSD-style license that can be
     1.9 + * found in the LICENSE file.
    1.10 + */
    1.11 +#include "SkPackBits.h"
    1.12 +
    1.13 +#define GATHER_STATSx
    1.14 +
    1.15 +static inline void small_memcpy(void* SK_RESTRICT dst,
    1.16 +                                const void* SK_RESTRICT src, int n) {
    1.17 +    SkASSERT(n > 0 && n <= 15);
    1.18 +    uint8_t* d = (uint8_t*)dst;
    1.19 +    const uint8_t* s = (const uint8_t*)src;
    1.20 +    switch (n) {
    1.21 +        case 15: *d++ = *s++;
    1.22 +        case 14: *d++ = *s++;
    1.23 +        case 13: *d++ = *s++;
    1.24 +        case 12: *d++ = *s++;
    1.25 +        case 11: *d++ = *s++;
    1.26 +        case 10: *d++ = *s++;
    1.27 +        case  9: *d++ = *s++;
    1.28 +        case  8: *d++ = *s++;
    1.29 +        case  7: *d++ = *s++;
    1.30 +        case  6: *d++ = *s++;
    1.31 +        case  5: *d++ = *s++;
    1.32 +        case  4: *d++ = *s++;
    1.33 +        case  3: *d++ = *s++;
    1.34 +        case  2: *d++ = *s++;
    1.35 +        case  1: *d++ = *s++;
    1.36 +        case  0: break;
    1.37 +    }
    1.38 +}
    1.39 +
    1.40 +static inline void small_memset(void* dst, uint8_t value, int n) {
    1.41 +    SkASSERT(n > 0 && n <= 15);
    1.42 +    uint8_t* d = (uint8_t*)dst;
    1.43 +    switch (n) {
    1.44 +        case 15: *d++ = value;
    1.45 +        case 14: *d++ = value;
    1.46 +        case 13: *d++ = value;
    1.47 +        case 12: *d++ = value;
    1.48 +        case 11: *d++ = value;
    1.49 +        case 10: *d++ = value;
    1.50 +        case  9: *d++ = value;
    1.51 +        case  8: *d++ = value;
    1.52 +        case  7: *d++ = value;
    1.53 +        case  6: *d++ = value;
    1.54 +        case  5: *d++ = value;
    1.55 +        case  4: *d++ = value;
    1.56 +        case  3: *d++ = value;
    1.57 +        case  2: *d++ = value;
    1.58 +        case  1: *d++ = value;
    1.59 +        case  0: break;
    1.60 +    }
    1.61 +}
    1.62 +
    1.63 +// can we do better for small counts with our own inlined memcpy/memset?
    1.64 +
    1.65 +#define PB_MEMSET(addr, value, count)       \
    1.66 +do {                                        \
    1.67 +if ((count) > 15) {                     \
    1.68 +memset(addr, value, count);         \
    1.69 +} else {                                \
    1.70 +small_memset(addr, value, count);   \
    1.71 +}                                       \
    1.72 +} while (0)
    1.73 +
    1.74 +#define PB_MEMCPY(dst, src, count)      \
    1.75 +do {                                    \
    1.76 +    if ((count) > 15) {                 \
    1.77 +        memcpy(dst, src, count);        \
    1.78 +    } else {                            \
    1.79 +        small_memcpy(dst, src, count);  \
    1.80 +    }                                   \
    1.81 +} while (0)
    1.82 +
    1.83 +///////////////////////////////////////////////////////////////////////////////
    1.84 +
    1.85 +#ifdef GATHER_STATS
    1.86 +    static int gMemSetBuckets[129];
    1.87 +    static int gMemCpyBuckets[129];
    1.88 +    static int gCounter;
    1.89 +
    1.90 +static void register_memset_count(int n) {
    1.91 +    SkASSERT((unsigned)n <= 128);
    1.92 +    gMemSetBuckets[n] += 1;
    1.93 +    gCounter += 1;
    1.94 +
    1.95 +    if ((gCounter & 0xFF) == 0) {
    1.96 +        SkDebugf("----- packbits memset stats: ");
    1.97 +        for (size_t i = 0; i < SK_ARRAY_COUNT(gMemSetBuckets); i++) {
    1.98 +            if (gMemSetBuckets[i]) {
    1.99 +                SkDebugf(" %d:%d", i, gMemSetBuckets[i]);
   1.100 +            }
   1.101 +        }
   1.102 +    }
   1.103 +}
   1.104 +static void register_memcpy_count(int n) {
   1.105 +    SkASSERT((unsigned)n <= 128);
   1.106 +    gMemCpyBuckets[n] += 1;
   1.107 +    gCounter += 1;
   1.108 +
   1.109 +    if ((gCounter & 0x1FF) == 0) {
   1.110 +        SkDebugf("----- packbits memcpy stats: ");
   1.111 +        for (size_t i = 0; i < SK_ARRAY_COUNT(gMemCpyBuckets); i++) {
   1.112 +            if (gMemCpyBuckets[i]) {
   1.113 +                SkDebugf(" %d:%d", i, gMemCpyBuckets[i]);
   1.114 +            }
   1.115 +        }
   1.116 +    }
   1.117 +}
   1.118 +#else
   1.119 +#define register_memset_count(n)
   1.120 +#define register_memcpy_count(n)
   1.121 +#endif
   1.122 +
   1.123 +
   1.124 +///////////////////////////////////////////////////////////////////////////////
   1.125 +
   1.126 +size_t SkPackBits::ComputeMaxSize16(int count) {
   1.127 +    // worst case is the number of 16bit values (times 2) +
   1.128 +    // 1 byte per (up to) 128 entries.
   1.129 +    return ((count + 127) >> 7) + (count << 1);
   1.130 +}
   1.131 +
   1.132 +size_t SkPackBits::ComputeMaxSize8(int count) {
   1.133 +    // worst case is the number of 8bit values + 1 byte per (up to) 128 entries.
   1.134 +    return ((count + 127) >> 7) + count;
   1.135 +}
   1.136 +
   1.137 +static uint8_t* flush_same16(uint8_t dst[], uint16_t value, int count) {
   1.138 +    while (count > 0) {
   1.139 +        int n = count;
   1.140 +        if (n > 128) {
   1.141 +            n = 128;
   1.142 +        }
   1.143 +        *dst++ = (uint8_t)(n - 1);
   1.144 +        *dst++ = (uint8_t)(value >> 8);
   1.145 +        *dst++ = (uint8_t)value;
   1.146 +        count -= n;
   1.147 +    }
   1.148 +    return dst;
   1.149 +}
   1.150 +
   1.151 +static uint8_t* flush_same8(uint8_t dst[], uint8_t value, int count) {
   1.152 +    while (count > 0) {
   1.153 +        int n = count;
   1.154 +        if (n > 128) {
   1.155 +            n = 128;
   1.156 +        }
   1.157 +        *dst++ = (uint8_t)(n - 1);
   1.158 +        *dst++ = (uint8_t)value;
   1.159 +        count -= n;
   1.160 +    }
   1.161 +    return dst;
   1.162 +}
   1.163 +
   1.164 +static uint8_t* flush_diff16(uint8_t* SK_RESTRICT dst,
   1.165 +                             const uint16_t* SK_RESTRICT src, int count) {
   1.166 +    while (count > 0) {
   1.167 +        int n = count;
   1.168 +        if (n > 128) {
   1.169 +            n = 128;
   1.170 +        }
   1.171 +        *dst++ = (uint8_t)(n + 127);
   1.172 +        PB_MEMCPY(dst, src, n * sizeof(uint16_t));
   1.173 +        src += n;
   1.174 +        dst += n * sizeof(uint16_t);
   1.175 +        count -= n;
   1.176 +    }
   1.177 +    return dst;
   1.178 +}
   1.179 +
   1.180 +static uint8_t* flush_diff8(uint8_t* SK_RESTRICT dst,
   1.181 +                            const uint8_t* SK_RESTRICT src, int count) {
   1.182 +    while (count > 0) {
   1.183 +        int n = count;
   1.184 +        if (n > 128) {
   1.185 +            n = 128;
   1.186 +        }
   1.187 +        *dst++ = (uint8_t)(n + 127);
   1.188 +        PB_MEMCPY(dst, src, n);
   1.189 +        src += n;
   1.190 +        dst += n;
   1.191 +        count -= n;
   1.192 +    }
   1.193 +    return dst;
   1.194 +}
   1.195 +
   1.196 +size_t SkPackBits::Pack16(const uint16_t* SK_RESTRICT src, int count,
   1.197 +                          uint8_t* SK_RESTRICT dst) {
   1.198 +    uint8_t* origDst = dst;
   1.199 +    const uint16_t* stop = src + count;
   1.200 +
   1.201 +    for (;;) {
   1.202 +        count = stop - src;
   1.203 +        SkASSERT(count >= 0);
   1.204 +        if (count == 0) {
   1.205 +            return dst - origDst;
   1.206 +        }
   1.207 +        if (1 == count) {
   1.208 +            *dst++ = 0;
   1.209 +            *dst++ = (uint8_t)(*src >> 8);
   1.210 +            *dst++ = (uint8_t)*src;
   1.211 +            return dst - origDst;
   1.212 +        }
   1.213 +
   1.214 +        unsigned value = *src;
   1.215 +        const uint16_t* s = src + 1;
   1.216 +
   1.217 +        if (*s == value) { // accumulate same values...
   1.218 +            do {
   1.219 +                s++;
   1.220 +                if (s == stop) {
   1.221 +                    break;
   1.222 +                }
   1.223 +            } while (*s == value);
   1.224 +            dst = flush_same16(dst, value, s - src);
   1.225 +        } else {    // accumulate diff values...
   1.226 +            do {
   1.227 +                if (++s == stop) {
   1.228 +                    goto FLUSH_DIFF;
   1.229 +                }
   1.230 +            } while (*s != s[-1]);
   1.231 +            s -= 1; // back up so we don't grab one of the "same" values that follow
   1.232 +        FLUSH_DIFF:
   1.233 +            dst = flush_diff16(dst, src, s - src);
   1.234 +        }
   1.235 +        src = s;
   1.236 +    }
   1.237 +}
   1.238 +
   1.239 +size_t SkPackBits::Pack8(const uint8_t* SK_RESTRICT src, int count,
   1.240 +                         uint8_t* SK_RESTRICT dst) {
   1.241 +    uint8_t* origDst = dst;
   1.242 +    const uint8_t* stop = src + count;
   1.243 +
   1.244 +    for (;;) {
   1.245 +        count = stop - src;
   1.246 +        SkASSERT(count >= 0);
   1.247 +        if (count == 0) {
   1.248 +            return dst - origDst;
   1.249 +        }
   1.250 +        if (1 == count) {
   1.251 +            *dst++ = 0;
   1.252 +            *dst++ = *src;
   1.253 +            return dst - origDst;
   1.254 +        }
   1.255 +
   1.256 +        unsigned value = *src;
   1.257 +        const uint8_t* s = src + 1;
   1.258 +
   1.259 +        if (*s == value) { // accumulate same values...
   1.260 +            do {
   1.261 +                s++;
   1.262 +                if (s == stop) {
   1.263 +                    break;
   1.264 +                }
   1.265 +            } while (*s == value);
   1.266 +            dst = flush_same8(dst, value, s - src);
   1.267 +        } else {    // accumulate diff values...
   1.268 +            do {
   1.269 +                if (++s == stop) {
   1.270 +                    goto FLUSH_DIFF;
   1.271 +                }
   1.272 +                // only stop if we hit 3 in a row,
   1.273 +                // otherwise we get bigger than compuatemax
   1.274 +            } while (*s != s[-1] || s[-1] != s[-2]);
   1.275 +            s -= 2; // back up so we don't grab the "same" values that follow
   1.276 +        FLUSH_DIFF:
   1.277 +            dst = flush_diff8(dst, src, s - src);
   1.278 +        }
   1.279 +        src = s;
   1.280 +    }
   1.281 +}
   1.282 +
   1.283 +#include "SkUtils.h"
   1.284 +
   1.285 +int SkPackBits::Unpack16(const uint8_t* SK_RESTRICT src, size_t srcSize,
   1.286 +                         uint16_t* SK_RESTRICT dst) {
   1.287 +    uint16_t* origDst = dst;
   1.288 +    const uint8_t* stop = src + srcSize;
   1.289 +
   1.290 +    while (src < stop) {
   1.291 +        unsigned n = *src++;
   1.292 +        if (n <= 127) {   // repeat count (n + 1)
   1.293 +            n += 1;
   1.294 +            sk_memset16(dst, (src[0] << 8) | src[1], n);
   1.295 +            src += 2;
   1.296 +        } else {    // same count (n - 127)
   1.297 +            n -= 127;
   1.298 +            PB_MEMCPY(dst, src, n * sizeof(uint16_t));
   1.299 +            src += n * sizeof(uint16_t);
   1.300 +        }
   1.301 +        dst += n;
   1.302 +    }
   1.303 +    SkASSERT(src == stop);
   1.304 +    return dst - origDst;
   1.305 +}
   1.306 +
   1.307 +int SkPackBits::Unpack8(const uint8_t* SK_RESTRICT src, size_t srcSize,
   1.308 +                        uint8_t* SK_RESTRICT dst) {
   1.309 +    uint8_t* origDst = dst;
   1.310 +    const uint8_t* stop = src + srcSize;
   1.311 +
   1.312 +    while (src < stop) {
   1.313 +        unsigned n = *src++;
   1.314 +        if (n <= 127) {   // repeat count (n + 1)
   1.315 +            n += 1;
   1.316 +            PB_MEMSET(dst, *src++, n);
   1.317 +        } else {    // same count (n - 127)
   1.318 +            n -= 127;
   1.319 +            PB_MEMCPY(dst, src, n);
   1.320 +            src += n;
   1.321 +        }
   1.322 +        dst += n;
   1.323 +    }
   1.324 +    SkASSERT(src == stop);
   1.325 +    return dst - origDst;
   1.326 +}
   1.327 +
   1.328 +enum UnpackState {
   1.329 +    CLEAN_STATE,
   1.330 +    REPEAT_BYTE_STATE,
   1.331 +    COPY_SRC_STATE
   1.332 +};
   1.333 +
   1.334 +void SkPackBits::Unpack8(uint8_t* SK_RESTRICT dst, size_t dstSkip,
   1.335 +                         size_t dstWrite, const uint8_t* SK_RESTRICT src) {
   1.336 +    if (dstWrite == 0) {
   1.337 +        return;
   1.338 +    }
   1.339 +
   1.340 +    UnpackState state = CLEAN_STATE;
   1.341 +    size_t      stateCount = 0;
   1.342 +
   1.343 +    // state 1: do the skip-loop
   1.344 +    while (dstSkip > 0) {
   1.345 +        unsigned n = *src++;
   1.346 +        if (n <= 127) {   // repeat count (n + 1)
   1.347 +            n += 1;
   1.348 +            if (n > dstSkip) {
   1.349 +                state = REPEAT_BYTE_STATE;
   1.350 +                stateCount = n - dstSkip;
   1.351 +                n = dstSkip;
   1.352 +                // we don't increment src here, since its needed in stage 2
   1.353 +            } else {
   1.354 +                src++;  // skip the src byte
   1.355 +            }
   1.356 +        } else {    // same count (n - 127)
   1.357 +            n -= 127;
   1.358 +            if (n > dstSkip) {
   1.359 +                state = COPY_SRC_STATE;
   1.360 +                stateCount = n - dstSkip;
   1.361 +                n = dstSkip;
   1.362 +            }
   1.363 +            src += n;
   1.364 +        }
   1.365 +        dstSkip -= n;
   1.366 +    }
   1.367 +
   1.368 +    // stage 2: perform any catchup from the skip-stage
   1.369 +    if (stateCount > dstWrite) {
   1.370 +        stateCount = dstWrite;
   1.371 +    }
   1.372 +    switch (state) {
   1.373 +        case REPEAT_BYTE_STATE:
   1.374 +            SkASSERT(stateCount > 0);
   1.375 +            register_memset_count(stateCount);
   1.376 +            PB_MEMSET(dst, *src++, stateCount);
   1.377 +            break;
   1.378 +        case COPY_SRC_STATE:
   1.379 +            SkASSERT(stateCount > 0);
   1.380 +            register_memcpy_count(stateCount);
   1.381 +            PB_MEMCPY(dst, src, stateCount);
   1.382 +            src += stateCount;
   1.383 +            break;
   1.384 +        default:
   1.385 +            SkASSERT(stateCount == 0);
   1.386 +            break;
   1.387 +    }
   1.388 +    dst += stateCount;
   1.389 +    dstWrite -= stateCount;
   1.390 +
   1.391 +    // copy at most dstWrite bytes into dst[]
   1.392 +    while (dstWrite > 0) {
   1.393 +        unsigned n = *src++;
   1.394 +        if (n <= 127) {   // repeat count (n + 1)
   1.395 +            n += 1;
   1.396 +            if (n > dstWrite) {
   1.397 +                n = dstWrite;
   1.398 +            }
   1.399 +            register_memset_count(n);
   1.400 +            PB_MEMSET(dst, *src++, n);
   1.401 +        } else {    // same count (n - 127)
   1.402 +            n -= 127;
   1.403 +            if (n > dstWrite) {
   1.404 +                n = dstWrite;
   1.405 +            }
   1.406 +            register_memcpy_count(n);
   1.407 +            PB_MEMCPY(dst, src, n);
   1.408 +            src += n;
   1.409 +        }
   1.410 +        dst += n;
   1.411 +        dstWrite -= n;
   1.412 +    }
   1.413 +    SkASSERT(0 == dstWrite);
   1.414 +}

mercurial