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