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 +}