Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1)

Side by Side Diff: src/utils/SkTextureCompressor_ASTC.cpp

Issue 444433002: Initial ASTC decoder -- currently only supports 2D LDR decomrpession modes. (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Change wording on comments Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/utils/SkTextureCompressor_ASTC.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
OLDNEW
« no previous file with comments | « src/utils/SkTextureCompressor_ASTC.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698