OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2014 Google Inc. | 2 * Copyright 2014 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "SkTextureCompressor_LATC.h" | 8 #include "SkTextureCompressor_LATC.h" |
9 #include "SkTextureCompressor_Blitter.h" | 9 #include "SkTextureCompressor_Blitter.h" |
10 | 10 |
11 #include "SkEndian.h" | 11 #include "SkEndian.h" |
12 | 12 |
13 // Compression options. In general, the slow version is much more accurate, but | 13 // Compression options. In general, the slow version is much more accurate, but |
14 // much slower. The fast option is much faster, but much less accurate. YMMV. | 14 // much slower. The fast option is much faster, but much less accurate. YMMV. |
15 #define COMPRESS_LATC_SLOW 0 | 15 #define COMPRESS_LATC_SLOW 0 |
16 #define COMPRESS_LATC_FAST 1 | 16 #define COMPRESS_LATC_FAST 1 |
17 | 17 |
18 //////////////////////////////////////////////////////////////////////////////// | 18 //////////////////////////////////////////////////////////////////////////////// |
19 | 19 |
20 // Generates an LATC palette. LATC constructs | |
21 // a palette of eight colors from LUM0 and LUM1 using the algorithm: | |
22 // | |
23 // LUM0, if lum0 > lum1 and code(x,y) == 0 | |
24 // LUM1, if lum0 > lum1 and code(x,y) == 1 | |
25 // (6*LUM0+ LUM1)/7, if lum0 > lum1 and code(x,y) == 2 | |
26 // (5*LUM0+2*LUM1)/7, if lum0 > lum1 and code(x,y) == 3 | |
27 // (4*LUM0+3*LUM1)/7, if lum0 > lum1 and code(x,y) == 4 | |
28 // (3*LUM0+4*LUM1)/7, if lum0 > lum1 and code(x,y) == 5 | |
29 // (2*LUM0+5*LUM1)/7, if lum0 > lum1 and code(x,y) == 6 | |
30 // ( LUM0+6*LUM1)/7, if lum0 > lum1 and code(x,y) == 7 | |
31 // | |
32 // LUM0, if lum0 <= lum1 and code(x,y) == 0 | |
33 // LUM1, if lum0 <= lum1 and code(x,y) == 1 | |
34 // (4*LUM0+ LUM1)/5, if lum0 <= lum1 and code(x,y) == 2 | |
35 // (3*LUM0+2*LUM1)/5, if lum0 <= lum1 and code(x,y) == 3 | |
36 // (2*LUM0+3*LUM1)/5, if lum0 <= lum1 and code(x,y) == 4 | |
37 // ( LUM0+4*LUM1)/5, if lum0 <= lum1 and code(x,y) == 5 | |
38 // 0, if lum0 <= lum1 and code(x,y) == 6 | |
39 // 255, if lum0 <= lum1 and code(x,y) == 7 | |
40 | |
41 static const int kLATCPaletteSize = 8; | |
42 static void generate_latc_palette(uint8_t palette[], uint8_t lum0, uint8_t lum1)
{ | |
43 palette[0] = lum0; | |
44 palette[1] = lum1; | |
45 if (lum0 > lum1) { | |
46 for (int i = 1; i < 7; i++) { | |
47 palette[i+1] = ((7-i)*lum0 + i*lum1) / 7; | |
48 } | |
49 } else { | |
50 for (int i = 1; i < 5; i++) { | |
51 palette[i+1] = ((5-i)*lum0 + i*lum1) / 5; | |
52 } | |
53 palette[6] = 0; | |
54 palette[7] = 255; | |
55 } | |
56 } | |
57 | |
58 //////////////////////////////////////////////////////////////////////////////// | |
59 | |
60 #if COMPRESS_LATC_SLOW | 20 #if COMPRESS_LATC_SLOW |
61 | 21 |
62 //////////////////////////////////////////////////////////////////////////////// | 22 //////////////////////////////////////////////////////////////////////////////// |
63 // | 23 // |
64 // Utility Functions | 24 // Utility Functions |
65 // | 25 // |
66 //////////////////////////////////////////////////////////////////////////////// | 26 //////////////////////////////////////////////////////////////////////////////// |
67 | 27 |
68 // Absolute difference between two values. More correct than SkTAbs(a - b) | 28 // Absolute difference between two values. More correct than SkTAbs(a - b) |
69 // because it works on unsigned values. | 29 // because it works on unsigned values. |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
112 return true; | 72 return true; |
113 } | 73 } |
114 | 74 |
115 //////////////////////////////////////////////////////////////////////////////// | 75 //////////////////////////////////////////////////////////////////////////////// |
116 // | 76 // |
117 // LATC compressor | 77 // LATC compressor |
118 // | 78 // |
119 //////////////////////////////////////////////////////////////////////////////// | 79 //////////////////////////////////////////////////////////////////////////////// |
120 | 80 |
121 // LATC compressed texels down into square 4x4 blocks | 81 // LATC compressed texels down into square 4x4 blocks |
| 82 static const int kLATCPaletteSize = 8; |
122 static const int kLATCBlockSize = 4; | 83 static const int kLATCBlockSize = 4; |
123 static const int kLATCPixelsPerBlock = kLATCBlockSize * kLATCBlockSize; | 84 static const int kLATCPixelsPerBlock = kLATCBlockSize * kLATCBlockSize; |
124 | 85 |
| 86 // Generates an LATC palette. LATC constructs |
| 87 // a palette of eight colors from LUM0 and LUM1 using the algorithm: |
| 88 // |
| 89 // LUM0, if lum0 > lum1 and code(x,y) == 0 |
| 90 // LUM1, if lum0 > lum1 and code(x,y) == 1 |
| 91 // (6*LUM0+ LUM1)/7, if lum0 > lum1 and code(x,y) == 2 |
| 92 // (5*LUM0+2*LUM1)/7, if lum0 > lum1 and code(x,y) == 3 |
| 93 // (4*LUM0+3*LUM1)/7, if lum0 > lum1 and code(x,y) == 4 |
| 94 // (3*LUM0+4*LUM1)/7, if lum0 > lum1 and code(x,y) == 5 |
| 95 // (2*LUM0+5*LUM1)/7, if lum0 > lum1 and code(x,y) == 6 |
| 96 // ( LUM0+6*LUM1)/7, if lum0 > lum1 and code(x,y) == 7 |
| 97 // |
| 98 // LUM0, if lum0 <= lum1 and code(x,y) == 0 |
| 99 // LUM1, if lum0 <= lum1 and code(x,y) == 1 |
| 100 // (4*LUM0+ LUM1)/5, if lum0 <= lum1 and code(x,y) == 2 |
| 101 // (3*LUM0+2*LUM1)/5, if lum0 <= lum1 and code(x,y) == 3 |
| 102 // (2*LUM0+3*LUM1)/5, if lum0 <= lum1 and code(x,y) == 4 |
| 103 // ( LUM0+4*LUM1)/5, if lum0 <= lum1 and code(x,y) == 5 |
| 104 // 0, if lum0 <= lum1 and code(x,y) == 6 |
| 105 // 255, if lum0 <= lum1 and code(x,y) == 7 |
| 106 |
| 107 static void generate_latc_palette(uint8_t palette[], uint8_t lum0, uint8_t lum1)
{ |
| 108 palette[0] = lum0; |
| 109 palette[1] = lum1; |
| 110 if (lum0 > lum1) { |
| 111 for (int i = 1; i < 7; i++) { |
| 112 palette[i+1] = ((7-i)*lum0 + i*lum1) / 7; |
| 113 } |
| 114 } else { |
| 115 for (int i = 1; i < 5; i++) { |
| 116 palette[i+1] = ((5-i)*lum0 + i*lum1) / 5; |
| 117 } |
| 118 palette[6] = 0; |
| 119 palette[7] = 255; |
| 120 } |
| 121 } |
| 122 |
125 // Compress a block by using the bounding box of the pixels. It is assumed that | 123 // Compress a block by using the bounding box of the pixels. It is assumed that |
126 // there are no extremal pixels in this block otherwise we would have used | 124 // there are no extremal pixels in this block otherwise we would have used |
127 // compressBlockBBIgnoreExtremal. | 125 // compressBlockBBIgnoreExtremal. |
128 static uint64_t compress_latc_block_bb(const uint8_t pixels[]) { | 126 static uint64_t compress_latc_block_bb(const uint8_t pixels[]) { |
129 uint8_t minVal = 255; | 127 uint8_t minVal = 255; |
130 uint8_t maxVal = 0; | 128 uint8_t maxVal = 0; |
131 for (int i = 0; i < kLATCPixelsPerBlock; ++i) { | 129 for (int i = 0; i < kLATCPixelsPerBlock; ++i) { |
132 minVal = SkTMin(pixels[i], minVal); | 130 minVal = SkTMin(pixels[i], minVal); |
133 maxVal = SkTMax(pixels[i], maxVal); | 131 maxVal = SkTMax(pixels[i], maxVal); |
134 } | 132 } |
(...skipping 253 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
388 | 386 |
389 return true; | 387 return true; |
390 } | 388 } |
391 | 389 |
392 void CompressA8LATCBlockVertical(uint8_t* dst, const uint8_t block[]) { | 390 void CompressA8LATCBlockVertical(uint8_t* dst, const uint8_t block[]) { |
393 compress_a8_latc_block<PackColumnMajor>(&dst, block, 4); | 391 compress_a8_latc_block<PackColumnMajor>(&dst, block, 4); |
394 } | 392 } |
395 | 393 |
396 #endif // COMPRESS_LATC_FAST | 394 #endif // COMPRESS_LATC_FAST |
397 | 395 |
398 void decompress_latc_block(uint8_t* dst, int dstRowBytes, const uint8_t* src) { | |
399 uint64_t block = SkEndian_SwapLE64(*(reinterpret_cast<const uint64_t *>(src)
)); | |
400 uint8_t lum0 = block & 0xFF; | |
401 uint8_t lum1 = (block >> 8) & 0xFF; | |
402 | |
403 uint8_t palette[kLATCPaletteSize]; | |
404 generate_latc_palette(palette, lum0, lum1); | |
405 | |
406 block >>= 16; | |
407 for (int j = 0; j < 4; ++j) { | |
408 for (int i = 0; i < 4; ++i) { | |
409 dst[i] = palette[block & 0x7]; | |
410 block >>= 3; | |
411 } | |
412 dst += dstRowBytes; | |
413 } | |
414 } | |
415 | |
416 //////////////////////////////////////////////////////////////////////////////// | 396 //////////////////////////////////////////////////////////////////////////////// |
417 | 397 |
418 namespace SkTextureCompressor { | 398 namespace SkTextureCompressor { |
419 | 399 |
420 bool CompressA8ToLATC(uint8_t* dst, const uint8_t* src, int width, int height, i
nt rowBytes) { | 400 bool CompressA8ToLATC(uint8_t* dst, const uint8_t* src, int width, int height, i
nt rowBytes) { |
421 #if COMPRESS_LATC_FAST | 401 #if COMPRESS_LATC_FAST |
422 return compress_4x4_a8_latc(dst, src, width, height, rowBytes); | 402 return compress_4x4_a8_latc(dst, src, width, height, rowBytes); |
423 #elif COMPRESS_LATC_SLOW | 403 #elif COMPRESS_LATC_SLOW |
424 return compress_4x4_a8_to_64bit(dst, src, width, height, rowBytes, compress_
latc_block); | 404 return compress_4x4_a8_to_64bit(dst, src, width, height, rowBytes, compress_
latc_block); |
425 #else | 405 #else |
426 #error "Must choose either fast or slow LATC compression" | 406 #error "Must choose either fast or slow LATC compression" |
427 #endif | 407 #endif |
428 } | 408 } |
429 | 409 |
430 SkBlitter* CreateLATCBlitter(int width, int height, void* outputBuffer) { | 410 SkBlitter* CreateLATCBlitter(int width, int height, void* outputBuffer) { |
431 #if COMPRESS_LATC_FAST | 411 #if COMPRESS_LATC_FAST |
432 return new | 412 return new |
433 SkTCompressedAlphaBlitter<4, 8, CompressA8LATCBlockVertical> | 413 SkTCompressedAlphaBlitter<4, 8, CompressA8LATCBlockVertical> |
434 (width, height, outputBuffer); | 414 (width, height, outputBuffer); |
435 #elif COMPRESS_LATC_SLOW | 415 #elif COMPRESS_LATC_SLOW |
436 // TODO (krajcevski) | 416 // TODO (krajcevski) |
437 return NULL; | 417 return NULL; |
438 #endif | 418 #endif |
439 } | 419 } |
440 | 420 |
441 void DecompressLATC(uint8_t* dst, int dstRowBytes, const uint8_t* src, int width
, int height) { | |
442 for (int j = 0; j < height; j += 4) { | |
443 for (int i = 0; i < width; i += 4) { | |
444 decompress_latc_block(dst + i, dstRowBytes, src); | |
445 src += 8; | |
446 } | |
447 dst += 4 * dstRowBytes; | |
448 } | |
449 } | |
450 | |
451 } // SkTextureCompressor | 421 } // SkTextureCompressor |
OLD | NEW |