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 |
20 #if COMPRESS_LATC_SLOW | 60 #if COMPRESS_LATC_SLOW |
21 | 61 |
22 //////////////////////////////////////////////////////////////////////////////// | 62 //////////////////////////////////////////////////////////////////////////////// |
23 // | 63 // |
24 // Utility Functions | 64 // Utility Functions |
25 // | 65 // |
26 //////////////////////////////////////////////////////////////////////////////// | 66 //////////////////////////////////////////////////////////////////////////////// |
27 | 67 |
28 // Absolute difference between two values. More correct than SkTAbs(a - b) | 68 // Absolute difference between two values. More correct than SkTAbs(a - b) |
29 // because it works on unsigned values. | 69 // because it works on unsigned values. |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
72 return true; | 112 return true; |
73 } | 113 } |
74 | 114 |
75 //////////////////////////////////////////////////////////////////////////////// | 115 //////////////////////////////////////////////////////////////////////////////// |
76 // | 116 // |
77 // LATC compressor | 117 // LATC compressor |
78 // | 118 // |
79 //////////////////////////////////////////////////////////////////////////////// | 119 //////////////////////////////////////////////////////////////////////////////// |
80 | 120 |
81 // LATC compressed texels down into square 4x4 blocks | 121 // LATC compressed texels down into square 4x4 blocks |
82 static const int kLATCPaletteSize = 8; | |
83 static const int kLATCBlockSize = 4; | 122 static const int kLATCBlockSize = 4; |
84 static const int kLATCPixelsPerBlock = kLATCBlockSize * kLATCBlockSize; | 123 static const int kLATCPixelsPerBlock = kLATCBlockSize * kLATCBlockSize; |
85 | 124 |
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 | |
123 // Compress a block by using the bounding box of the pixels. It is assumed that | 125 // Compress a block by using the bounding box of the pixels. It is assumed that |
124 // there are no extremal pixels in this block otherwise we would have used | 126 // there are no extremal pixels in this block otherwise we would have used |
125 // compressBlockBBIgnoreExtremal. | 127 // compressBlockBBIgnoreExtremal. |
126 static uint64_t compress_latc_block_bb(const uint8_t pixels[]) { | 128 static uint64_t compress_latc_block_bb(const uint8_t pixels[]) { |
127 uint8_t minVal = 255; | 129 uint8_t minVal = 255; |
128 uint8_t maxVal = 0; | 130 uint8_t maxVal = 0; |
129 for (int i = 0; i < kLATCPixelsPerBlock; ++i) { | 131 for (int i = 0; i < kLATCPixelsPerBlock; ++i) { |
130 minVal = SkTMin(pixels[i], minVal); | 132 minVal = SkTMin(pixels[i], minVal); |
131 maxVal = SkTMax(pixels[i], maxVal); | 133 maxVal = SkTMax(pixels[i], maxVal); |
132 } | 134 } |
(...skipping 253 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
386 | 388 |
387 return true; | 389 return true; |
388 } | 390 } |
389 | 391 |
390 void CompressA8LATCBlockVertical(uint8_t* dst, const uint8_t block[]) { | 392 void CompressA8LATCBlockVertical(uint8_t* dst, const uint8_t block[]) { |
391 compress_a8_latc_block<PackColumnMajor>(&dst, block, 4); | 393 compress_a8_latc_block<PackColumnMajor>(&dst, block, 4); |
392 } | 394 } |
393 | 395 |
394 #endif // COMPRESS_LATC_FAST | 396 #endif // COMPRESS_LATC_FAST |
395 | 397 |
| 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 |
396 //////////////////////////////////////////////////////////////////////////////// | 416 //////////////////////////////////////////////////////////////////////////////// |
397 | 417 |
398 namespace SkTextureCompressor { | 418 namespace SkTextureCompressor { |
399 | 419 |
400 bool CompressA8ToLATC(uint8_t* dst, const uint8_t* src, int width, int height, i
nt rowBytes) { | 420 bool CompressA8ToLATC(uint8_t* dst, const uint8_t* src, int width, int height, i
nt rowBytes) { |
401 #if COMPRESS_LATC_FAST | 421 #if COMPRESS_LATC_FAST |
402 return compress_4x4_a8_latc(dst, src, width, height, rowBytes); | 422 return compress_4x4_a8_latc(dst, src, width, height, rowBytes); |
403 #elif COMPRESS_LATC_SLOW | 423 #elif COMPRESS_LATC_SLOW |
404 return compress_4x4_a8_to_64bit(dst, src, width, height, rowBytes, compress_
latc_block); | 424 return compress_4x4_a8_to_64bit(dst, src, width, height, rowBytes, compress_
latc_block); |
405 #else | 425 #else |
406 #error "Must choose either fast or slow LATC compression" | 426 #error "Must choose either fast or slow LATC compression" |
407 #endif | 427 #endif |
408 } | 428 } |
409 | 429 |
410 SkBlitter* CreateLATCBlitter(int width, int height, void* outputBuffer) { | 430 SkBlitter* CreateLATCBlitter(int width, int height, void* outputBuffer) { |
411 #if COMPRESS_LATC_FAST | 431 #if COMPRESS_LATC_FAST |
412 return new | 432 return new |
413 SkTCompressedAlphaBlitter<4, 8, CompressA8LATCBlockVertical> | 433 SkTCompressedAlphaBlitter<4, 8, CompressA8LATCBlockVertical> |
414 (width, height, outputBuffer); | 434 (width, height, outputBuffer); |
415 #elif COMPRESS_LATC_SLOW | 435 #elif COMPRESS_LATC_SLOW |
416 // TODO (krajcevski) | 436 // TODO (krajcevski) |
417 return NULL; | 437 return NULL; |
418 #endif | 438 #endif |
419 } | 439 } |
420 | 440 |
| 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 |
421 } // SkTextureCompressor | 451 } // SkTextureCompressor |
OLD | NEW |