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_ASTC.h" | 8 #include "SkTextureCompressor_ASTC.h" |
9 #include "SkTextureCompressor_Blitter.h" | 9 #include "SkTextureCompressor_Blitter.h" |
10 | 10 |
11 #include "SkBlitter.h" | 11 #include "SkBlitter.h" |
12 #include "SkEndian.h" | 12 #include "SkEndian.h" |
13 #include "SkMath.h" | |
13 | 14 |
14 // This table contains the weight values for each texel. This is used in determi ning | 15 // This table contains the weight values for each texel. This is used in determi ning |
15 // how to convert a 12x12 grid of alpha values into a 6x5 grid of index values. Since | 16 // how to convert a 12x12 grid of alpha values into a 6x5 grid of index values. Since |
16 // we have a 6x5 grid, that gives 30 values that we have to compute. For each in dex, | 17 // we have a 6x5 grid, that gives 30 values that we have to compute. For each in dex, |
17 // we store up to 20 different triplets of values. In order the triplets are: | 18 // we store up to 20 different triplets of values. In order the triplets are: |
18 // weight, texel-x, texel-y | 19 // weight, texel-x, texel-y |
19 // The weight value corresponds to the amount that this index contributes to the final | 20 // The weight value corresponds to the amount that this index contributes to the final |
20 // index value of the given texel. Hence, we need to reconstruct the 6x5 index g rid | 21 // index value of the given texel. Hence, we need to reconstruct the 6x5 index g rid |
21 // from their relative contribution to the 12x12 texel grid. | 22 // from their relative contribution to the 12x12 texel grid. |
22 // | 23 // |
(...skipping 231 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
254 top = top ^ t ^ (t << 2); | 255 top = top ^ t ^ (t << 2); |
255 | 256 |
256 send_packing(dst, SkEndian_SwapLE64(top), SkEndian_SwapLE64(bottom)); | 257 send_packing(dst, SkEndian_SwapLE64(top), SkEndian_SwapLE64(bottom)); |
257 } | 258 } |
258 | 259 |
259 inline void CompressA8ASTCBlockVertical(uint8_t* dst, const uint8_t* src) { | 260 inline void CompressA8ASTCBlockVertical(uint8_t* dst, const uint8_t* src) { |
260 compress_a8_astc_block<GetAlphaTranspose>(&dst, src, 12); | 261 compress_a8_astc_block<GetAlphaTranspose>(&dst, src, 12); |
261 } | 262 } |
262 | 263 |
263 //////////////////////////////////////////////////////////////////////////////// | 264 //////////////////////////////////////////////////////////////////////////////// |
265 // | |
266 // ASTC Decoder | |
267 // | |
268 // Full details available in the spec: | |
269 // http://www.khronos.org/registry/gles/extensions/OES/OES_texture_compression_a stc.txt | |
270 // | |
271 //////////////////////////////////////////////////////////////////////////////// | |
272 | |
robertphillips
2014/08/06 17:24:21
// Enable this to debug decoding errors. If not se
krajcevski
2014/08/06 18:14:30
Done.
| |
273 #define ASSERT_ASTC_DECODE_ERROR 0 | |
274 | |
275 // Reverse 64-bit integer taken from TAOCP 4a, although it's better | |
276 // documented at this site: | |
277 // http://matthewarcus.wordpress.com/2012/11/18/reversing-a-64-bit-word/ | |
278 | |
279 template <typename T, T m, int k> | |
280 static inline T swap_bits(T p) { | |
281 T q = ((p>>k)^p) & m; | |
282 return p^q^(q<<k); | |
283 } | |
284 | |
285 static inline uint64_t reverse64(uint64_t n) { | |
286 static const uint64_t m0 = 0x5555555555555555LLU; | |
287 static const uint64_t m1 = 0x0300c0303030c303LLU; | |
288 static const uint64_t m2 = 0x00c0300c03f0003fLLU; | |
289 static const uint64_t m3 = 0x00000ffc00003fffLLU; | |
290 n = ((n>>1)&m0) | (n&m0)<<1; | |
291 n = swap_bits<uint64_t, m1, 4>(n); | |
292 n = swap_bits<uint64_t, m2, 8>(n); | |
293 n = swap_bits<uint64_t, m3, 20>(n); | |
294 n = (n >> 34) | (n << 30); | |
295 return n; | |
296 } | |
297 | |
298 // An ASTC block is 128 bits. We represent it as two 64-bit integers in order | |
299 // to efficiently operate on the block using bitwise operations. | |
300 struct ASTCBlock { | |
301 uint64_t fLow; | |
302 uint64_t fHigh; | |
303 | |
304 // Reverses the bits of an ASTC block, making the LSB of the | |
305 // 128 bit block the MSB. | |
robertphillips
2014/08/06 17:24:21
lower case - since not static ?
krajcevski
2014/08/06 18:14:30
Done.
| |
306 inline void Reverse() { | |
307 const uint64_t newLow = reverse64(this->fHigh); | |
robertphillips
2014/08/06 17:24:20
Why have the newHigh temp? Why not plop it into fH
krajcevski
2014/08/06 18:14:30
Done.
| |
308 const uint64_t newHigh = reverse64(this->fLow); | |
309 this->fHigh = newHigh; | |
310 this->fLow = newLow; | |
311 } | |
312 }; | |
313 | |
314 // Writes the given color to every pixel in the block. This is used by void-exte nt | |
315 // blocks (a special constant-color encoding of a block) and by the error functi on. | |
316 static inline void write_constant_color(uint8_t* dst, int blockDimX, int blockDi mY, | |
317 int dstRowBytes, SkColor color) { | |
318 for (int y = 0; y < blockDimY; ++y) { | |
319 SkColor *dstColors = reinterpret_cast<SkColor*>(dst); | |
320 for (int x = 0; x < blockDimX; ++x) { | |
321 dstColors[x] = color; | |
322 } | |
323 dst += dstRowBytes; | |
324 } | |
325 } | |
326 | |
327 // Sets the entire block to the ASTC "error" color, a disgusting magenta | |
328 // that's not supposed to appear in natural images. | |
329 static inline void write_error_color(uint8_t* dst, int blockDimX, int blockDimY, | |
330 int dstRowBytes) { | |
331 static const SkColor kASTCErrorColor = SkColorSetRGB(0xFF, 0, 0xFF); | |
332 | |
333 #if ASSERT_ASTC_DECODE_ERROR | |
334 SkDEBUGFAIL("ASTC decoding error!\n"); | |
335 #endif | |
336 | |
337 write_constant_color(dst, blockDimX, blockDimY, dstRowBytes, kASTCErrorColor ); | |
338 } | |
339 | |
340 // Reads up to 64 bits of the ASTC block starting from bit | |
341 // 'from' and going up to but not including bit 'to'. 'from' starts | |
342 // counting from the LSB, counting up to the MSB. Returns -1 on | |
343 // error. | |
344 static uint64_t read_astc_bits(const ASTCBlock &block, int from, int to) { | |
345 SkASSERT(0 <= from && from <= 128); | |
346 SkASSERT(0 <= to && to <= 128); | |
347 | |
348 const int nBits = to - from; | |
349 if (0 == nBits) { | |
350 return 0; | |
351 } | |
352 | |
353 if (nBits < 0 || 64 <= nBits) { | |
354 SkDEBUGFAIL("ASTC -- shouldn't read more than 64 bits"); | |
355 return -1; | |
356 } | |
357 | |
358 // Remember, the 'to' bit isn't read. | |
359 uint64_t result = 0; | |
360 if (to <= 64) { | |
361 // All desired bits are in the low 64-bits. | |
362 result = (block.fLow >> from) & ((1ULL << nBits) - 1); | |
363 } else if (from >= 64) { | |
364 // All desired bits are in the high 64-bits. | |
365 result = (block.fHigh >> (from - 64)) & ((1ULL << nBits) - 1); | |
366 } else { | |
367 // from < 64 && to > 64 | |
368 SkASSERT(nBits > (64 - from)); | |
369 const int nLow = 64 - from; | |
370 const int nHigh = nBits - nLow; | |
371 result = | |
372 ((block.fLow >> from) & ((1ULL << nLow) - 1)) | | |
373 ((block.fHigh & ((1ULL << nHigh) - 1)) << nLow); | |
374 } | |
375 | |
376 return result; | |
377 } | |
378 | |
379 // Returns the number of bits needed to represent a number | |
robertphillips
2014/08/06 17:24:21
add "(excluding the power-of-two itself)" ?
krajcevski
2014/08/06 18:14:29
Done.
| |
380 // in the given power-of-two range. | |
381 static inline int bits_for_range(int x) { | |
382 SkASSERT(SkIsPow2(x)); | |
383 SkASSERT(0 != x); | |
384 // Since we know it's a power of two, there should only be one bit set, | |
385 // meaning the number of trailing zeros is 31 minus the number of leading | |
386 // zeros. | |
387 return 31 - SkCLZ(x); | |
388 } | |
389 | |
390 // Clamps an integer to the range [0, 255] | |
391 static inline int clamp_byte(int x) { | |
392 return SkClampMax(x, 255); | |
393 } | |
394 | |
395 // Helper function defined in the ASTC spec, section C.2.14 | |
396 // It transfers a few bits of precision from one value to another. | |
397 static inline void bit_transfer_signed(int *a, int *b) { | |
398 *b >>= 1; | |
399 *b |= *a & 0x80; | |
400 *a >>= 1; | |
401 *a &= 0x3F; | |
402 if ( (*a & 0x20) != 0 ) { | |
403 *a -= 0x40; | |
404 } | |
405 } | |
406 | |
407 // Helper function defined in the ASTC spec, section C.2.14 | |
robertphillips
2014/08/06 17:24:21
modulate -> tint ?
krajcevski
2014/08/06 18:14:30
Done.
| |
408 // It uses the value in the blue channel to modulate the red and green | |
409 static inline SkColor blue_contract(int a, int r, int g, int b) { | |
410 return SkColorSetARGB(a, (r + b) >> 1, (g + b) >> 1, b); | |
411 } | |
412 | |
robertphillips
2014/08/06 17:24:21
six or eight ?
krajcevski
2014/08/06 18:14:29
Done.
| |
413 // Helper function that decodes two colors from eight values stored in | |
414 // the pointer 'v'. This corresponds to the decode procedure for the following | |
415 // endpoint modes: | |
416 // kLDR_RGB_Direct_ColorEndpointMode | |
417 // kLDR_RGBA_Direct_ColorEndpointMode | |
418 static inline void decode_rgba_direct(const int *v, SkColor *endpoints, bool isR GB) { | |
419 | |
420 int v6 = 0xFF; | |
421 int v7 = 0xFF; | |
422 if (!isRGB) { | |
423 v6 = v[6]; | |
424 v7 = v[7]; | |
425 } | |
426 | |
427 const int s0 = v[0] + v[2] + v[4]; | |
428 const int s1 = v[1] + v[3] + v[5]; | |
429 | |
430 if (s1 >= s0) { | |
431 endpoints[0] = SkColorSetARGB(v6, v[0], v[2], v[4]); | |
432 endpoints[1] = SkColorSetARGB(v7, v[1], v[3], v[5]); | |
433 } else { | |
434 endpoints[0] = blue_contract(v7, v[1], v[3], v[5]); | |
435 endpoints[1] = blue_contract(v6, v[0], v[2], v[4]); | |
436 } | |
437 } | |
438 | |
robertphillips
2014/08/06 17:24:20
six or eight ?
krajcevski
2014/08/06 18:14:30
Done.
| |
439 // Helper function that decodes two colors from eight values stored in | |
440 // the pointer 'v'. This corresponds to the decode procedure for the following | |
441 // endpoint modes: | |
442 // kLDR_RGB_BaseOffset_ColorEndpointMode | |
443 // kLDR_RGBA_BaseOffset_ColorEndpointMode | |
444 // | |
445 // If isRGB is true, then treat this as if v6 and v7 are meant to encode full al pha values. | |
446 static inline void decode_rgba_baseoffset(const int *v, SkColor *endpoints, bool isRGB) { | |
447 int v0 = v[0]; | |
448 int v1 = v[1]; | |
449 int v2 = v[2]; | |
450 int v3 = v[3]; | |
451 int v4 = v[4]; | |
452 int v5 = v[5]; | |
453 int v6 = isRGB ? 0xFF : v[6]; | |
robertphillips
2014/08/06 17:24:20
0 -> 0xFF ?
krajcevski
2014/08/06 18:14:30
It's supposed to be 0 because it's added to v6. Th
| |
454 int v7 = isRGB ? 0 : v[7]; | |
455 | |
456 bit_transfer_signed(&v1, &v0); | |
457 bit_transfer_signed(&v3, &v2); | |
458 bit_transfer_signed(&v5, &v4); | |
459 if (!isRGB) { | |
460 bit_transfer_signed(&v7, &v6); | |
461 } | |
462 | |
463 int c[2][4]; | |
464 if ((v1 + v3 + v5) >= 0) { | |
465 c[0][0] = v6; | |
466 c[0][1] = v0; | |
467 c[0][2] = v2; | |
468 c[0][3] = v4; | |
469 | |
470 c[1][0] = v6 + v7; | |
471 c[1][1] = v0 + v1; | |
472 c[1][2] = v2 + v3; | |
473 c[1][3] = v4 + v5; | |
474 } else { | |
475 c[0][0] = v6 + v7; | |
476 c[0][1] = (v0 + v1 + v4 + v5) >> 1; | |
477 c[0][2] = (v2 + v3 + v4 + v5) >> 1; | |
478 c[0][3] = v4 + v5; | |
479 | |
480 c[1][0] = v6; | |
481 c[1][1] = (v0 + v4) >> 1; | |
482 c[1][2] = (v2 + v4) >> 1; | |
483 c[1][3] = v4; | |
484 } | |
485 | |
486 endpoints[0] = SkColorSetARGB( | |
robertphillips
2014/08/06 17:24:20
tab these guys over? Maybe have them on two lines?
krajcevski
2014/08/06 18:14:29
Done.
| |
487 clamp_byte(c[0][0]), | |
488 clamp_byte(c[0][1]), | |
489 clamp_byte(c[0][2]), | |
490 clamp_byte(c[0][3])); | |
491 | |
492 endpoints[1] = SkColorSetARGB( | |
493 clamp_byte(c[1][0]), | |
494 clamp_byte(c[1][1]), | |
495 clamp_byte(c[1][2]), | |
496 clamp_byte(c[1][3])); | |
497 } | |
498 | |
499 | |
500 // A helper class used to decode bit values from standard integer values. | |
501 // We can't use this class with ASTCBlock because then it would need to | |
502 // handle multi-value ranges, and it's non-trivial to lookup a range of bits | |
503 // that splits across two different ints. | |
504 template <typename T> | |
505 class SkTBits { | |
506 public: | |
507 SkTBits(const T val) : fVal(val) { } | |
508 | |
509 // Returns the bit at the given position | |
510 T operator [](const int idx) const { | |
511 return (fVal >> idx) & 1; | |
512 } | |
513 | |
514 // Returns the bits in the given range, inclusive | |
515 T operator ()(const int end, const int start) const { | |
516 SkASSERT(end >= start); | |
517 return (fVal >> start) & ((1ULL << ((end - start) + 1)) - 1); | |
518 } | |
519 | |
520 private: | |
521 const T fVal; | |
522 }; | |
523 | |
524 // This algorithm matches the trit block decoding in the spec (Table C.2.14) | |
525 static void decode_trit_block(int* dst, int nBits, const uint64_t &block) { | |
526 | |
527 SkTBits<uint64_t> blockBits(block); | |
528 | |
529 // According to the spec, a trit block, which contains five values, | |
530 // has the following layout: | |
531 // | |
532 // 27 26 25 24 23 22 21 20 19 18 17 16 | |
533 // ----------------------------------------------- | |
534 // |T7 | m4 |T6 T5 | m3 |T4 | | |
535 // ----------------------------------------------- | |
536 // | |
537 // 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 | |
538 // -------------------------------------------------------------- | |
539 // | m2 |T3 T2 | m1 |T1 T0 | m0 | | |
540 // -------------------------------------------------------------- | |
541 // | |
542 // Where the m's are variable width depending on the number of bits used | |
543 // to encode the values (anywhere from 0 to 6). Since 3^5 = 243, the extra | |
544 // byte labeled T (whose bits are interleaved where 0 is the LSB and 7 is | |
545 // the MSB), contains five trit values. To decode the trit values, the spec | |
546 // says that we need to follow the following algorithm: | |
547 // | |
548 // if T[4:2] = 111 | |
549 // C = { T[7:5], T[1:0] }; t4 = t3 = 2 | |
550 // else | |
551 // C = T[4:0] | |
552 // | |
553 // if T[6:5] = 11 | |
554 // t4 = 2; t3 = T[7] | |
555 // else | |
556 // t4 = T[7]; t3 = T[6:5] | |
557 // | |
558 // if C[1:0] = 11 | |
559 // t2 = 2; t1 = C[4]; t0 = { C[3], C[2]&~C[3] } | |
560 // else if C[3:2] = 11 | |
561 // t2 = 2; t1 = 2; t0 = C[1:0] | |
562 // else | |
563 // t2 = C[4]; t1 = C[3:2]; t0 = { C[1], C[0]&~C[1] } | |
564 // | |
565 // The following C++ code is meant to mirror this layout and algorithm as | |
566 // closely as possible. | |
567 | |
568 int m[5]; | |
569 if (0 == nBits) { | |
570 memset(m, 0, sizeof(m)); | |
571 } else { | |
572 m[0] = blockBits(nBits - 1, 0); | |
573 m[1] = blockBits(2*nBits - 1 + 2, nBits + 2); | |
574 m[2] = blockBits(3*nBits - 1 + 4, 2*nBits + 4); | |
575 m[3] = blockBits(4*nBits - 1 + 5, 3*nBits + 5); | |
576 m[4] = blockBits(5*nBits - 1 + 7, 4*nBits + 7); | |
577 } | |
578 | |
579 int T = | |
580 blockBits(nBits + 1, nBits) | | |
581 (blockBits(2*nBits + 2 + 1, 2*nBits + 2) << 2) | | |
582 (blockBits[3*nBits + 4] << 4) | | |
583 (blockBits(4*nBits + 5 + 1, 4*nBits + 5) << 5) | | |
584 (blockBits[5*nBits + 7] << 7); | |
585 | |
586 int t[5]; | |
587 | |
588 int C; | |
589 SkTBits<int> Tbits(T); | |
590 if (0x7 == Tbits(4, 2)) { | |
591 C = (Tbits(7, 5) << 2) | Tbits(1, 0); | |
592 t[3] = t[4] = 2; | |
593 } else { | |
594 C = Tbits(4, 0); | |
595 if (Tbits(6, 5) == 0x3) { | |
596 t[4] = 2; t[3] = Tbits[7]; | |
597 } else { | |
598 t[4] = Tbits[7]; t[3] = Tbits(6, 5); | |
599 } | |
600 } | |
601 | |
602 SkTBits<int> Cbits(C); | |
603 if (Cbits(1, 0) == 0x3) { | |
604 t[2] = 2; | |
605 t[1] = Cbits[4]; | |
606 t[0] = (Cbits[3] << 1) | (Cbits[2] & (0x1 & ~(Cbits[3]))); | |
607 } else if (Cbits(3, 2) == 0x3) { | |
608 t[2] = 2; | |
609 t[1] = 2; | |
610 t[0] = Cbits(1, 0); | |
611 } else { | |
612 t[2] = Cbits[4]; | |
613 t[1] = Cbits(3, 2); | |
614 t[0] = (Cbits[1] << 1) | (Cbits[0] & (0x1 & ~(Cbits[1]))); | |
615 } | |
616 | |
617 #if SK_DEBUG | |
618 // Make sure all of the decoded values have a trit less than three | |
619 // and a bit value within the range of the allocated bits. | |
620 for (int i = 0; i < 5; ++i) { | |
621 SkASSERT(t[i] < 3); | |
622 SkASSERT(m[i] < (1 << nBits)); | |
623 } | |
624 #endif | |
625 | |
626 for (int i = 0; i < 5; ++i) { | |
627 *dst = (t[i] << nBits) + m[i]; | |
628 ++dst; | |
629 } | |
630 } | |
631 | |
632 // This algorithm matches the quint block decoding in the spec (Table C.2.15) | |
633 static void decode_quint_block(int* dst, int nBits, const uint64_t &block) { | |
634 SkTBits<uint64_t> blockBits(block); | |
635 | |
636 // According to the spec, a quint block, which contains three values, | |
637 // has the following layout: | |
638 // | |
639 // | |
640 // 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 | |
641 // ------------------------------------------------------------------------ -- | |
642 // |Q6 Q5 | m2 |Q4 Q3 | m1 |Q2 Q1 Q0 | m0 | | |
643 // ------------------------------------------------------------------------ -- | |
644 // | |
645 // Where the m's are variable width depending on the number of bits used | |
646 // to encode the values (anywhere from 0 to 4). Since 5^3 = 125, the extra | |
647 // 7-bit value labeled Q (whose bits are interleaved where 0 is the LSB and 6 is | |
648 // the MSB), contains three quint values. To decode the quint values, the sp ec | |
649 // says that we need to follow the following algorithm: | |
650 // | |
651 // if Q[2:1] = 11 and Q[6:5] = 00 | |
652 // q2 = { Q[0], Q[4]&~Q[0], Q[3]&~Q[0] }; q1 = q0 = 4 | |
653 // else | |
654 // if Q[2:1] = 11 | |
655 // q2 = 4; C = { Q[4:3], ~Q[6:5], Q[0] } | |
656 // else | |
657 // q2 = T[6:5]; C = Q[4:0] | |
658 // | |
659 // if C[2:0] = 101 | |
660 // q1 = 4; q0 = C[4:3] | |
661 // else | |
662 // q1 = C[4:3]; q0 = C[2:0] | |
663 // | |
664 // The following C++ code is meant to mirror this layout and algorithm as | |
665 // closely as possible. | |
666 | |
667 int m[3]; | |
668 if (0 == nBits) { | |
669 memset(m, 0, sizeof(m)); | |
670 } else { | |
671 m[0] = blockBits(nBits - 1, 0); | |
672 m[1] = blockBits(2*nBits - 1 + 3, nBits + 3); | |
673 m[2] = blockBits(3*nBits - 1 + 5, 2*nBits + 5); | |
674 } | |
675 | |
676 int Q = | |
677 blockBits(nBits + 2, nBits) | | |
678 (blockBits(2*nBits + 3 + 1, 2*nBits + 3) << 3) | | |
679 (blockBits(3*nBits + 5 + 1, 3*nBits + 5) << 5); | |
680 | |
681 int q[3]; | |
682 SkTBits<int> Qbits(Q); // quantum? | |
683 | |
684 if (Qbits(2, 1) == 0x3 && Qbits(6, 5) == 0) { | |
685 const int notBitZero = (0x1 & ~(Qbits[0])); | |
686 q[2] = (Qbits[0] << 2) | ((Qbits[4] & notBitZero) << 1) | (Qbits[3] & no tBitZero); | |
687 q[1] = 4; | |
688 q[0] = 4; | |
689 } else { | |
690 int C; | |
691 if (Qbits(2, 1) == 0x3) { | |
692 q[2] = 4; | |
693 C = (Qbits(4, 3) << 3) | ((0x3 & ~(Qbits(6, 5))) << 1) | Qbits[0]; | |
694 } else { | |
695 q[2] = Qbits(6, 5); | |
696 C = Qbits(4, 0); | |
697 } | |
698 | |
699 SkTBits<int> Cbits(C); | |
700 if (Cbits(2, 0) == 0x5) { | |
701 q[1] = 4; | |
702 q[0] = Cbits(4, 3); | |
703 } else { | |
704 q[1] = Cbits(4, 3); | |
705 q[0] = Cbits(2, 0); | |
706 } | |
707 } | |
708 | |
709 #if SK_DEBUG | |
710 for (int i = 0; i < 3; ++i) { | |
711 SkASSERT(q[i] < 5); | |
712 SkASSERT(m[i] < (1 << nBits)); | |
713 } | |
714 #endif | |
715 | |
716 for (int i = 0; i < 3; ++i) { | |
717 *dst = (q[i] << nBits) + m[i]; | |
718 ++dst; | |
719 } | |
720 } | |
721 | |
722 // Function that decodes a sequence of integers stored as an ISE (Integer | |
723 // Sequence Encoding) bit stream. The full details of this function are outlined | |
724 // in section C.2.12 of the ASTC spec. A brief overview is as follows: | |
725 // | |
726 // - Each integer in the sequence is bounded by a specific range r. | |
727 // - The range of each value determines the way the bit stream is interpreted, | |
728 // - If the range is a power of two, then the sequence is a sequence of bits | |
729 // - If the range is of the form 3*2^n, then the sequence is stored as a | |
730 // sequence of blocks, each block contains 5 trits and 5 bit sequences, which | |
731 // decodes into 5 values. | |
732 // - Similarly, if the range is of the form 5*2^n, then the sequence is stored a s a | |
733 // sequence of blocks, each block contains 3 quints and 3 bit sequences, which | |
734 // decodes into 3 values. | |
735 static bool decode_integer_sequence( | |
736 int* dst, // The array holding the destination bits | |
737 int dstSize, // The maximum size of the array | |
738 int nVals, // The number of values that we'd like to decode | |
739 const ASTCBlock &block, // The block that we're decoding from | |
740 int startBit, // The bit from which we're going to do the readin g | |
741 int endBit, // The bit at which we stop reading (not inclusive ) | |
742 bool bReadForward, // If true, then read LSB -> MSB, else read MSB -> LSB | |
743 int nBits, // The number of bits representing this encoding | |
744 int nTrits, // The number of trits representing this encoding | |
745 int nQuints // The number of quints representing this encoding | |
746 ) { | |
747 // If we want more values than we have, then fail. | |
748 if (nVals > dstSize) { | |
749 return false; | |
750 } | |
751 | |
752 ASTCBlock src = block; | |
753 | |
754 if (!bReadForward) { | |
755 src.Reverse(); | |
756 startBit = 128 - startBit; | |
757 endBit = 128 - endBit; | |
758 } | |
759 | |
760 while (nVals > 0) { | |
761 | |
762 if (nTrits > 0) { | |
763 SkASSERT(0 == nQuints); | |
764 | |
765 int endBlockBit = startBit + 8 + 5*nBits; | |
766 if (endBlockBit > endBit) { | |
767 endBlockBit = endBit; | |
768 } | |
769 | |
770 decode_trit_block(dst, nBits, read_astc_bits(src, startBit, endBlock Bit)); | |
771 dst += 5; | |
772 nVals -= 5; | |
773 startBit = endBlockBit; | |
774 | |
775 } else if (nQuints > 0) { | |
776 SkASSERT(0 == nTrits); | |
777 | |
778 int endBlockBit = startBit + 7 + 3*nBits; | |
779 if (endBlockBit > endBit) { | |
780 endBlockBit = endBit; | |
781 } | |
782 | |
783 decode_quint_block(dst, nBits, read_astc_bits(src, startBit, endBloc kBit)); | |
784 dst += 3; | |
785 nVals -= 3; | |
786 startBit = endBlockBit; | |
787 | |
788 } else { | |
789 // Just read the bits, but don't read more than we have... | |
790 int endValBit = startBit + nBits; | |
791 if (endValBit > endBit) { | |
792 endValBit = endBit; | |
793 } | |
794 | |
795 *dst = read_astc_bits(src, startBit, endValBit); | |
796 ++dst; | |
797 --nVals; | |
798 startBit = endValBit; | |
799 } | |
800 } | |
801 | |
802 return true; | |
803 } | |
804 | |
805 // Helper function that unquantizes some (seemingly random) generated | |
806 // numbers... meant to match the ASTC hardware. This function is used | |
807 // to unquantize both colors (Table C.2.16) and weights (Table C.2.26) | |
808 static inline int unquantize_value(unsigned mask, int A, int B, int C, int D) { | |
809 int T = D * C + B; | |
810 T = T ^ A; | |
811 T = (A & mask) | (T >> 2); | |
812 SkASSERT(T < 256); | |
813 return T; | |
814 } | |
815 | |
816 // Helper function to replicate the bits in x that represents an oldPrec | |
817 // precision integer into a prec precision integer. For example: | |
818 // 255 == replicate_bits(7, 3, 8); | |
819 static inline int replicate_bits(int x, int oldPrec, int prec) { | |
820 while (oldPrec < prec) { | |
821 const int toShift = SkMin32(prec-oldPrec, oldPrec); | |
822 x = (x << toShift) | (x >> (oldPrec - toShift)); | |
823 oldPrec += toShift; | |
824 } | |
825 | |
826 // Make sure that no bits are set outside the desired precision. | |
827 SkASSERT((-(1 << prec) & x) == 0); | |
828 return x; | |
829 } | |
830 | |
831 // Returns the unquantized value of a color that's represented only as | |
832 // a set of bits. | |
833 static inline int unquantize_bits_color(int val, int nBits) { | |
834 return replicate_bits(val, nBits, 8); | |
835 } | |
836 | |
837 // Returns the unquantized value of a color that's represented as a | |
838 // trit followed by nBits bits. This algorithm follows the sequence | |
839 // defined in section C.2.13 of the ASTC spec. | |
840 static inline int unquantize_trit_color(int val, int nBits) { | |
841 SkASSERT(nBits > 0); | |
842 SkASSERT(nBits < 7); | |
843 | |
844 const int D = (val >> nBits) & 0x3; | |
845 SkASSERT(D < 3); | |
846 | |
847 const int A = -(val & 0x1) & 0x1FF; | |
848 | |
849 static const int Cvals[6] = { 204, 93, 44, 22, 11, 5 }; | |
850 const int C = Cvals[nBits - 1]; | |
851 | |
852 int B = 0; | |
853 const SkTBits<int> valBits(val); | |
854 switch (nBits) { | |
855 case 1: | |
856 B = 0; | |
857 break; | |
858 | |
859 case 2: { | |
860 const int b = valBits[1]; | |
861 B = (b << 1) | (b << 2) | (b << 4) | (b << 8); | |
862 } | |
863 break; | |
864 | |
865 case 3: { | |
866 const int cb = valBits(2, 1); | |
867 B = cb | (cb << 2) | (cb << 7); | |
868 } | |
869 break; | |
870 | |
871 case 4: { | |
872 const int dcb = valBits(3, 1); | |
873 B = dcb | (dcb << 6); | |
874 } | |
875 break; | |
876 | |
877 case 5: { | |
878 const int edcb = valBits(4, 1); | |
879 B = (edcb << 5) | (edcb >> 2); | |
880 } | |
881 break; | |
882 | |
883 case 6: { | |
884 const int fedcb = valBits(5, 1); | |
885 B = (fedcb << 4) | (fedcb >> 4); | |
886 } | |
887 break; | |
888 } | |
889 | |
890 return unquantize_value(0x80, A, B, C, D); | |
891 } | |
892 | |
893 // Returns the unquantized value of a color that's represented as a | |
894 // quint followed by nBits bits. This algorithm follows the sequence | |
895 // defined in section C.2.13 of the ASTC spec. | |
896 static inline int unquantize_quint_color(int val, int nBits) { | |
897 const int D = (val >> nBits) & 0x7; | |
898 SkASSERT(D < 5); | |
899 | |
900 const int A = -(val & 0x1) & 0x1FF; | |
901 | |
902 static const int Cvals[5] = { 113, 54, 26, 13, 6 }; | |
903 SkASSERT(nBits > 0); | |
904 SkASSERT(nBits < 6); | |
905 | |
906 const int C = Cvals[nBits - 1]; | |
907 | |
908 int B = 0; | |
909 const SkTBits<int> valBits(val); | |
910 switch (nBits) { | |
911 case 1: | |
912 B = 0; | |
913 break; | |
914 | |
915 case 2: { | |
916 const int b = valBits[1]; | |
917 B = (b << 2) | (b << 3) | (b << 8); | |
918 } | |
919 break; | |
920 | |
921 case 3: { | |
922 const int cb = valBits(2, 1); | |
923 B = (cb >> 1) | (cb << 1) | (cb << 7); | |
924 } | |
925 break; | |
926 | |
927 case 4: { | |
928 const int dcb = valBits(3, 1); | |
929 B = (dcb >> 1) | (dcb << 6); | |
930 } | |
931 break; | |
932 | |
933 case 5: { | |
934 const int edcb = valBits(4, 1); | |
935 B = (edcb << 5) | (edcb >> 3); | |
936 } | |
937 break; | |
938 } | |
939 | |
940 return unquantize_value(0x80, A, B, C, D); | |
941 } | |
942 | |
943 // This algorithm takes a list of integers, stored in vals, and unquantizes them | |
944 // in place. This follows the algorithm laid out in section C.2.13 of the ASTC s pec. | |
945 static void unquantize_colors(int *vals, int nVals, int nBits, int nTrits, int n Quints) { | |
946 for (int i = 0; i < nVals; ++i) { | |
947 if (nTrits > 0) { | |
948 SkASSERT(nQuints == 0); | |
949 vals[i] = unquantize_trit_color(vals[i], nBits); | |
950 } else if (nQuints > 0) { | |
951 SkASSERT(nTrits == 0); | |
952 vals[i] = unquantize_quint_color(vals[i], nBits); | |
953 } else { | |
954 SkASSERT(nQuints == 0 && nTrits == 0); | |
955 vals[i] = unquantize_bits_color(vals[i], nBits); | |
956 } | |
957 } | |
958 } | |
959 | |
960 // Returns an interpolated value between c0 and c1 based on the weight. This | |
961 // follows the algorithm laid out in section C.2.19 of the ASTC spec. | |
962 static int interpolate_channel(int c0, int c1, int weight) { | |
963 SkASSERT(0 <= c0 && c0 < 256); | |
964 SkASSERT(0 <= c1 && c1 < 256); | |
965 | |
966 c0 = (c0 << 8) | c0; | |
967 c1 = (c1 << 8) | c1; | |
968 | |
969 const int result = ((c0*(64 - weight) + c1*weight + 32) / 64) >> 8; | |
970 | |
971 if (result > 255) { | |
972 return 255; | |
973 } | |
974 | |
975 SkASSERT(result >= 0); | |
976 return result; | |
977 } | |
978 | |
979 // Returns an interpolated color between the two endpoints based on the weight. | |
980 static SkColor interpolate_endpoints(const SkColor endpoints[2], int weight) { | |
981 return SkColorSetARGB( | |
982 interpolate_channel(SkColorGetA(endpoints[0]), SkColorGetA(endpoints[1]) , weight), | |
983 interpolate_channel(SkColorGetR(endpoints[0]), SkColorGetR(endpoints[1]) , weight), | |
984 interpolate_channel(SkColorGetG(endpoints[0]), SkColorGetG(endpoints[1]) , weight), | |
985 interpolate_channel(SkColorGetB(endpoints[0]), SkColorGetB(endpoints[1]) , weight)); | |
986 } | |
987 | |
988 // Returns an interpolated color between the two endpoints based on the weight. | |
989 // It uses separate weights for the channel depending on the value of the 'plane ' | |
990 // variable. By default, all channels will use weight 0, and the value of plane | |
991 // means that weight1 will be used for: | |
992 // 0: red | |
993 // 1: green | |
994 // 2: blue | |
995 // 3: alpha | |
996 static SkColor interpolate_dual_endpoints( | |
997 const SkColor endpoints[2], int weight0, int weight1, int plane) { | |
998 int a = interpolate_channel(SkColorGetA(endpoints[0]), SkColorGetA(endpoints [1]), weight0); | |
999 int r = interpolate_channel(SkColorGetR(endpoints[0]), SkColorGetR(endpoints [1]), weight0); | |
1000 int g = interpolate_channel(SkColorGetG(endpoints[0]), SkColorGetG(endpoints [1]), weight0); | |
1001 int b = interpolate_channel(SkColorGetB(endpoints[0]), SkColorGetB(endpoints [1]), weight0); | |
1002 | |
1003 switch (plane) { | |
1004 | |
1005 case 0: | |
1006 r = interpolate_channel( | |
1007 SkColorGetR(endpoints[0]), SkColorGetR(endpoints[1]), weight1); | |
1008 break; | |
1009 | |
1010 case 1: | |
1011 g = interpolate_channel( | |
1012 SkColorGetG(endpoints[0]), SkColorGetG(endpoints[1]), weight1); | |
1013 break; | |
1014 | |
1015 case 2: | |
1016 b = interpolate_channel( | |
1017 SkColorGetB(endpoints[0]), SkColorGetB(endpoints[1]), weight1); | |
1018 break; | |
1019 | |
1020 case 3: | |
1021 a = interpolate_channel( | |
1022 SkColorGetA(endpoints[0]), SkColorGetA(endpoints[1]), weight1); | |
1023 break; | |
1024 | |
1025 default: | |
1026 SkDEBUGFAIL("Plane should be 0-3"); | |
1027 break; | |
1028 } | |
1029 | |
1030 return SkColorSetARGB(a, r, g, b); | |
1031 } | |
1032 | |
1033 // A struct of decoded values that we use to carry around information | |
1034 // about the block. dimX and dimY are the dimension in texels of the block, | |
1035 // for which there is only a limited subset of valid values: | |
1036 // | |
1037 // 4x4, 5x4, 5x5, 6x5, 6x6, 8x5, 8x6, 8x8, 10x5, 10x6, 10x8, 10x10, 12x10, 12x12 | |
1038 | |
1039 struct ASTCDecompressionData { | |
1040 ASTCDecompressionData(int dimX, int dimY) : fDimX(dimX), fDimY(dimY) { } | |
1041 const int fDimX; // the X dimension of the decompressed block | |
1042 const int fDimY; // the Y dimension of the decompressed block | |
1043 ASTCBlock fBlock; // the block data | |
1044 int fBlockMode; // the block header that contains the block mode. | |
1045 | |
1046 bool fDualPlaneEnabled; // is this block compressing dual weight planes? | |
1047 int fDualPlane; // the independent plane in dual plane mode. | |
1048 | |
1049 bool fVoidExtent; // is this block a single color? | |
1050 bool fError; // does this block have an error encoding? | |
1051 | |
1052 int fWeightDimX; // the x dimension of the weight grid | |
1053 int fWeightDimY; // the y dimension of the weight grid | |
1054 | |
1055 int fWeightBits; // the number of bits used for each weight value | |
1056 int fWeightTrits; // the number of trits used for each weight value | |
1057 int fWeightQuints; // the number of quints used for each weight value | |
1058 | |
1059 int fPartCount; // the number of partitions in this block | |
1060 int fPartIndex; // the partition index: only relevant if fPartCount > 0 | |
1061 | |
1062 // CEM values can be anything in the range 0-15, and each corresponds to a d ifferent | |
1063 // mode that represents the color data. We only support LDR modes. | |
1064 enum ColorEndpointMode { | |
1065 kLDR_Luminance_Direct_ColorEndpointMode = 0, | |
1066 kLDR_Luminance_BaseOffset_ColorEndpointMode = 1, | |
1067 kHDR_Luminance_LargeRange_ColorEndpointMode = 2, | |
1068 kHDR_Luminance_SmallRange_ColorEndpointMode = 3, | |
1069 kLDR_LuminanceAlpha_Direct_ColorEndpointMode = 4, | |
1070 kLDR_LuminanceAlpha_BaseOffset_ColorEndpointMode = 5, | |
1071 kLDR_RGB_BaseScale_ColorEndpointMode = 6, | |
1072 kHDR_RGB_BaseScale_ColorEndpointMode = 7, | |
1073 kLDR_RGB_Direct_ColorEndpointMode = 8, | |
1074 kLDR_RGB_BaseOffset_ColorEndpointMode = 9, | |
1075 kLDR_RGB_BaseScaleWithAlpha_ColorEndpointMode = 10, | |
1076 kHDR_RGB_ColorEndpointMode = 11, | |
1077 kLDR_RGBA_Direct_ColorEndpointMode = 12, | |
1078 kLDR_RGBA_BaseOffset_ColorEndpointMode = 13, | |
1079 kHDR_RGB_LDRAlpha_ColorEndpointMode = 14, | |
1080 kHDR_RGB_HDRAlpha_ColorEndpointMode = 15 | |
1081 }; | |
1082 static const int kMaxColorEndpointModes = 16; | |
1083 | |
1084 // the color endpoint modes for this block. | |
1085 static const int kMaxPartitions = 4; | |
1086 ColorEndpointMode fCEM[kMaxPartitions]; | |
1087 | |
1088 int fColorStartBit; // The bit position of the first bit of the color da ta | |
1089 int fColorEndBit; // The bit position of the last *possible* bit of th e color data | |
1090 | |
1091 // Returns the number of partitions for this block. | |
1092 int numPartitions() const { | |
1093 return fPartCount; | |
1094 } | |
1095 | |
1096 // Returns the total number of weight values that are stored in this block | |
1097 int numWeights() const { | |
1098 return fWeightDimX * fWeightDimY * (fDualPlaneEnabled ? 2 : 1); | |
1099 } | |
1100 | |
1101 #ifdef SK_DEBUG | |
1102 // Returns the maximum value that any weight can take. We really only use | |
1103 // this function for debugging. | |
1104 int maxWeightValue() const { | |
1105 int maxVal = (1 << fWeightBits); | |
1106 if (fWeightTrits > 0) { | |
1107 SkASSERT(0 == fWeightQuints); | |
1108 maxVal *= 3; | |
1109 } else if (fWeightQuints > 0) { | |
1110 SkASSERT(0 == fWeightTrits); | |
1111 maxVal *= 5; | |
1112 } | |
1113 return maxVal - 1; | |
1114 } | |
1115 #endif | |
1116 | |
1117 // The number of bits needed to represent the texel weight data. This | |
1118 // comes from the 'data size determination' section of the ASTC spec (C.2.22 ) | |
1119 int numWeightBits() const { | |
1120 const int nWeights = this->numWeights(); | |
1121 return | |
1122 ((nWeights*8*fWeightTrits + 4) / 5) + | |
1123 ((nWeights*7*fWeightQuints + 2) / 3) + | |
1124 (nWeights*fWeightBits); | |
1125 } | |
1126 | |
1127 // Returns the number of color values stored in this block. The number of | |
1128 // values stored is directly a function of the color endpoint modes. | |
1129 int numColorValues() const { | |
1130 int numValues = 0; | |
1131 for (int i = 0; i < this->numPartitions(); ++i) { | |
1132 int cemInt = static_cast<int>(fCEM[i]); | |
1133 numValues += ((cemInt >> 2) + 1) * 2; | |
1134 } | |
1135 | |
1136 return numValues; | |
1137 } | |
1138 | |
1139 // Figures out the number of bits available for color values, and fills | |
1140 // in the maximum encoding that will fit the number of color values that | |
1141 // we need. Returns false on error. (See section C.2.22 of the spec) | |
1142 bool getColorValueEncoding(int *nBits, int *nTrits, int *nQuints) const { | |
1143 if (NULL == nBits || NULL == nTrits || NULL == nQuints) { | |
1144 return false; | |
1145 } | |
1146 | |
1147 const int nColorVals = this->numColorValues(); | |
1148 if (nColorVals <= 0) { | |
1149 return false; | |
1150 } | |
1151 | |
1152 const int colorBits = fColorEndBit - fColorStartBit; | |
1153 SkASSERT(colorBits > 0); | |
1154 | |
1155 // This is the minimum amount of accuracy required by the spec. | |
1156 if (colorBits < ((13 * nColorVals + 4) / 5)) { | |
1157 return false; | |
1158 } | |
1159 | |
1160 // Values can be represented as at most 8-bit values. | |
1161 // !SPEED! place this in a lookup table based on colorBits and nColorVal s | |
1162 for (int i = 255; i > 0; --i) { | |
1163 int range = i + 1; | |
1164 int bits = 0, trits = 0, quints = 0; | |
1165 bool valid = false; | |
1166 if (SkIsPow2(range)) { | |
1167 bits = bits_for_range(range); | |
1168 valid = true; | |
1169 } else if ((range % 3) == 0 && SkIsPow2(range/3)) { | |
1170 trits = 1; | |
1171 bits = bits_for_range(range/3); | |
1172 valid = true; | |
1173 } else if ((range % 5) == 0 && SkIsPow2(range/5)) { | |
1174 quints = 1; | |
1175 bits = bits_for_range(range/5); | |
1176 valid = true; | |
1177 } | |
1178 | |
1179 if (valid) { | |
1180 const int actualColorBits = | |
1181 ((nColorVals*8*trits + 4) / 5) + | |
1182 ((nColorVals*7*quints + 2) / 3) + | |
1183 (nColorVals*bits); | |
1184 if (actualColorBits <= colorBits) { | |
1185 *nTrits = trits; | |
1186 *nQuints = quints; | |
1187 *nBits = bits; | |
1188 return true; | |
1189 } | |
1190 } | |
1191 } | |
1192 | |
1193 return false; | |
1194 } | |
1195 | |
1196 // Converts the sequence of color values into endpoints. The algorithm here | |
1197 // corresponds to the values determined by section C.2.14 of the ASTC spec | |
1198 void colorEndpoints(SkColor endpoints[4][2], const int* colorValues) const { | |
1199 for (int i = 0; i < this->numPartitions(); ++i) { | |
1200 switch (fCEM[i]) { | |
robertphillips
2014/08/06 17:24:20
Share subroutine with kLDR_LuminanceAlpha_Direct_C
krajcevski
2014/08/06 18:14:30
This will probably create more upkeep than it save
| |
1201 case kLDR_Luminance_Direct_ColorEndpointMode: { | |
1202 const int* v = colorValues; | |
1203 endpoints[i][0] = SkColorSetARGB(0xFF, v[0], v[0], v[0]); | |
1204 endpoints[i][1] = SkColorSetARGB(0xFF, v[1], v[1], v[1]); | |
1205 | |
1206 colorValues += 2; | |
1207 } | |
1208 break; | |
1209 | |
1210 case kLDR_Luminance_BaseOffset_ColorEndpointMode: { | |
1211 const int* v = colorValues; | |
1212 const int L0 = (v[0] >> 2) | (v[1] & 0xC0); | |
1213 const int L1 = clamp_byte(L0 + (v[1] & 0x3F)); | |
1214 | |
1215 endpoints[i][0] = SkColorSetARGB(0xFF, L0, L0, L0); | |
1216 endpoints[i][1] = SkColorSetARGB(0xFF, L1, L1, L1); | |
1217 | |
1218 colorValues += 2; | |
1219 } | |
1220 break; | |
1221 | |
1222 case kLDR_LuminanceAlpha_Direct_ColorEndpointMode: { | |
1223 const int* v = colorValues; | |
1224 | |
1225 endpoints[i][0] = SkColorSetARGB(v[2], v[0], v[0], v[0]); | |
1226 endpoints[i][1] = SkColorSetARGB(v[3], v[1], v[1], v[1]); | |
1227 | |
1228 colorValues += 4; | |
1229 } | |
1230 break; | |
1231 | |
1232 case kLDR_LuminanceAlpha_BaseOffset_ColorEndpointMode: { | |
1233 int v0 = colorValues[0]; | |
1234 int v1 = colorValues[1]; | |
1235 int v2 = colorValues[2]; | |
1236 int v3 = colorValues[3]; | |
1237 | |
1238 bit_transfer_signed(&v1, &v0); | |
1239 bit_transfer_signed(&v3, &v2); | |
1240 | |
1241 endpoints[i][0] = SkColorSetARGB(v2, v0, v0, v0); | |
1242 endpoints[i][1] = SkColorSetARGB( | |
1243 clamp_byte(v3+v2), | |
1244 clamp_byte(v1+v0), | |
1245 clamp_byte(v1+v0), | |
1246 clamp_byte(v1+v0)); | |
1247 | |
1248 colorValues += 4; | |
1249 } | |
1250 break; | |
1251 | |
robertphillips
2014/08/06 17:24:21
Share subroutine with kLDR_RGB_BaseScaleWithAlpha_
krajcevski
2014/08/06 18:14:30
Done.
| |
1252 case kLDR_RGB_BaseScale_ColorEndpointMode: { | |
1253 const int* v = colorValues; | |
1254 | |
1255 endpoints[i][0] = SkColorSetARGB( | |
1256 0xFF, v[0]*v[3] >> 8, v[1]*v[3] >> 8, v[2]*v[3] >> 8); | |
1257 endpoints[i][1] = SkColorSetARGB(0xFF, v[0], v[1], v[2]); | |
1258 | |
1259 colorValues += 4; | |
1260 } | |
1261 break; | |
1262 | |
1263 case kLDR_RGB_Direct_ColorEndpointMode: { | |
1264 decode_rgba_direct(colorValues, endpoints[i], true); | |
1265 colorValues += 6; | |
1266 } | |
1267 break; | |
1268 | |
1269 case kLDR_RGB_BaseOffset_ColorEndpointMode: { | |
1270 decode_rgba_baseoffset(colorValues, endpoints[i], true); | |
1271 colorValues += 6; | |
1272 } | |
1273 break; | |
1274 | |
1275 case kLDR_RGB_BaseScaleWithAlpha_ColorEndpointMode: { | |
1276 const int* v = colorValues; | |
1277 | |
1278 endpoints[i][0] = SkColorSetARGB(v[4], | |
1279 (v[0]*v[3]) >> 8, | |
1280 (v[1]*v[3]) >> 8, | |
1281 (v[2]*v[3]) >> 8); | |
1282 endpoints[i][1] = SkColorSetARGB(v[5], v[0], v[1], v[2]); | |
1283 | |
1284 colorValues += 6; | |
1285 } | |
1286 break; | |
1287 | |
1288 case kLDR_RGBA_Direct_ColorEndpointMode: { | |
1289 decode_rgba_direct(colorValues, endpoints[i], false); | |
1290 colorValues += 8; | |
1291 } | |
1292 break; | |
1293 | |
1294 case kLDR_RGBA_BaseOffset_ColorEndpointMode: { | |
1295 decode_rgba_baseoffset(colorValues, endpoints[i], false); | |
1296 colorValues += 8; | |
1297 } | |
1298 break; | |
1299 | |
1300 default: | |
1301 SkDEBUGFAIL("HDR mode unsupported! This should be caught soo ner."); | |
1302 break; | |
1303 } | |
1304 } | |
1305 } | |
1306 | |
1307 // Follows the procedure from section C.2.17 of the ASTC specification | |
1308 int unquantizeWeight(int x) const { | |
1309 SkASSERT(x <= this->maxWeightValue()); | |
1310 | |
1311 const int D = (x >> fWeightBits) & 0x7; | |
1312 const int A = -(x & 0x1) & 0x7F; | |
1313 | |
1314 SkTBits<int> xbits(x); | |
1315 | |
1316 int T = 0; | |
1317 if (fWeightTrits > 0) { | |
1318 SkASSERT(0 == fWeightQuints); | |
1319 switch (fWeightBits) { | |
1320 case 0: { | |
1321 // x is a single trit | |
1322 SkASSERT(x < 3); | |
1323 | |
1324 static const int kUnquantizationTable[3] = { 0, 32, 63 }; | |
1325 T = kUnquantizationTable[x]; | |
1326 } | |
1327 break; | |
1328 | |
1329 case 1: { | |
1330 const int B = 0; | |
1331 const int C = 50; | |
1332 T = unquantize_value(0x20, A, B, C, D); | |
1333 } | |
1334 break; | |
1335 | |
1336 case 2: { | |
1337 const int b = xbits[1]; | |
1338 const int B = b | (b << 2) | (b << 6); | |
1339 const int C = 23; | |
1340 T = unquantize_value(0x20, A, B, C, D); | |
1341 } | |
1342 break; | |
1343 | |
1344 case 3: { | |
1345 const int cb = xbits(2, 1); | |
1346 const int B = cb | (cb << 5); | |
1347 const int C = 11; | |
1348 T = unquantize_value(0x20, A, B, C, D); | |
1349 } | |
1350 break; | |
1351 | |
1352 default: | |
1353 SkDEBUGFAIL("Too many bits for trit encoding"); | |
1354 break; | |
1355 } | |
1356 | |
1357 } else if (fWeightQuints > 0) { | |
1358 SkASSERT(0 == fWeightTrits); | |
1359 switch (fWeightBits) { | |
1360 case 0: { | |
1361 // x is a single quint | |
1362 SkASSERT(x < 5); | |
1363 | |
1364 static const int kUnquantizationTable[5] = { 0, 16, 32, 47, 63 }; | |
1365 T = kUnquantizationTable[x]; | |
1366 } | |
1367 break; | |
1368 | |
1369 case 1: { | |
1370 const int B = 0; | |
1371 const int C = 28; | |
1372 T = unquantize_value(0x20, A, B, C, D); | |
1373 } | |
1374 break; | |
1375 | |
1376 case 2: { | |
1377 const int b = xbits[1]; | |
1378 const int B = (b << 1) | (b << 6); | |
1379 const int C = 13; | |
1380 T = unquantize_value(0x20, A, B, C, D); | |
1381 } | |
1382 break; | |
1383 | |
1384 default: | |
1385 SkDEBUGFAIL("Too many bits for quint encoding"); | |
1386 break; | |
1387 } | |
1388 } else { | |
1389 SkASSERT(0 == fWeightTrits); | |
1390 SkASSERT(0 == fWeightQuints); | |
1391 | |
1392 T = replicate_bits(x, fWeightBits, 6); | |
1393 } | |
1394 | |
1395 // This should bring the value within [0, 63].. | |
1396 SkASSERT(T <= 63); | |
1397 | |
1398 if (T > 32) { | |
1399 T += 1; | |
1400 } | |
1401 | |
1402 SkASSERT(T <= 64); | |
1403 | |
1404 return T; | |
1405 } | |
1406 | |
1407 // Returns the weight at the associated index. If the index is out of bounds , it | |
1408 // returns zero. It also chooses the weight appropriately based on the given dual | |
1409 // plane. | |
1410 int getWeight(const int* unquantizedWeights, int idx, bool dualPlane) const { | |
robertphillips
2014/08/06 17:24:21
Space before '?' ?
Do we need the parens around fD
krajcevski
2014/08/06 18:14:30
Done.
| |
1411 const int maxIdx = ((fDualPlaneEnabled)? 2 : 1) * fWeightDimX * fWeightD imY - 1; | |
1412 if (fDualPlaneEnabled) { | |
1413 const int effectiveIdx = 2*idx + (dualPlane ? 1 : 0); | |
1414 if (effectiveIdx > maxIdx) { | |
1415 return 0; | |
1416 } | |
1417 return unquantizedWeights[effectiveIdx]; | |
1418 } | |
1419 | |
1420 SkASSERT(!dualPlane); | |
1421 | |
1422 if (idx > maxIdx) { | |
1423 return 0; | |
1424 } else { | |
1425 return unquantizedWeights[idx]; | |
1426 } | |
1427 } | |
1428 | |
1429 // This computes the effective weight at location (s, t) of the block. This | |
1430 // weight is computed by sampling the texel weight grid (it's usually not 1- 1), and | |
1431 // then applying a bilerp. The algorithm outlined here follows the algorithm | |
1432 // defined in section C.2.18 of the ASTC spec. | |
1433 int infillWeight(const int* unquantizedValues, int s, int t, bool dualPlane) const { | |
1434 const int Ds = (1024 + fDimX/2) / (fDimX - 1); | |
1435 const int Dt = (1024 + fDimY/2) / (fDimY - 1); | |
1436 | |
1437 const int cs = Ds * s; | |
1438 const int ct = Dt * t; | |
1439 | |
1440 const int gs = (cs*(fWeightDimX - 1) + 32) >> 6; | |
1441 const int gt = (ct*(fWeightDimY - 1) + 32) >> 6; | |
1442 | |
1443 const int js = gs >> 4; | |
1444 const int jt = gt >> 4; | |
1445 | |
1446 const int fs = gs & 0xF; | |
1447 const int ft = gt & 0xF; | |
1448 | |
1449 const int idx = js + jt*fWeightDimX; | |
1450 const int p00 = this->getWeight(unquantizedValues, idx, dualPlane); | |
1451 const int p01 = this->getWeight(unquantizedValues, idx + 1, dualPlane); | |
1452 const int p10 = this->getWeight(unquantizedValues, idx + fWeightDimX, du alPlane); | |
1453 const int p11 = this->getWeight(unquantizedValues, idx + fWeightDimX + 1 , dualPlane); | |
1454 | |
1455 const int w11 = (fs*ft + 8) >> 4; | |
1456 const int w10 = ft - w11; | |
1457 const int w01 = fs - w11; | |
1458 const int w00 = 16 - fs - ft + w11; | |
1459 | |
1460 const int weight = (p00*w00 + p01*w01 + p10*w10 + p11*w11 + 8) >> 4; | |
1461 SkASSERT(weight <= 64); | |
1462 return weight; | |
1463 } | |
1464 | |
1465 // Unquantizes the decoded texel weights as described in section C.2.17 of | |
1466 // the ASTC specification. Additionally, it populates texelWeights with | |
1467 // the expanded weight grid, which is computed according to section C.2.18 | |
1468 void texelWeights(int texelWeights[2][12][12], const int* texelValues) const { | |
1469 // Unquantized texel weights... | |
1470 int unquantizedValues[144*2]; // 12x12 blocks with dual plane decoding.. . | |
1471 SkASSERT(this->numWeights() <= 144*2); | |
1472 | |
1473 // Unquantize the weights and cache them | |
1474 for (int j = 0; j < this->numWeights(); ++j) { | |
1475 unquantizedValues[j] = this->unquantizeWeight(texelValues[j]); | |
1476 } | |
1477 | |
1478 // Do weight infill... | |
1479 for (int y = 0; y < fDimY; ++y) { | |
1480 for (int x = 0; x < fDimX; ++x) { | |
1481 texelWeights[0][x][y] = this->infillWeight(unquantizedValues, x, y, false); | |
1482 if (fDualPlaneEnabled) { | |
1483 texelWeights[1][x][y] = this->infillWeight(unquantizedValues , x, y, true); | |
1484 } | |
1485 } | |
1486 } | |
1487 } | |
1488 | |
1489 // Returns the partition for the texel located at position (x, y). | |
1490 // Adapted from C.2.21 of the ASTC specification | |
1491 int getPartition(int x, int y) const { | |
1492 const int partitionCount = this->numPartitions(); | |
1493 int seed = fPartIndex; | |
1494 if ((fDimX * fDimY) < 31) { | |
1495 x <<= 1; | |
1496 y <<= 1; | |
1497 } | |
1498 | |
1499 seed += (partitionCount - 1) * 1024; | |
1500 | |
1501 uint32_t p = seed; | |
1502 p ^= p >> 15; p -= p << 17; p += p << 7; p += p << 4; | |
1503 p ^= p >> 5; p += p << 16; p ^= p >> 7; p ^= p >> 3; | |
1504 p ^= p << 6; p ^= p >> 17; | |
1505 | |
1506 uint32_t rnum = p; | |
1507 uint8_t seed1 = rnum & 0xF; | |
1508 uint8_t seed2 = (rnum >> 4) & 0xF; | |
1509 uint8_t seed3 = (rnum >> 8) & 0xF; | |
1510 uint8_t seed4 = (rnum >> 12) & 0xF; | |
1511 uint8_t seed5 = (rnum >> 16) & 0xF; | |
1512 uint8_t seed6 = (rnum >> 20) & 0xF; | |
1513 uint8_t seed7 = (rnum >> 24) & 0xF; | |
1514 uint8_t seed8 = (rnum >> 28) & 0xF; | |
1515 uint8_t seed9 = (rnum >> 18) & 0xF; | |
1516 uint8_t seed10 = (rnum >> 22) & 0xF; | |
1517 uint8_t seed11 = (rnum >> 26) & 0xF; | |
1518 uint8_t seed12 = ((rnum >> 30) | (rnum << 2)) & 0xF; | |
1519 | |
1520 seed1 *= seed1; seed2 *= seed2; | |
1521 seed3 *= seed3; seed4 *= seed4; | |
1522 seed5 *= seed5; seed6 *= seed6; | |
1523 seed7 *= seed7; seed8 *= seed8; | |
1524 seed9 *= seed9; seed10 *= seed10; | |
1525 seed11 *= seed11; seed12 *= seed12; | |
1526 | |
1527 int sh1, sh2, sh3; | |
1528 if (0 != (seed & 1)) { | |
1529 sh1 = (0 != (seed & 2))? 4 : 5; | |
1530 sh2 = (partitionCount == 3)? 6 : 5; | |
1531 } else { | |
1532 sh1 = (partitionCount==3)? 6 : 5; | |
1533 sh2 = (0 != (seed & 2))? 4 : 5; | |
1534 } | |
1535 sh3 = (0 != (seed & 0x10))? sh1 : sh2; | |
1536 | |
1537 seed1 >>= sh1; seed2 >>= sh2; seed3 >>= sh1; seed4 >>= sh2; | |
1538 seed5 >>= sh1; seed6 >>= sh2; seed7 >>= sh1; seed8 >>= sh2; | |
1539 seed9 >>= sh3; seed10 >>= sh3; seed11 >>= sh3; seed12 >>= sh3; | |
1540 | |
1541 const int z = 0; | |
1542 int a = seed1*x + seed2*y + seed11*z + (rnum >> 14); | |
1543 int b = seed3*x + seed4*y + seed12*z + (rnum >> 10); | |
1544 int c = seed5*x + seed6*y + seed9 *z + (rnum >> 6); | |
1545 int d = seed7*x + seed8*y + seed10*z + (rnum >> 2); | |
1546 | |
1547 a &= 0x3F; | |
1548 b &= 0x3F; | |
1549 c &= 0x3F; | |
1550 d &= 0x3F; | |
1551 | |
1552 if (partitionCount < 4) { | |
1553 d = 0; | |
1554 } | |
1555 | |
1556 if (partitionCount < 3) { | |
1557 c = 0; | |
1558 } | |
1559 | |
1560 if (a >= b && a >= c && a >= d) { | |
1561 return 0; | |
1562 } else if (b >= c && b >= d) { | |
1563 return 1; | |
1564 } else if (c >= d) { | |
1565 return 2; | |
1566 } else { | |
1567 return 3; | |
1568 } | |
1569 } | |
1570 | |
1571 // Performs the proper interpolation of the texel based on the | |
1572 // endpoints and weights. | |
1573 SkColor getTexel(const SkColor endpoints[4][2], | |
1574 const int weights[2][12][12], | |
1575 int x, int y) const { | |
1576 int part = 0; | |
1577 if (this->numPartitions() > 1) { | |
1578 part = this->getPartition(x, y); | |
1579 } | |
1580 | |
1581 SkColor result; | |
1582 if (fDualPlaneEnabled) { | |
1583 result = interpolate_dual_endpoints( | |
1584 endpoints[part], weights[0][x][y], weights[1][x][y], fDualPlane) ; | |
1585 } else { | |
1586 result = interpolate_endpoints(endpoints[part], weights[0][x][y]); | |
1587 } | |
1588 | |
1589 #if 1 | |
1590 // !FIXME! if we're writing directly to a bitmap, then we don't need | |
1591 // to swap the red and blue channels, but since we're usually being used | |
1592 // by the SkImageDecoder_astc module, the results are expected to be in RGBA. | |
1593 result = SkColorSetARGB( | |
1594 SkColorGetA(result), SkColorGetB(result), SkColorGetG(result), SkCol orGetR(result)); | |
1595 #endif | |
1596 | |
1597 return result; | |
1598 } | |
1599 | |
1600 void decode() { | |
1601 // First decode the block mode. | |
1602 this->decodeBlockMode(); | |
1603 | |
1604 // Now we can decode the partition information. | |
1605 fPartIndex = read_astc_bits(fBlock, 11, 23); | |
1606 fPartCount = (fPartIndex & 0x3) + 1; | |
1607 fPartIndex >>= 2; | |
1608 | |
1609 // This is illegal | |
1610 if (fDualPlaneEnabled && this->numPartitions() == 4) { | |
1611 fError = true; | |
1612 return; | |
1613 } | |
1614 | |
1615 // Based on the partition info, we can decode the color information. | |
1616 this->decodeColorData(); | |
1617 } | |
1618 | |
1619 // Decodes the dual plane based on the given bit location. The final | |
1620 // location, if the dual plane is enabled, is also the end of our color data . | |
1621 // This function is only meant to be used from this->decodeColorData() | |
1622 void decodeDualPlane(int bitLoc) { | |
1623 if (fDualPlaneEnabled) { | |
1624 fDualPlane = read_astc_bits(fBlock, bitLoc - 2, bitLoc); | |
1625 fColorEndBit = bitLoc - 2; | |
1626 } else { | |
1627 fColorEndBit = bitLoc; | |
1628 } | |
1629 } | |
1630 | |
1631 // Decodes the color information based on the ASTC spec. | |
1632 void decodeColorData() { | |
1633 | |
1634 // By default, the last color bit is at the end of the texel weights | |
1635 const int lastWeight = 128 - this->numWeightBits(); | |
1636 | |
1637 // If we have a dual plane then it will be at this location, too. | |
1638 int dualPlaneBitLoc = lastWeight; | |
1639 | |
1640 // If there's only one partition, then our job is (relatively) easy. | |
1641 if (this->numPartitions() == 1) { | |
1642 fCEM[0] = static_cast<ColorEndpointMode>(read_astc_bits(fBlock, 13, 17)); | |
1643 fColorStartBit = 17; | |
1644 | |
1645 // Handle dual plane mode... | |
1646 this->decodeDualPlane(dualPlaneBitLoc); | |
1647 | |
1648 return; | |
1649 } | |
1650 | |
1651 // If we have more than one partition, then we need to make | |
1652 // room for the partition index. | |
1653 fColorStartBit = 29; | |
1654 | |
1655 // Read the base CEM. If it's zero, then we have no additional | |
1656 // CEM data and the endpoints for each partition share the same CEM. | |
1657 const int baseCEM = read_astc_bits(fBlock, 23, 25); | |
1658 if (0 == baseCEM) { | |
1659 | |
1660 const ColorEndpointMode sameCEM = | |
1661 static_cast<ColorEndpointMode>(read_astc_bits(fBlock, 25, 29)); | |
1662 | |
1663 for (int i = 0; i < kMaxPartitions; ++i) { | |
1664 fCEM[i] = sameCEM; | |
1665 } | |
1666 | |
1667 // Handle dual plane mode... | |
1668 this->decodeDualPlane(dualPlaneBitLoc); | |
1669 | |
1670 return; | |
1671 } | |
1672 | |
1673 // Move the dual plane selector bits down based on how many | |
1674 // partitions the block contains. | |
1675 switch (this->numPartitions()) { | |
1676 case 2: | |
1677 dualPlaneBitLoc -= 2; | |
1678 break; | |
1679 | |
1680 case 3: | |
1681 dualPlaneBitLoc -= 5; | |
1682 break; | |
1683 | |
1684 case 4: | |
1685 dualPlaneBitLoc -= 8; | |
1686 break; | |
1687 | |
1688 default: | |
1689 SkDEBUGFAIL("Internal ASTC decoding error."); | |
1690 break; | |
1691 } | |
1692 | |
1693 // The rest of the CEM config will be between the dual plane bit selecto r | |
1694 // and the texel weight grid. | |
1695 const int lowCEM = read_astc_bits(fBlock, 23, 29); | |
1696 int fullCEM = read_astc_bits(fBlock, dualPlaneBitLoc, lastWeight); | |
1697 | |
1698 // Attach the config at the end of the weight grid to the CEM values | |
1699 // in the beginning of the block. | |
1700 fullCEM = (fullCEM << 6) | lowCEM; | |
1701 | |
1702 // Ignore the two least significant bits, since those are our baseCEM ab ove. | |
1703 fullCEM = fullCEM >> 2; | |
1704 | |
1705 int C[kMaxPartitions]; // Next, decode C and M from the spec (Table C.2. 12) | |
1706 for (int i = 0; i < this->numPartitions(); ++i) { | |
1707 C[i] = fullCEM & 1; | |
1708 fullCEM = fullCEM >> 1; | |
1709 } | |
1710 | |
1711 int M[kMaxPartitions]; | |
1712 for (int i = 0; i < this->numPartitions(); ++i) { | |
1713 M[i] = fullCEM & 0x3; | |
1714 fullCEM = fullCEM >> 2; | |
1715 } | |
1716 | |
1717 // Construct our CEMs.. | |
1718 SkASSERT(baseCEM > 0); | |
1719 for (int i = 0; i < this->numPartitions(); ++i) { | |
1720 int cem = (baseCEM - 1) * 4; | |
1721 cem += (0 == C[i])? 0 : 4; | |
1722 cem += M[i]; | |
1723 | |
1724 SkASSERT(cem < 16); | |
1725 fCEM[i] = static_cast<ColorEndpointMode>(cem); | |
1726 } | |
1727 | |
1728 // Finally, if we have dual plane mode, then read the plane selector. | |
1729 this->decodeDualPlane(dualPlaneBitLoc); | |
1730 } | |
1731 | |
1732 // Decodes the block mode. This function determines whether or not we use | |
1733 // dual plane encoding, the size of the texel weight grid, and the number of | |
1734 // bits, trits and quints that are used to encode it. For more information, | |
1735 // see section C.2.10 of the ASTC spec. | |
1736 // | |
1737 // For 2D blocks, the Block Mode field is laid out as follows: | |
1738 // | |
1739 // ------------------------------------------------------------------------- | |
1740 // 10 9 8 7 6 5 4 3 2 1 0 Width Height Notes | |
1741 // ------------------------------------------------------------------------- | |
1742 // D H B A R0 0 0 R2 R1 B+4 A+2 | |
1743 // D H B A R0 0 1 R2 R1 B+8 A+2 | |
1744 // D H B A R0 1 0 R2 R1 A+2 B+8 | |
1745 // D H 0 B A R0 1 1 R2 R1 A+2 B+6 | |
1746 // D H 1 B A R0 1 1 R2 R1 B+2 A+2 | |
1747 // D H 0 0 A R0 R2 R1 0 0 12 A+2 | |
1748 // D H 0 1 A R0 R2 R1 0 0 A+2 12 | |
1749 // D H 1 1 0 0 R0 R2 R1 0 0 6 10 | |
1750 // D H 1 1 0 1 R0 R2 R1 0 0 10 6 | |
1751 // B 1 0 A R0 R2 R1 0 0 A+6 B+6 D=0, H=0 | |
1752 // x x 1 1 1 1 1 1 1 0 0 - - Void-extent | |
1753 // x x 1 1 1 x x x x 0 0 - - Reserved* | |
1754 // x x x x x x x 0 0 0 0 - - Reserved | |
1755 // ------------------------------------------------------------------------- | |
1756 // | |
robertphillips
2014/08/06 17:24:20
A, B ?
krajcevski
2014/08/06 18:14:30
Done.
| |
1757 // D - dual plane enabled | |
1758 // H, R - used to determine the number of bits/trits/quints in texel weight encoding | |
robertphillips
2014/08/06 17:24:21
R0, R1, R2 ?
krajcevski
2014/08/06 18:14:29
Done.
| |
1759 // Width, Height - dimensions of the texel weight grid. | |
1760 | |
1761 void decodeBlockMode() { | |
1762 const int blockMode = read_astc_bits(fBlock, 0, 11); | |
1763 | |
1764 // Check for special void extent encoding | |
1765 fVoidExtent = (blockMode & 0x1FF) == 0x1FC; | |
1766 | |
1767 // Check for reserved block modes | |
1768 fError = ((blockMode & 0x1C3) == 0x1C0) || ((blockMode & 0xF) == 0); | |
1769 | |
1770 // Neither reserved nor void-extent, decode as usual | |
1771 // This code corresponds to table C.2.8 of the ASTC spec | |
1772 bool highPrecision = false; | |
1773 int R = 0; | |
1774 if ((blockMode & 0x3) == 0) { | |
1775 R = ((0xC & blockMode) >> 1) | ((0x10 & blockMode) >> 4); | |
1776 const int bitsSevenAndEight = (blockMode & 0x180) >> 7; | |
1777 SkASSERT(0 <= bitsSevenAndEight && bitsSevenAndEight < 4); | |
1778 | |
1779 const int A = (blockMode >> 5) & 0x3; | |
1780 const int B = (blockMode >> 9) & 0x3; | |
1781 | |
1782 fDualPlaneEnabled = (blockMode >> 10) & 0x1; | |
1783 highPrecision = (blockMode >> 9) & 0x1; | |
1784 | |
1785 switch (bitsSevenAndEight) { | |
1786 default: | |
1787 case 0: | |
1788 fWeightDimX = 12; | |
1789 fWeightDimY = A + 2; | |
1790 break; | |
1791 | |
1792 case 1: | |
1793 fWeightDimX = A + 2; | |
1794 fWeightDimY = 12; | |
1795 break; | |
1796 | |
1797 case 2: | |
1798 fWeightDimX = A + 6; | |
1799 fWeightDimY = B + 6; | |
1800 fDualPlaneEnabled = false; | |
1801 highPrecision = false; | |
1802 break; | |
1803 | |
1804 case 3: | |
1805 if (0 == A) { | |
1806 fWeightDimX = 6; | |
1807 fWeightDimY = 10; | |
1808 } else { | |
1809 fWeightDimX = 10; | |
1810 fWeightDimY = 6; | |
1811 } | |
1812 break; | |
1813 } | |
1814 } else { // (blockMode & 0x3) != 0 | |
1815 R = ((blockMode & 0x3) << 1) | ((blockMode & 0x10) >> 4); | |
1816 | |
1817 const int bitsTwoAndThree = (blockMode >> 2) & 0x3; | |
1818 SkASSERT(0 <= bitsTwoAndThree && bitsTwoAndThree < 4); | |
1819 | |
1820 const int A = (blockMode >> 5) & 0x3; | |
1821 const int B = (blockMode >> 7) & 0x3; | |
1822 | |
1823 fDualPlaneEnabled = (blockMode >> 10) & 0x1; | |
1824 highPrecision = (blockMode >> 9) & 0x1; | |
1825 | |
1826 switch (bitsTwoAndThree) { | |
1827 case 0: | |
1828 fWeightDimX = B + 4; | |
1829 fWeightDimY = A + 2; | |
1830 break; | |
1831 case 1: | |
1832 fWeightDimX = B + 8; | |
1833 fWeightDimY = A + 2; | |
1834 break; | |
1835 case 2: | |
1836 fWeightDimX = A + 2; | |
1837 fWeightDimY = B + 8; | |
1838 break; | |
1839 case 3: | |
1840 if ((B & 0x2) == 0) { | |
1841 fWeightDimX = A + 2; | |
1842 fWeightDimY = (B & 1) + 6; | |
1843 } else { | |
1844 fWeightDimX = (B & 1) + 2; | |
1845 fWeightDimY = A + 2; | |
1846 } | |
1847 break; | |
1848 } | |
1849 } | |
1850 | |
1851 // We should have set the values of R and highPrecision | |
1852 // from decoding the block mode, these are used to determine | |
1853 // the proper dimensions of our weight grid. | |
1854 if ((R & 0x6) == 0) { | |
1855 fError = true; | |
1856 } else { | |
1857 static const int kBitAllocationTable[2][6][3] = { | |
1858 { | |
1859 { 1, 0, 0 }, | |
1860 { 0, 1, 0 }, | |
1861 { 2, 0, 0 }, | |
1862 { 0, 0, 1 }, | |
1863 { 1, 1, 0 }, | |
1864 { 3, 0, 0 } | |
1865 }, | |
1866 { | |
1867 { 1, 0, 1 }, | |
1868 { 2, 1, 0 }, | |
1869 { 4, 0, 0 }, | |
1870 { 2, 0, 1 }, | |
1871 { 3, 1, 0 }, | |
1872 { 5, 0, 0 } | |
1873 } | |
1874 }; | |
1875 | |
1876 fWeightBits = kBitAllocationTable[highPrecision][R - 2][0]; | |
1877 fWeightTrits = kBitAllocationTable[highPrecision][R - 2][1]; | |
1878 fWeightQuints = kBitAllocationTable[highPrecision][R - 2][2]; | |
1879 } | |
1880 } | |
1881 }; | |
1882 | |
1883 // Reads an ASTC block from the given pointer. | |
1884 static inline void read_astc_block(ASTCDecompressionData *dst, const uint8_t* sr c) { | |
1885 const uint64_t* qword = reinterpret_cast<const uint64_t*>(src); | |
1886 dst->fBlock.fLow = SkEndian_SwapLE64(qword[0]); | |
1887 dst->fBlock.fHigh = SkEndian_SwapLE64(qword[1]); | |
1888 dst->decode(); | |
1889 } | |
1890 | |
1891 // Take a known void-extent block, and write out the values as a constant color. | |
1892 static void decompress_void_extent(uint8_t* dst, int dstRowBytes, | |
1893 const ASTCDecompressionData &data) { | |
1894 // The top 64 bits contain 4 16-bit RGBA values. | |
1895 int a = (read_astc_bits(data.fBlock, 112, 128) + 255) >> 8; | |
1896 int b = (read_astc_bits(data.fBlock, 96, 112) + 255) >> 8; | |
1897 int g = (read_astc_bits(data.fBlock, 80, 96) + 255) >> 8; | |
1898 int r = (read_astc_bits(data.fBlock, 64, 80) + 255) >> 8; | |
1899 | |
1900 write_constant_color(dst, data.fDimX, data.fDimY, dstRowBytes, SkColorSetARG B(a, r, g, b)); | |
1901 } | |
1902 | |
1903 // Decompresses a single ASTC block. It's assumed that data.fDimX and data.fDimY are | |
1904 // set and that the block has already been decoded (i.e. data.decode() has been called) | |
1905 static void decompress_astc_block(uint8_t* dst, int dstRowBytes, | |
1906 const ASTCDecompressionData &data) { | |
1907 if (data.fError) { | |
1908 write_error_color(dst, data.fDimX, data.fDimY, dstRowBytes); | |
1909 return; | |
1910 } | |
1911 | |
robertphillips
2014/08/06 17:24:21
space after "if" ?
krajcevski
2014/08/06 18:14:30
Done.
| |
1912 if(data.fVoidExtent) { | |
1913 decompress_void_extent(dst, dstRowBytes, data); | |
1914 return; | |
1915 } | |
1916 | |
1917 // According to the spec, any more than 64 values is illegal. (C.2.24) | |
1918 static const int kMaxTexelValues = 64; | |
1919 | |
1920 // Decode the texel weights. | |
1921 int texelValues[kMaxTexelValues]; | |
1922 bool success = decode_integer_sequence( | |
1923 texelValues, kMaxTexelValues, data.numWeights(), | |
1924 // texel data goes to the end of the 128 bit block. | |
1925 data.fBlock, 128, 128 - data.numWeightBits(), false, | |
1926 data.fWeightBits, data.fWeightTrits, data.fWeightQuints); | |
1927 | |
1928 if (!success) { | |
1929 write_error_color(dst, data.fDimX, data.fDimY, dstRowBytes); | |
1930 return; | |
1931 } | |
1932 | |
1933 // Decode the color endpoints | |
1934 int colorBits, colorTrits, colorQuints; | |
1935 if (!data.getColorValueEncoding(&colorBits, &colorTrits, &colorQuints)) { | |
1936 write_error_color(dst, data.fDimX, data.fDimY, dstRowBytes); | |
1937 return; | |
1938 } | |
1939 | |
1940 // According to the spec, any more than 18 color values is illegal. (C.2.24) | |
1941 static const int kMaxColorValues = 18; | |
1942 | |
1943 int colorValues[kMaxColorValues]; | |
1944 success = decode_integer_sequence( | |
1945 colorValues, kMaxColorValues, data.numColorValues(), | |
1946 data.fBlock, data.fColorStartBit, data.fColorEndBit, true, | |
1947 colorBits, colorTrits, colorQuints); | |
1948 | |
1949 if (!success) { | |
1950 write_error_color(dst, data.fDimX, data.fDimY, dstRowBytes); | |
1951 return; | |
1952 } | |
1953 | |
1954 // Unquantize the color values after they've been decoded. | |
1955 unquantize_colors(colorValues, data.numColorValues(), colorBits, colorTrits, colorQuints); | |
1956 | |
1957 // Decode the colors into the appropriate endpoints. | |
1958 SkColor endpoints[4][2]; | |
1959 data.colorEndpoints(endpoints, colorValues); | |
1960 | |
1961 // Do texel infill and decode the texel values. | |
1962 int texelWeights[2][12][12]; | |
1963 data.texelWeights(texelWeights, texelValues); | |
1964 | |
1965 // Write the texels by interpolating them based on the information | |
1966 // stored in the block. | |
1967 dst += data.fDimY * dstRowBytes; | |
1968 for (int y = 0; y < data.fDimY; ++y) { | |
1969 dst -= dstRowBytes; | |
1970 SkColor* colorPtr = reinterpret_cast<SkColor*>(dst); | |
1971 for (int x = 0; x < data.fDimX; ++x) { | |
1972 colorPtr[x] = data.getTexel(endpoints, texelWeights, x, y); | |
1973 } | |
1974 } | |
1975 } | |
1976 | |
1977 //////////////////////////////////////////////////////////////////////////////// | |
264 | 1978 |
265 namespace SkTextureCompressor { | 1979 namespace SkTextureCompressor { |
266 | 1980 |
267 bool CompressA8To12x12ASTC(uint8_t* dst, const uint8_t* src, int width, int heig ht, int rowBytes) { | 1981 bool CompressA8To12x12ASTC(uint8_t* dst, const uint8_t* src, |
1982 int width, int height, int rowBytes) { | |
268 if (width < 0 || ((width % 12) != 0) || height < 0 || ((height % 12) != 0)) { | 1983 if (width < 0 || ((width % 12) != 0) || height < 0 || ((height % 12) != 0)) { |
269 return false; | 1984 return false; |
270 } | 1985 } |
271 | 1986 |
272 uint8_t** dstPtr = &dst; | 1987 uint8_t** dstPtr = &dst; |
273 for (int y = 0; y < height; y += 12) { | 1988 for (int y = 0; y < height; y += 12) { |
274 for (int x = 0; x < width; x += 12) { | 1989 for (int x = 0; x < width; x += 12) { |
275 compress_a8_astc_block<GetAlpha>(dstPtr, src + y*rowBytes + x, rowBy tes); | 1990 compress_a8_astc_block<GetAlpha>(dstPtr, src + y*rowBytes + x, rowBy tes); |
276 } | 1991 } |
277 } | 1992 } |
278 | 1993 |
279 return true; | 1994 return true; |
280 } | 1995 } |
281 | 1996 |
282 SkBlitter* CreateASTCBlitter(int width, int height, void* outputBuffer) { | 1997 SkBlitter* CreateASTCBlitter(int width, int height, void* outputBuffer) { |
283 return new | 1998 return new |
284 SkTCompressedAlphaBlitter<12, 16, CompressA8ASTCBlockVertical> | 1999 SkTCompressedAlphaBlitter<12, 16, CompressA8ASTCBlockVertical> |
285 (width, height, outputBuffer); | 2000 (width, height, outputBuffer); |
286 } | 2001 } |
287 | 2002 |
2003 void DecompressASTC(uint8_t* dst, int dstRowBytes, const uint8_t* src, | |
2004 int width, int height, int blockDimX, int blockDimY) { | |
2005 // ASTC is encoded in what they call "raster order", so that the first | |
2006 // block is the bottom-left block in the image, and the first pixel | |
2007 // is the bottom-left pixel of the image | |
2008 dst += height * dstRowBytes; | |
2009 | |
2010 ASTCDecompressionData data(blockDimX, blockDimY); | |
robertphillips
2014/08/06 17:24:20
i,j -> x,y ?
krajcevski
2014/08/06 18:14:29
Done.
| |
2011 for (int j = 0; j < height; j += blockDimY) { | |
2012 dst -= blockDimY * dstRowBytes; | |
2013 SkColor *colorPtr = reinterpret_cast<SkColor*>(dst); | |
2014 for (int i = 0; i < width; i += blockDimX) { | |
2015 read_astc_block(&data, src); | |
2016 decompress_astc_block(reinterpret_cast<uint8_t*>(colorPtr + i), dstR owBytes, data); | |
2017 | |
2018 // ASTC encoded blocks are 16 bytes (128 bits) large. | |
2019 src += 16; | |
2020 } | |
2021 } | |
2022 } | |
2023 | |
288 } // SkTextureCompressor | 2024 } // SkTextureCompressor |
OLD | NEW |