OLD | NEW |
| (Empty) |
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 fo
llow | |
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 | |
OLD | NEW |