1/*------------------------------------------------------------------------- 2 * drawElements Quality Program Tester Core 3 * ---------------------------------------- 4 * 5 * Copyright 2016 The Android Open Source Project 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License"); 8 * you may not use this file except in compliance with the License. 9 * You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 * 19 *//*! 20 * \file 21 * \brief ASTC Utilities. 22 *//*--------------------------------------------------------------------*/ 23 24#include "tcuAstcUtil.hpp" 25#include "deFloat16.h" 26#include "deRandom.hpp" 27#include "deMeta.hpp" 28 29#include <algorithm> 30 31namespace tcu 32{ 33namespace astc 34{ 35 36using std::vector; 37 38namespace 39{ 40 41// Common utilities 42 43enum 44{ 45 MAX_BLOCK_WIDTH = 12, 46 MAX_BLOCK_HEIGHT = 12 47}; 48 49inline deUint32 getBit (deUint32 src, int ndx) 50{ 51 DE_ASSERT(de::inBounds(ndx, 0, 32)); 52 return (src >> ndx) & 1; 53} 54 55inline deUint32 getBits (deUint32 src, int low, int high) 56{ 57 const int numBits = (high-low) + 1; 58 59 DE_ASSERT(de::inRange(numBits, 1, 32)); 60 61 if (numBits < 32) 62 return (deUint32)((src >> low) & ((1u<<numBits)-1)); 63 else 64 return (deUint32)((src >> low) & 0xFFFFFFFFu); 65} 66 67inline bool isBitSet (deUint32 src, int ndx) 68{ 69 return getBit(src, ndx) != 0; 70} 71 72inline deUint32 reverseBits (deUint32 src, int numBits) 73{ 74 DE_ASSERT(de::inRange(numBits, 0, 32)); 75 deUint32 result = 0; 76 for (int i = 0; i < numBits; i++) 77 result |= ((src >> i) & 1) << (numBits-1-i); 78 return result; 79} 80 81inline deUint32 bitReplicationScale (deUint32 src, int numSrcBits, int numDstBits) 82{ 83 DE_ASSERT(numSrcBits <= numDstBits); 84 DE_ASSERT((src & ((1<<numSrcBits)-1)) == src); 85 deUint32 dst = 0; 86 for (int shift = numDstBits-numSrcBits; shift > -numSrcBits; shift -= numSrcBits) 87 dst |= shift >= 0 ? src << shift : src >> -shift; 88 return dst; 89} 90 91inline deInt32 signExtend (deInt32 src, int numSrcBits) 92{ 93 DE_ASSERT(de::inRange(numSrcBits, 2, 31)); 94 const bool negative = (src & (1 << (numSrcBits-1))) != 0; 95 return src | (negative ? ~((1 << numSrcBits) - 1) : 0); 96} 97 98inline bool isFloat16InfOrNan (deFloat16 v) 99{ 100 return getBits(v, 10, 14) == 31; 101} 102 103enum ISEMode 104{ 105 ISEMODE_TRIT = 0, 106 ISEMODE_QUINT, 107 ISEMODE_PLAIN_BIT, 108 109 ISEMODE_LAST 110}; 111 112struct ISEParams 113{ 114 ISEMode mode; 115 int numBits; 116 117 ISEParams (ISEMode mode_, int numBits_) : mode(mode_), numBits(numBits_) {} 118}; 119 120inline int computeNumRequiredBits (const ISEParams& iseParams, int numValues) 121{ 122 switch (iseParams.mode) 123 { 124 case ISEMODE_TRIT: return deDivRoundUp32(numValues*8, 5) + numValues*iseParams.numBits; 125 case ISEMODE_QUINT: return deDivRoundUp32(numValues*7, 3) + numValues*iseParams.numBits; 126 case ISEMODE_PLAIN_BIT: return numValues*iseParams.numBits; 127 default: 128 DE_ASSERT(false); 129 return -1; 130 } 131} 132 133ISEParams computeMaximumRangeISEParams (int numAvailableBits, int numValuesInSequence) 134{ 135 int curBitsForTritMode = 6; 136 int curBitsForQuintMode = 5; 137 int curBitsForPlainBitMode = 8; 138 139 while (true) 140 { 141 DE_ASSERT(curBitsForTritMode > 0 || curBitsForQuintMode > 0 || curBitsForPlainBitMode > 0); 142 143 const int tritRange = curBitsForTritMode > 0 ? (3 << curBitsForTritMode) - 1 : -1; 144 const int quintRange = curBitsForQuintMode > 0 ? (5 << curBitsForQuintMode) - 1 : -1; 145 const int plainBitRange = curBitsForPlainBitMode > 0 ? (1 << curBitsForPlainBitMode) - 1 : -1; 146 const int maxRange = de::max(de::max(tritRange, quintRange), plainBitRange); 147 148 if (maxRange == tritRange) 149 { 150 const ISEParams params(ISEMODE_TRIT, curBitsForTritMode); 151 if (computeNumRequiredBits(params, numValuesInSequence) <= numAvailableBits) 152 return ISEParams(ISEMODE_TRIT, curBitsForTritMode); 153 curBitsForTritMode--; 154 } 155 else if (maxRange == quintRange) 156 { 157 const ISEParams params(ISEMODE_QUINT, curBitsForQuintMode); 158 if (computeNumRequiredBits(params, numValuesInSequence) <= numAvailableBits) 159 return ISEParams(ISEMODE_QUINT, curBitsForQuintMode); 160 curBitsForQuintMode--; 161 } 162 else 163 { 164 const ISEParams params(ISEMODE_PLAIN_BIT, curBitsForPlainBitMode); 165 DE_ASSERT(maxRange == plainBitRange); 166 if (computeNumRequiredBits(params, numValuesInSequence) <= numAvailableBits) 167 return ISEParams(ISEMODE_PLAIN_BIT, curBitsForPlainBitMode); 168 curBitsForPlainBitMode--; 169 } 170 } 171} 172 173inline int computeNumColorEndpointValues (deUint32 endpointMode) 174{ 175 DE_ASSERT(endpointMode < 16); 176 return (endpointMode/4 + 1) * 2; 177} 178 179// Decompression utilities 180 181enum DecompressResult 182{ 183 DECOMPRESS_RESULT_VALID_BLOCK = 0, //!< Decompressed valid block 184 DECOMPRESS_RESULT_ERROR, //!< Encountered error while decompressing, error color written 185 186 DECOMPRESS_RESULT_LAST 187}; 188 189// A helper for getting bits from a 128-bit block. 190class Block128 191{ 192private: 193 typedef deUint64 Word; 194 195 enum 196 { 197 WORD_BYTES = sizeof(Word), 198 WORD_BITS = 8*WORD_BYTES, 199 NUM_WORDS = 128 / WORD_BITS 200 }; 201 202 DE_STATIC_ASSERT(128 % WORD_BITS == 0); 203 204public: 205 Block128 (const deUint8* src) 206 { 207 for (int wordNdx = 0; wordNdx < NUM_WORDS; wordNdx++) 208 { 209 m_words[wordNdx] = 0; 210 for (int byteNdx = 0; byteNdx < WORD_BYTES; byteNdx++) 211 m_words[wordNdx] |= (Word)src[wordNdx*WORD_BYTES + byteNdx] << (8*byteNdx); 212 } 213 } 214 215 deUint32 getBit (int ndx) const 216 { 217 DE_ASSERT(de::inBounds(ndx, 0, 128)); 218 return (m_words[ndx / WORD_BITS] >> (ndx % WORD_BITS)) & 1; 219 } 220 221 deUint32 getBits (int low, int high) const 222 { 223 DE_ASSERT(de::inBounds(low, 0, 128)); 224 DE_ASSERT(de::inBounds(high, 0, 128)); 225 DE_ASSERT(de::inRange(high-low+1, 0, 32)); 226 227 if (high-low+1 == 0) 228 return 0; 229 230 const int word0Ndx = low / WORD_BITS; 231 const int word1Ndx = high / WORD_BITS; 232 233 // \note "foo << bar << 1" done instead of "foo << (bar+1)" to avoid overflow, i.e. shift amount being too big. 234 235 if (word0Ndx == word1Ndx) 236 return (deUint32)((m_words[word0Ndx] & ((((Word)1 << high%WORD_BITS << 1) - 1))) >> ((Word)low % WORD_BITS)); 237 else 238 { 239 DE_ASSERT(word1Ndx == word0Ndx + 1); 240 241 return (deUint32)(m_words[word0Ndx] >> (low%WORD_BITS)) | 242 (deUint32)((m_words[word1Ndx] & (((Word)1 << high%WORD_BITS << 1) - 1)) << (high-low - high%WORD_BITS)); 243 } 244 } 245 246 bool isBitSet (int ndx) const 247 { 248 DE_ASSERT(de::inBounds(ndx, 0, 128)); 249 return getBit(ndx) != 0; 250 } 251 252private: 253 Word m_words[NUM_WORDS]; 254}; 255 256// A helper for sequential access into a Block128. 257class BitAccessStream 258{ 259public: 260 BitAccessStream (const Block128& src, int startNdxInSrc, int length, bool forward) 261 : m_src (src) 262 , m_startNdxInSrc (startNdxInSrc) 263 , m_length (length) 264 , m_forward (forward) 265 , m_ndx (0) 266 { 267 } 268 269 // Get the next num bits. Bits at positions greater than or equal to m_length are zeros. 270 deUint32 getNext (int num) 271 { 272 if (num == 0 || m_ndx >= m_length) 273 return 0; 274 275 const int end = m_ndx + num; 276 const int numBitsFromSrc = de::max(0, de::min(m_length, end) - m_ndx); 277 const int low = m_ndx; 278 const int high = m_ndx + numBitsFromSrc - 1; 279 280 m_ndx += num; 281 282 return m_forward ? m_src.getBits(m_startNdxInSrc + low, m_startNdxInSrc + high) 283 : reverseBits(m_src.getBits(m_startNdxInSrc - high, m_startNdxInSrc - low), numBitsFromSrc); 284 } 285 286private: 287 const Block128& m_src; 288 const int m_startNdxInSrc; 289 const int m_length; 290 const bool m_forward; 291 292 int m_ndx; 293}; 294 295struct ISEDecodedResult 296{ 297 deUint32 m; 298 deUint32 tq; //!< Trit or quint value, depending on ISE mode. 299 deUint32 v; 300}; 301 302// Data from an ASTC block's "block mode" part (i.e. bits [0,10]). 303struct ASTCBlockMode 304{ 305 bool isError; 306 // \note Following fields only relevant if !isError. 307 bool isVoidExtent; 308 // \note Following fields only relevant if !isVoidExtent. 309 bool isDualPlane; 310 int weightGridWidth; 311 int weightGridHeight; 312 ISEParams weightISEParams; 313 314 ASTCBlockMode (void) 315 : isError (true) 316 , isVoidExtent (true) 317 , isDualPlane (true) 318 , weightGridWidth (-1) 319 , weightGridHeight (-1) 320 , weightISEParams (ISEMODE_LAST, -1) 321 { 322 } 323}; 324 325inline int computeNumWeights (const ASTCBlockMode& mode) 326{ 327 return mode.weightGridWidth * mode.weightGridHeight * (mode.isDualPlane ? 2 : 1); 328} 329 330struct ColorEndpointPair 331{ 332 UVec4 e0; 333 UVec4 e1; 334}; 335 336struct TexelWeightPair 337{ 338 deUint32 w[2]; 339}; 340 341ASTCBlockMode getASTCBlockMode (deUint32 blockModeData) 342{ 343 ASTCBlockMode blockMode; 344 blockMode.isError = true; // \note Set to false later, if not error. 345 346 blockMode.isVoidExtent = getBits(blockModeData, 0, 8) == 0x1fc; 347 348 if (!blockMode.isVoidExtent) 349 { 350 if ((getBits(blockModeData, 0, 1) == 0 && getBits(blockModeData, 6, 8) == 7) || getBits(blockModeData, 0, 3) == 0) 351 return blockMode; // Invalid ("reserved"). 352 353 deUint32 r = (deUint32)-1; // \note Set in the following branches. 354 355 if (getBits(blockModeData, 0, 1) == 0) 356 { 357 const deUint32 r0 = getBit(blockModeData, 4); 358 const deUint32 r1 = getBit(blockModeData, 2); 359 const deUint32 r2 = getBit(blockModeData, 3); 360 const deUint32 i78 = getBits(blockModeData, 7, 8); 361 362 r = (r2 << 2) | (r1 << 1) | (r0 << 0); 363 364 if (i78 == 3) 365 { 366 const bool i5 = isBitSet(blockModeData, 5); 367 blockMode.weightGridWidth = i5 ? 10 : 6; 368 blockMode.weightGridHeight = i5 ? 6 : 10; 369 } 370 else 371 { 372 const deUint32 a = getBits(blockModeData, 5, 6); 373 switch (i78) 374 { 375 case 0: blockMode.weightGridWidth = 12; blockMode.weightGridHeight = a + 2; break; 376 case 1: blockMode.weightGridWidth = a + 2; blockMode.weightGridHeight = 12; break; 377 case 2: blockMode.weightGridWidth = a + 6; blockMode.weightGridHeight = getBits(blockModeData, 9, 10) + 6; break; 378 default: DE_ASSERT(false); 379 } 380 } 381 } 382 else 383 { 384 const deUint32 r0 = getBit(blockModeData, 4); 385 const deUint32 r1 = getBit(blockModeData, 0); 386 const deUint32 r2 = getBit(blockModeData, 1); 387 const deUint32 i23 = getBits(blockModeData, 2, 3); 388 const deUint32 a = getBits(blockModeData, 5, 6); 389 390 r = (r2 << 2) | (r1 << 1) | (r0 << 0); 391 392 if (i23 == 3) 393 { 394 const deUint32 b = getBit(blockModeData, 7); 395 const bool i8 = isBitSet(blockModeData, 8); 396 blockMode.weightGridWidth = i8 ? b+2 : a+2; 397 blockMode.weightGridHeight = i8 ? a+2 : b+6; 398 } 399 else 400 { 401 const deUint32 b = getBits(blockModeData, 7, 8); 402 403 switch (i23) 404 { 405 case 0: blockMode.weightGridWidth = b + 4; blockMode.weightGridHeight = a + 2; break; 406 case 1: blockMode.weightGridWidth = b + 8; blockMode.weightGridHeight = a + 2; break; 407 case 2: blockMode.weightGridWidth = a + 2; blockMode.weightGridHeight = b + 8; break; 408 default: DE_ASSERT(false); 409 } 410 } 411 } 412 413 const bool zeroDH = getBits(blockModeData, 0, 1) == 0 && getBits(blockModeData, 7, 8) == 2; 414 const bool h = zeroDH ? 0 : isBitSet(blockModeData, 9); 415 blockMode.isDualPlane = zeroDH ? 0 : isBitSet(blockModeData, 10); 416 417 { 418 ISEMode& m = blockMode.weightISEParams.mode; 419 int& b = blockMode.weightISEParams.numBits; 420 m = ISEMODE_PLAIN_BIT; 421 b = 0; 422 423 if (h) 424 { 425 switch (r) 426 { 427 case 2: m = ISEMODE_QUINT; b = 1; break; 428 case 3: m = ISEMODE_TRIT; b = 2; break; 429 case 4: b = 4; break; 430 case 5: m = ISEMODE_QUINT; b = 2; break; 431 case 6: m = ISEMODE_TRIT; b = 3; break; 432 case 7: b = 5; break; 433 default: DE_ASSERT(false); 434 } 435 } 436 else 437 { 438 switch (r) 439 { 440 case 2: b = 1; break; 441 case 3: m = ISEMODE_TRIT; break; 442 case 4: b = 2; break; 443 case 5: m = ISEMODE_QUINT; break; 444 case 6: m = ISEMODE_TRIT; b = 1; break; 445 case 7: b = 3; break; 446 default: DE_ASSERT(false); 447 } 448 } 449 } 450 } 451 452 blockMode.isError = false; 453 return blockMode; 454} 455 456inline void setASTCErrorColorBlock (void* dst, int blockWidth, int blockHeight, bool isSRGB) 457{ 458 if (isSRGB) 459 { 460 deUint8* const dstU = (deUint8*)dst; 461 462 for (int i = 0; i < blockWidth*blockHeight; i++) 463 { 464 dstU[4*i + 0] = 0xff; 465 dstU[4*i + 1] = 0; 466 dstU[4*i + 2] = 0xff; 467 dstU[4*i + 3] = 0xff; 468 } 469 } 470 else 471 { 472 float* const dstF = (float*)dst; 473 474 for (int i = 0; i < blockWidth*blockHeight; i++) 475 { 476 dstF[4*i + 0] = 1.0f; 477 dstF[4*i + 1] = 0.0f; 478 dstF[4*i + 2] = 1.0f; 479 dstF[4*i + 3] = 1.0f; 480 } 481 } 482} 483 484DecompressResult decodeVoidExtentBlock (void* dst, const Block128& blockData, int blockWidth, int blockHeight, bool isSRGB, bool isLDRMode) 485{ 486 const deUint32 minSExtent = blockData.getBits(12, 24); 487 const deUint32 maxSExtent = blockData.getBits(25, 37); 488 const deUint32 minTExtent = blockData.getBits(38, 50); 489 const deUint32 maxTExtent = blockData.getBits(51, 63); 490 const bool allExtentsAllOnes = minSExtent == 0x1fff && maxSExtent == 0x1fff && minTExtent == 0x1fff && maxTExtent == 0x1fff; 491 const bool isHDRBlock = blockData.isBitSet(9); 492 493 if ((isLDRMode && isHDRBlock) || (!allExtentsAllOnes && (minSExtent >= maxSExtent || minTExtent >= maxTExtent))) 494 { 495 setASTCErrorColorBlock(dst, blockWidth, blockHeight, isSRGB); 496 return DECOMPRESS_RESULT_ERROR; 497 } 498 499 const deUint32 rgba[4] = 500 { 501 blockData.getBits(64, 79), 502 blockData.getBits(80, 95), 503 blockData.getBits(96, 111), 504 blockData.getBits(112, 127) 505 }; 506 507 if (isSRGB) 508 { 509 deUint8* const dstU = (deUint8*)dst; 510 for (int i = 0; i < blockWidth*blockHeight; i++) 511 for (int c = 0; c < 4; c++) 512 dstU[i*4 + c] = (deUint8)((rgba[c] & 0xff00) >> 8); 513 } 514 else 515 { 516 float* const dstF = (float*)dst; 517 518 if (isHDRBlock) 519 { 520 for (int c = 0; c < 4; c++) 521 { 522 if (isFloat16InfOrNan((deFloat16)rgba[c])) 523 throw InternalError("Infinity or NaN color component in HDR void extent block in ASTC texture (behavior undefined by ASTC specification)"); 524 } 525 526 for (int i = 0; i < blockWidth*blockHeight; i++) 527 for (int c = 0; c < 4; c++) 528 dstF[i*4 + c] = deFloat16To32((deFloat16)rgba[c]); 529 } 530 else 531 { 532 for (int i = 0; i < blockWidth*blockHeight; i++) 533 for (int c = 0; c < 4; c++) 534 dstF[i*4 + c] = rgba[c] == 65535 ? 1.0f : (float)rgba[c] / 65536.0f; 535 } 536 } 537 538 return DECOMPRESS_RESULT_VALID_BLOCK; 539} 540 541void decodeColorEndpointModes (deUint32* endpointModesDst, const Block128& blockData, int numPartitions, int extraCemBitsStart) 542{ 543 if (numPartitions == 1) 544 endpointModesDst[0] = blockData.getBits(13, 16); 545 else 546 { 547 const deUint32 highLevelSelector = blockData.getBits(23, 24); 548 549 if (highLevelSelector == 0) 550 { 551 const deUint32 mode = blockData.getBits(25, 28); 552 for (int i = 0; i < numPartitions; i++) 553 endpointModesDst[i] = mode; 554 } 555 else 556 { 557 for (int partNdx = 0; partNdx < numPartitions; partNdx++) 558 { 559 const deUint32 cemClass = highLevelSelector - (blockData.isBitSet(25 + partNdx) ? 0 : 1); 560 const deUint32 lowBit0Ndx = numPartitions + 2*partNdx; 561 const deUint32 lowBit1Ndx = numPartitions + 2*partNdx + 1; 562 const deUint32 lowBit0 = blockData.getBit(lowBit0Ndx < 4 ? 25+lowBit0Ndx : extraCemBitsStart+lowBit0Ndx-4); 563 const deUint32 lowBit1 = blockData.getBit(lowBit1Ndx < 4 ? 25+lowBit1Ndx : extraCemBitsStart+lowBit1Ndx-4); 564 565 endpointModesDst[partNdx] = (cemClass << 2) | (lowBit1 << 1) | lowBit0; 566 } 567 } 568 } 569} 570 571int computeNumColorEndpointValues (const deUint32* endpointModes, int numPartitions) 572{ 573 int result = 0; 574 for (int i = 0; i < numPartitions; i++) 575 result += computeNumColorEndpointValues(endpointModes[i]); 576 return result; 577} 578 579void decodeISETritBlock (ISEDecodedResult* dst, int numValues, BitAccessStream& data, int numBits) 580{ 581 DE_ASSERT(de::inRange(numValues, 1, 5)); 582 583 deUint32 m[5]; 584 585 m[0] = data.getNext(numBits); 586 deUint32 T01 = data.getNext(2); 587 m[1] = data.getNext(numBits); 588 deUint32 T23 = data.getNext(2); 589 m[2] = data.getNext(numBits); 590 deUint32 T4 = data.getNext(1); 591 m[3] = data.getNext(numBits); 592 deUint32 T56 = data.getNext(2); 593 m[4] = data.getNext(numBits); 594 deUint32 T7 = data.getNext(1); 595 596 switch (numValues) 597 { 598 // \note Fall-throughs. 599 case 1: T23 = 0; 600 case 2: T4 = 0; 601 case 3: T56 = 0; 602 case 4: T7 = 0; 603 case 5: break; 604 default: 605 DE_ASSERT(false); 606 } 607 608 const deUint32 T = (T7 << 7) | (T56 << 5) | (T4 << 4) | (T23 << 2) | (T01 << 0); 609 610 static const deUint32 tritsFromT[256][5] = 611 { 612 { 0,0,0,0,0 }, { 1,0,0,0,0 }, { 2,0,0,0,0 }, { 0,0,2,0,0 }, { 0,1,0,0,0 }, { 1,1,0,0,0 }, { 2,1,0,0,0 }, { 1,0,2,0,0 }, { 0,2,0,0,0 }, { 1,2,0,0,0 }, { 2,2,0,0,0 }, { 2,0,2,0,0 }, { 0,2,2,0,0 }, { 1,2,2,0,0 }, { 2,2,2,0,0 }, { 2,0,2,0,0 }, 613 { 0,0,1,0,0 }, { 1,0,1,0,0 }, { 2,0,1,0,0 }, { 0,1,2,0,0 }, { 0,1,1,0,0 }, { 1,1,1,0,0 }, { 2,1,1,0,0 }, { 1,1,2,0,0 }, { 0,2,1,0,0 }, { 1,2,1,0,0 }, { 2,2,1,0,0 }, { 2,1,2,0,0 }, { 0,0,0,2,2 }, { 1,0,0,2,2 }, { 2,0,0,2,2 }, { 0,0,2,2,2 }, 614 { 0,0,0,1,0 }, { 1,0,0,1,0 }, { 2,0,0,1,0 }, { 0,0,2,1,0 }, { 0,1,0,1,0 }, { 1,1,0,1,0 }, { 2,1,0,1,0 }, { 1,0,2,1,0 }, { 0,2,0,1,0 }, { 1,2,0,1,0 }, { 2,2,0,1,0 }, { 2,0,2,1,0 }, { 0,2,2,1,0 }, { 1,2,2,1,0 }, { 2,2,2,1,0 }, { 2,0,2,1,0 }, 615 { 0,0,1,1,0 }, { 1,0,1,1,0 }, { 2,0,1,1,0 }, { 0,1,2,1,0 }, { 0,1,1,1,0 }, { 1,1,1,1,0 }, { 2,1,1,1,0 }, { 1,1,2,1,0 }, { 0,2,1,1,0 }, { 1,2,1,1,0 }, { 2,2,1,1,0 }, { 2,1,2,1,0 }, { 0,1,0,2,2 }, { 1,1,0,2,2 }, { 2,1,0,2,2 }, { 1,0,2,2,2 }, 616 { 0,0,0,2,0 }, { 1,0,0,2,0 }, { 2,0,0,2,0 }, { 0,0,2,2,0 }, { 0,1,0,2,0 }, { 1,1,0,2,0 }, { 2,1,0,2,0 }, { 1,0,2,2,0 }, { 0,2,0,2,0 }, { 1,2,0,2,0 }, { 2,2,0,2,0 }, { 2,0,2,2,0 }, { 0,2,2,2,0 }, { 1,2,2,2,0 }, { 2,2,2,2,0 }, { 2,0,2,2,0 }, 617 { 0,0,1,2,0 }, { 1,0,1,2,0 }, { 2,0,1,2,0 }, { 0,1,2,2,0 }, { 0,1,1,2,0 }, { 1,1,1,2,0 }, { 2,1,1,2,0 }, { 1,1,2,2,0 }, { 0,2,1,2,0 }, { 1,2,1,2,0 }, { 2,2,1,2,0 }, { 2,1,2,2,0 }, { 0,2,0,2,2 }, { 1,2,0,2,2 }, { 2,2,0,2,2 }, { 2,0,2,2,2 }, 618 { 0,0,0,0,2 }, { 1,0,0,0,2 }, { 2,0,0,0,2 }, { 0,0,2,0,2 }, { 0,1,0,0,2 }, { 1,1,0,0,2 }, { 2,1,0,0,2 }, { 1,0,2,0,2 }, { 0,2,0,0,2 }, { 1,2,0,0,2 }, { 2,2,0,0,2 }, { 2,0,2,0,2 }, { 0,2,2,0,2 }, { 1,2,2,0,2 }, { 2,2,2,0,2 }, { 2,0,2,0,2 }, 619 { 0,0,1,0,2 }, { 1,0,1,0,2 }, { 2,0,1,0,2 }, { 0,1,2,0,2 }, { 0,1,1,0,2 }, { 1,1,1,0,2 }, { 2,1,1,0,2 }, { 1,1,2,0,2 }, { 0,2,1,0,2 }, { 1,2,1,0,2 }, { 2,2,1,0,2 }, { 2,1,2,0,2 }, { 0,2,2,2,2 }, { 1,2,2,2,2 }, { 2,2,2,2,2 }, { 2,0,2,2,2 }, 620 { 0,0,0,0,1 }, { 1,0,0,0,1 }, { 2,0,0,0,1 }, { 0,0,2,0,1 }, { 0,1,0,0,1 }, { 1,1,0,0,1 }, { 2,1,0,0,1 }, { 1,0,2,0,1 }, { 0,2,0,0,1 }, { 1,2,0,0,1 }, { 2,2,0,0,1 }, { 2,0,2,0,1 }, { 0,2,2,0,1 }, { 1,2,2,0,1 }, { 2,2,2,0,1 }, { 2,0,2,0,1 }, 621 { 0,0,1,0,1 }, { 1,0,1,0,1 }, { 2,0,1,0,1 }, { 0,1,2,0,1 }, { 0,1,1,0,1 }, { 1,1,1,0,1 }, { 2,1,1,0,1 }, { 1,1,2,0,1 }, { 0,2,1,0,1 }, { 1,2,1,0,1 }, { 2,2,1,0,1 }, { 2,1,2,0,1 }, { 0,0,1,2,2 }, { 1,0,1,2,2 }, { 2,0,1,2,2 }, { 0,1,2,2,2 }, 622 { 0,0,0,1,1 }, { 1,0,0,1,1 }, { 2,0,0,1,1 }, { 0,0,2,1,1 }, { 0,1,0,1,1 }, { 1,1,0,1,1 }, { 2,1,0,1,1 }, { 1,0,2,1,1 }, { 0,2,0,1,1 }, { 1,2,0,1,1 }, { 2,2,0,1,1 }, { 2,0,2,1,1 }, { 0,2,2,1,1 }, { 1,2,2,1,1 }, { 2,2,2,1,1 }, { 2,0,2,1,1 }, 623 { 0,0,1,1,1 }, { 1,0,1,1,1 }, { 2,0,1,1,1 }, { 0,1,2,1,1 }, { 0,1,1,1,1 }, { 1,1,1,1,1 }, { 2,1,1,1,1 }, { 1,1,2,1,1 }, { 0,2,1,1,1 }, { 1,2,1,1,1 }, { 2,2,1,1,1 }, { 2,1,2,1,1 }, { 0,1,1,2,2 }, { 1,1,1,2,2 }, { 2,1,1,2,2 }, { 1,1,2,2,2 }, 624 { 0,0,0,2,1 }, { 1,0,0,2,1 }, { 2,0,0,2,1 }, { 0,0,2,2,1 }, { 0,1,0,2,1 }, { 1,1,0,2,1 }, { 2,1,0,2,1 }, { 1,0,2,2,1 }, { 0,2,0,2,1 }, { 1,2,0,2,1 }, { 2,2,0,2,1 }, { 2,0,2,2,1 }, { 0,2,2,2,1 }, { 1,2,2,2,1 }, { 2,2,2,2,1 }, { 2,0,2,2,1 }, 625 { 0,0,1,2,1 }, { 1,0,1,2,1 }, { 2,0,1,2,1 }, { 0,1,2,2,1 }, { 0,1,1,2,1 }, { 1,1,1,2,1 }, { 2,1,1,2,1 }, { 1,1,2,2,1 }, { 0,2,1,2,1 }, { 1,2,1,2,1 }, { 2,2,1,2,1 }, { 2,1,2,2,1 }, { 0,2,1,2,2 }, { 1,2,1,2,2 }, { 2,2,1,2,2 }, { 2,1,2,2,2 }, 626 { 0,0,0,1,2 }, { 1,0,0,1,2 }, { 2,0,0,1,2 }, { 0,0,2,1,2 }, { 0,1,0,1,2 }, { 1,1,0,1,2 }, { 2,1,0,1,2 }, { 1,0,2,1,2 }, { 0,2,0,1,2 }, { 1,2,0,1,2 }, { 2,2,0,1,2 }, { 2,0,2,1,2 }, { 0,2,2,1,2 }, { 1,2,2,1,2 }, { 2,2,2,1,2 }, { 2,0,2,1,2 }, 627 { 0,0,1,1,2 }, { 1,0,1,1,2 }, { 2,0,1,1,2 }, { 0,1,2,1,2 }, { 0,1,1,1,2 }, { 1,1,1,1,2 }, { 2,1,1,1,2 }, { 1,1,2,1,2 }, { 0,2,1,1,2 }, { 1,2,1,1,2 }, { 2,2,1,1,2 }, { 2,1,2,1,2 }, { 0,2,2,2,2 }, { 1,2,2,2,2 }, { 2,2,2,2,2 }, { 2,1,2,2,2 } 628 }; 629 630 const deUint32 (& trits)[5] = tritsFromT[T]; 631 632 for (int i = 0; i < numValues; i++) 633 { 634 dst[i].m = m[i]; 635 dst[i].tq = trits[i]; 636 dst[i].v = (trits[i] << numBits) + m[i]; 637 } 638} 639 640void decodeISEQuintBlock (ISEDecodedResult* dst, int numValues, BitAccessStream& data, int numBits) 641{ 642 DE_ASSERT(de::inRange(numValues, 1, 3)); 643 644 deUint32 m[3]; 645 646 m[0] = data.getNext(numBits); 647 deUint32 Q012 = data.getNext(3); 648 m[1] = data.getNext(numBits); 649 deUint32 Q34 = data.getNext(2); 650 m[2] = data.getNext(numBits); 651 deUint32 Q56 = data.getNext(2); 652 653 switch (numValues) 654 { 655 // \note Fall-throughs. 656 case 1: Q34 = 0; 657 case 2: Q56 = 0; 658 case 3: break; 659 default: 660 DE_ASSERT(false); 661 } 662 663 const deUint32 Q = (Q56 << 5) | (Q34 << 3) | (Q012 << 0); 664 665 static const deUint32 quintsFromQ[256][3] = 666 { 667 { 0,0,0 }, { 1,0,0 }, { 2,0,0 }, { 3,0,0 }, { 4,0,0 }, { 0,4,0 }, { 4,4,0 }, { 4,4,4 }, { 0,1,0 }, { 1,1,0 }, { 2,1,0 }, { 3,1,0 }, { 4,1,0 }, { 1,4,0 }, { 4,4,1 }, { 4,4,4 }, 668 { 0,2,0 }, { 1,2,0 }, { 2,2,0 }, { 3,2,0 }, { 4,2,0 }, { 2,4,0 }, { 4,4,2 }, { 4,4,4 }, { 0,3,0 }, { 1,3,0 }, { 2,3,0 }, { 3,3,0 }, { 4,3,0 }, { 3,4,0 }, { 4,4,3 }, { 4,4,4 }, 669 { 0,0,1 }, { 1,0,1 }, { 2,0,1 }, { 3,0,1 }, { 4,0,1 }, { 0,4,1 }, { 4,0,4 }, { 0,4,4 }, { 0,1,1 }, { 1,1,1 }, { 2,1,1 }, { 3,1,1 }, { 4,1,1 }, { 1,4,1 }, { 4,1,4 }, { 1,4,4 }, 670 { 0,2,1 }, { 1,2,1 }, { 2,2,1 }, { 3,2,1 }, { 4,2,1 }, { 2,4,1 }, { 4,2,4 }, { 2,4,4 }, { 0,3,1 }, { 1,3,1 }, { 2,3,1 }, { 3,3,1 }, { 4,3,1 }, { 3,4,1 }, { 4,3,4 }, { 3,4,4 }, 671 { 0,0,2 }, { 1,0,2 }, { 2,0,2 }, { 3,0,2 }, { 4,0,2 }, { 0,4,2 }, { 2,0,4 }, { 3,0,4 }, { 0,1,2 }, { 1,1,2 }, { 2,1,2 }, { 3,1,2 }, { 4,1,2 }, { 1,4,2 }, { 2,1,4 }, { 3,1,4 }, 672 { 0,2,2 }, { 1,2,2 }, { 2,2,2 }, { 3,2,2 }, { 4,2,2 }, { 2,4,2 }, { 2,2,4 }, { 3,2,4 }, { 0,3,2 }, { 1,3,2 }, { 2,3,2 }, { 3,3,2 }, { 4,3,2 }, { 3,4,2 }, { 2,3,4 }, { 3,3,4 }, 673 { 0,0,3 }, { 1,0,3 }, { 2,0,3 }, { 3,0,3 }, { 4,0,3 }, { 0,4,3 }, { 0,0,4 }, { 1,0,4 }, { 0,1,3 }, { 1,1,3 }, { 2,1,3 }, { 3,1,3 }, { 4,1,3 }, { 1,4,3 }, { 0,1,4 }, { 1,1,4 }, 674 { 0,2,3 }, { 1,2,3 }, { 2,2,3 }, { 3,2,3 }, { 4,2,3 }, { 2,4,3 }, { 0,2,4 }, { 1,2,4 }, { 0,3,3 }, { 1,3,3 }, { 2,3,3 }, { 3,3,3 }, { 4,3,3 }, { 3,4,3 }, { 0,3,4 }, { 1,3,4 } 675 }; 676 677 const deUint32 (& quints)[3] = quintsFromQ[Q]; 678 679 for (int i = 0; i < numValues; i++) 680 { 681 dst[i].m = m[i]; 682 dst[i].tq = quints[i]; 683 dst[i].v = (quints[i] << numBits) + m[i]; 684 } 685} 686 687inline void decodeISEBitBlock (ISEDecodedResult* dst, BitAccessStream& data, int numBits) 688{ 689 dst[0].m = data.getNext(numBits); 690 dst[0].v = dst[0].m; 691} 692 693void decodeISE (ISEDecodedResult* dst, int numValues, BitAccessStream& data, const ISEParams& params) 694{ 695 if (params.mode == ISEMODE_TRIT) 696 { 697 const int numBlocks = deDivRoundUp32(numValues, 5); 698 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++) 699 { 700 const int numValuesInBlock = blockNdx == numBlocks-1 ? numValues - 5*(numBlocks-1) : 5; 701 decodeISETritBlock(&dst[5*blockNdx], numValuesInBlock, data, params.numBits); 702 } 703 } 704 else if (params.mode == ISEMODE_QUINT) 705 { 706 const int numBlocks = deDivRoundUp32(numValues, 3); 707 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++) 708 { 709 const int numValuesInBlock = blockNdx == numBlocks-1 ? numValues - 3*(numBlocks-1) : 3; 710 decodeISEQuintBlock(&dst[3*blockNdx], numValuesInBlock, data, params.numBits); 711 } 712 } 713 else 714 { 715 DE_ASSERT(params.mode == ISEMODE_PLAIN_BIT); 716 for (int i = 0; i < numValues; i++) 717 decodeISEBitBlock(&dst[i], data, params.numBits); 718 } 719} 720 721void unquantizeColorEndpoints (deUint32* dst, const ISEDecodedResult* iseResults, int numEndpoints, const ISEParams& iseParams) 722{ 723 if (iseParams.mode == ISEMODE_TRIT || iseParams.mode == ISEMODE_QUINT) 724 { 725 const int rangeCase = iseParams.numBits*2 - (iseParams.mode == ISEMODE_TRIT ? 2 : 1); 726 DE_ASSERT(de::inRange(rangeCase, 0, 10)); 727 static const deUint32 Ca[11] = { 204, 113, 93, 54, 44, 26, 22, 13, 11, 6, 5 }; 728 const deUint32 C = Ca[rangeCase]; 729 730 for (int endpointNdx = 0; endpointNdx < numEndpoints; endpointNdx++) 731 { 732 const deUint32 a = getBit(iseResults[endpointNdx].m, 0); 733 const deUint32 b = getBit(iseResults[endpointNdx].m, 1); 734 const deUint32 c = getBit(iseResults[endpointNdx].m, 2); 735 const deUint32 d = getBit(iseResults[endpointNdx].m, 3); 736 const deUint32 e = getBit(iseResults[endpointNdx].m, 4); 737 const deUint32 f = getBit(iseResults[endpointNdx].m, 5); 738 739 const deUint32 A = a == 0 ? 0 : (1<<9)-1; 740 const deUint32 B = rangeCase == 0 ? 0 741 : rangeCase == 1 ? 0 742 : rangeCase == 2 ? (b << 8) | (b << 4) | (b << 2) | (b << 1) 743 : rangeCase == 3 ? (b << 8) | (b << 3) | (b << 2) 744 : rangeCase == 4 ? (c << 8) | (b << 7) | (c << 3) | (b << 2) | (c << 1) | (b << 0) 745 : rangeCase == 5 ? (c << 8) | (b << 7) | (c << 2) | (b << 1) | (c << 0) 746 : rangeCase == 6 ? (d << 8) | (c << 7) | (b << 6) | (d << 2) | (c << 1) | (b << 0) 747 : rangeCase == 7 ? (d << 8) | (c << 7) | (b << 6) | (d << 1) | (c << 0) 748 : rangeCase == 8 ? (e << 8) | (d << 7) | (c << 6) | (b << 5) | (e << 1) | (d << 0) 749 : rangeCase == 9 ? (e << 8) | (d << 7) | (c << 6) | (b << 5) | (e << 0) 750 : rangeCase == 10 ? (f << 8) | (e << 7) | (d << 6) | (c << 5) | (b << 4) | (f << 0) 751 : (deUint32)-1; 752 DE_ASSERT(B != (deUint32)-1); 753 754 dst[endpointNdx] = (((iseResults[endpointNdx].tq*C + B) ^ A) >> 2) | (A & 0x80); 755 } 756 } 757 else 758 { 759 DE_ASSERT(iseParams.mode == ISEMODE_PLAIN_BIT); 760 761 for (int endpointNdx = 0; endpointNdx < numEndpoints; endpointNdx++) 762 dst[endpointNdx] = bitReplicationScale(iseResults[endpointNdx].v, iseParams.numBits, 8); 763 } 764} 765 766inline void bitTransferSigned (deInt32& a, deInt32& b) 767{ 768 b >>= 1; 769 b |= a & 0x80; 770 a >>= 1; 771 a &= 0x3f; 772 if (isBitSet(a, 5)) 773 a -= 0x40; 774} 775 776inline UVec4 clampedRGBA (const IVec4& rgba) 777{ 778 return UVec4(de::clamp(rgba.x(), 0, 0xff), 779 de::clamp(rgba.y(), 0, 0xff), 780 de::clamp(rgba.z(), 0, 0xff), 781 de::clamp(rgba.w(), 0, 0xff)); 782} 783 784inline IVec4 blueContract (int r, int g, int b, int a) 785{ 786 return IVec4((r+b)>>1, (g+b)>>1, b, a); 787} 788 789inline bool isColorEndpointModeHDR (deUint32 mode) 790{ 791 return mode == 2 || 792 mode == 3 || 793 mode == 7 || 794 mode == 11 || 795 mode == 14 || 796 mode == 15; 797} 798 799void decodeHDREndpointMode7 (UVec4& e0, UVec4& e1, deUint32 v0, deUint32 v1, deUint32 v2, deUint32 v3) 800{ 801 const deUint32 m10 = getBit(v1, 7) | (getBit(v2, 7) << 1); 802 const deUint32 m23 = getBits(v0, 6, 7); 803 const deUint32 majComp = m10 != 3 ? m10 804 : m23 != 3 ? m23 805 : 0; 806 const deUint32 mode = m10 != 3 ? m23 807 : m23 != 3 ? 4 808 : 5; 809 810 deInt32 red = (deInt32)getBits(v0, 0, 5); 811 deInt32 green = (deInt32)getBits(v1, 0, 4); 812 deInt32 blue = (deInt32)getBits(v2, 0, 4); 813 deInt32 scale = (deInt32)getBits(v3, 0, 4); 814 815 { 816#define SHOR(DST_VAR, SHIFT, BIT_VAR) (DST_VAR) |= (BIT_VAR) << (SHIFT) 817#define ASSIGN_X_BITS(V0,S0, V1,S1, V2,S2, V3,S3, V4,S4, V5,S5, V6,S6) do { SHOR(V0,S0,x0); SHOR(V1,S1,x1); SHOR(V2,S2,x2); SHOR(V3,S3,x3); SHOR(V4,S4,x4); SHOR(V5,S5,x5); SHOR(V6,S6,x6); } while (false) 818 819 const deUint32 x0 = getBit(v1, 6); 820 const deUint32 x1 = getBit(v1, 5); 821 const deUint32 x2 = getBit(v2, 6); 822 const deUint32 x3 = getBit(v2, 5); 823 const deUint32 x4 = getBit(v3, 7); 824 const deUint32 x5 = getBit(v3, 6); 825 const deUint32 x6 = getBit(v3, 5); 826 827 deInt32& R = red; 828 deInt32& G = green; 829 deInt32& B = blue; 830 deInt32& S = scale; 831 832 switch (mode) 833 { 834 case 0: ASSIGN_X_BITS(R,9, R,8, R,7, R,10, R,6, S,6, S,5); break; 835 case 1: ASSIGN_X_BITS(R,8, G,5, R,7, B,5, R,6, R,10, R,9); break; 836 case 2: ASSIGN_X_BITS(R,9, R,8, R,7, R,6, S,7, S,6, S,5); break; 837 case 3: ASSIGN_X_BITS(R,8, G,5, R,7, B,5, R,6, S,6, S,5); break; 838 case 4: ASSIGN_X_BITS(G,6, G,5, B,6, B,5, R,6, R,7, S,5); break; 839 case 5: ASSIGN_X_BITS(G,6, G,5, B,6, B,5, R,6, S,6, S,5); break; 840 default: 841 DE_ASSERT(false); 842 } 843 844#undef ASSIGN_X_BITS 845#undef SHOR 846 } 847 848 static const int shiftAmounts[] = { 1, 1, 2, 3, 4, 5 }; 849 DE_ASSERT(mode < DE_LENGTH_OF_ARRAY(shiftAmounts)); 850 851 red <<= shiftAmounts[mode]; 852 green <<= shiftAmounts[mode]; 853 blue <<= shiftAmounts[mode]; 854 scale <<= shiftAmounts[mode]; 855 856 if (mode != 5) 857 { 858 green = red - green; 859 blue = red - blue; 860 } 861 862 if (majComp == 1) 863 std::swap(red, green); 864 else if (majComp == 2) 865 std::swap(red, blue); 866 867 e0 = UVec4(de::clamp(red - scale, 0, 0xfff), 868 de::clamp(green - scale, 0, 0xfff), 869 de::clamp(blue - scale, 0, 0xfff), 870 0x780); 871 872 e1 = UVec4(de::clamp(red, 0, 0xfff), 873 de::clamp(green, 0, 0xfff), 874 de::clamp(blue, 0, 0xfff), 875 0x780); 876} 877 878void decodeHDREndpointMode11 (UVec4& e0, UVec4& e1, deUint32 v0, deUint32 v1, deUint32 v2, deUint32 v3, deUint32 v4, deUint32 v5) 879{ 880 const deUint32 major = (getBit(v5, 7) << 1) | getBit(v4, 7); 881 882 if (major == 3) 883 { 884 e0 = UVec4(v0<<4, v2<<4, getBits(v4,0,6)<<5, 0x780); 885 e1 = UVec4(v1<<4, v3<<4, getBits(v5,0,6)<<5, 0x780); 886 } 887 else 888 { 889 const deUint32 mode = (getBit(v3, 7) << 2) | (getBit(v2, 7) << 1) | getBit(v1, 7); 890 891 deInt32 a = (deInt32)((getBit(v1, 6) << 8) | v0); 892 deInt32 c = (deInt32)(getBits(v1, 0, 5)); 893 deInt32 b0 = (deInt32)(getBits(v2, 0, 5)); 894 deInt32 b1 = (deInt32)(getBits(v3, 0, 5)); 895 deInt32 d0 = (deInt32)(getBits(v4, 0, 4)); 896 deInt32 d1 = (deInt32)(getBits(v5, 0, 4)); 897 898 { 899#define SHOR(DST_VAR, SHIFT, BIT_VAR) (DST_VAR) |= (BIT_VAR) << (SHIFT) 900#define ASSIGN_X_BITS(V0,S0, V1,S1, V2,S2, V3,S3, V4,S4, V5,S5) do { SHOR(V0,S0,x0); SHOR(V1,S1,x1); SHOR(V2,S2,x2); SHOR(V3,S3,x3); SHOR(V4,S4,x4); SHOR(V5,S5,x5); } while (false) 901 902 const deUint32 x0 = getBit(v2, 6); 903 const deUint32 x1 = getBit(v3, 6); 904 const deUint32 x2 = getBit(v4, 6); 905 const deUint32 x3 = getBit(v5, 6); 906 const deUint32 x4 = getBit(v4, 5); 907 const deUint32 x5 = getBit(v5, 5); 908 909 switch (mode) 910 { 911 case 0: ASSIGN_X_BITS(b0,6, b1,6, d0,6, d1,6, d0,5, d1,5); break; 912 case 1: ASSIGN_X_BITS(b0,6, b1,6, b0,7, b1,7, d0,5, d1,5); break; 913 case 2: ASSIGN_X_BITS(a,9, c,6, d0,6, d1,6, d0,5, d1,5); break; 914 case 3: ASSIGN_X_BITS(b0,6, b1,6, a,9, c,6, d0,5, d1,5); break; 915 case 4: ASSIGN_X_BITS(b0,6, b1,6, b0,7, b1,7, a,9, a,10); break; 916 case 5: ASSIGN_X_BITS(a,9, a,10, c,7, c,6, d0,5, d1,5); break; 917 case 6: ASSIGN_X_BITS(b0,6, b1,6, a,11, c,6, a,9, a,10); break; 918 case 7: ASSIGN_X_BITS(a,9, a,10, a,11, c,6, d0,5, d1,5); break; 919 default: 920 DE_ASSERT(false); 921 } 922 923#undef ASSIGN_X_BITS 924#undef SHOR 925 } 926 927 static const int numDBits[] = { 7, 6, 7, 6, 5, 6, 5, 6 }; 928 DE_ASSERT(mode < DE_LENGTH_OF_ARRAY(numDBits)); 929 930 d0 = signExtend(d0, numDBits[mode]); 931 d1 = signExtend(d1, numDBits[mode]); 932 933 const int shiftAmount = (mode >> 1) ^ 3; 934 a <<= shiftAmount; 935 c <<= shiftAmount; 936 b0 <<= shiftAmount; 937 b1 <<= shiftAmount; 938 d0 <<= shiftAmount; 939 d1 <<= shiftAmount; 940 941 e0 = UVec4(de::clamp(a-c, 0, 0xfff), 942 de::clamp(a-b0-c-d0, 0, 0xfff), 943 de::clamp(a-b1-c-d1, 0, 0xfff), 944 0x780); 945 946 e1 = UVec4(de::clamp(a, 0, 0xfff), 947 de::clamp(a-b0, 0, 0xfff), 948 de::clamp(a-b1, 0, 0xfff), 949 0x780); 950 951 if (major == 1) 952 { 953 std::swap(e0.x(), e0.y()); 954 std::swap(e1.x(), e1.y()); 955 } 956 else if (major == 2) 957 { 958 std::swap(e0.x(), e0.z()); 959 std::swap(e1.x(), e1.z()); 960 } 961 } 962} 963 964void decodeHDREndpointMode15(UVec4& e0, UVec4& e1, deUint32 v0, deUint32 v1, deUint32 v2, deUint32 v3, deUint32 v4, deUint32 v5, deUint32 v6In, deUint32 v7In) 965{ 966 decodeHDREndpointMode11(e0, e1, v0, v1, v2, v3, v4, v5); 967 968 const deUint32 mode = (getBit(v7In, 7) << 1) | getBit(v6In, 7); 969 deInt32 v6 = (deInt32)getBits(v6In, 0, 6); 970 deInt32 v7 = (deInt32)getBits(v7In, 0, 6); 971 972 if (mode == 3) 973 { 974 e0.w() = v6 << 5; 975 e1.w() = v7 << 5; 976 } 977 else 978 { 979 v6 |= (v7 << (mode+1)) & 0x780; 980 v7 &= (0x3f >> mode); 981 v7 ^= 0x20 >> mode; 982 v7 -= 0x20 >> mode; 983 v6 <<= 4-mode; 984 v7 <<= 4-mode; 985 986 v7 += v6; 987 v7 = de::clamp(v7, 0, 0xfff); 988 e0.w() = v6; 989 e1.w() = v7; 990 } 991} 992 993void decodeColorEndpoints (ColorEndpointPair* dst, const deUint32* unquantizedEndpoints, const deUint32* endpointModes, int numPartitions) 994{ 995 int unquantizedNdx = 0; 996 997 for (int partitionNdx = 0; partitionNdx < numPartitions; partitionNdx++) 998 { 999 const deUint32 endpointMode = endpointModes[partitionNdx]; 1000 const deUint32* v = &unquantizedEndpoints[unquantizedNdx]; 1001 UVec4& e0 = dst[partitionNdx].e0; 1002 UVec4& e1 = dst[partitionNdx].e1; 1003 1004 unquantizedNdx += computeNumColorEndpointValues(endpointMode); 1005 1006 switch (endpointMode) 1007 { 1008 case 0: 1009 e0 = UVec4(v[0], v[0], v[0], 0xff); 1010 e1 = UVec4(v[1], v[1], v[1], 0xff); 1011 break; 1012 1013 case 1: 1014 { 1015 const deUint32 L0 = (v[0] >> 2) | (getBits(v[1], 6, 7) << 6); 1016 const deUint32 L1 = de::min(0xffu, L0 + getBits(v[1], 0, 5)); 1017 e0 = UVec4(L0, L0, L0, 0xff); 1018 e1 = UVec4(L1, L1, L1, 0xff); 1019 break; 1020 } 1021 1022 case 2: 1023 { 1024 const deUint32 v1Gr = v[1] >= v[0]; 1025 const deUint32 y0 = v1Gr ? v[0]<<4 : (v[1]<<4) + 8; 1026 const deUint32 y1 = v1Gr ? v[1]<<4 : (v[0]<<4) - 8; 1027 1028 e0 = UVec4(y0, y0, y0, 0x780); 1029 e1 = UVec4(y1, y1, y1, 0x780); 1030 break; 1031 } 1032 1033 case 3: 1034 { 1035 const bool m = isBitSet(v[0], 7); 1036 const deUint32 y0 = m ? (getBits(v[1], 5, 7) << 9) | (getBits(v[0], 0, 6) << 2) 1037 : (getBits(v[1], 4, 7) << 8) | (getBits(v[0], 0, 6) << 1); 1038 const deUint32 d = m ? getBits(v[1], 0, 4) << 2 1039 : getBits(v[1], 0, 3) << 1; 1040 const deUint32 y1 = de::min(0xfffu, y0+d); 1041 1042 e0 = UVec4(y0, y0, y0, 0x780); 1043 e1 = UVec4(y1, y1, y1, 0x780); 1044 break; 1045 } 1046 1047 case 4: 1048 e0 = UVec4(v[0], v[0], v[0], v[2]); 1049 e1 = UVec4(v[1], v[1], v[1], v[3]); 1050 break; 1051 1052 case 5: 1053 { 1054 deInt32 v0 = (deInt32)v[0]; 1055 deInt32 v1 = (deInt32)v[1]; 1056 deInt32 v2 = (deInt32)v[2]; 1057 deInt32 v3 = (deInt32)v[3]; 1058 bitTransferSigned(v1, v0); 1059 bitTransferSigned(v3, v2); 1060 1061 e0 = clampedRGBA(IVec4(v0, v0, v0, v2)); 1062 e1 = clampedRGBA(IVec4(v0+v1, v0+v1, v0+v1, v2+v3)); 1063 break; 1064 } 1065 1066 case 6: 1067 e0 = UVec4((v[0]*v[3]) >> 8, (v[1]*v[3]) >> 8, (v[2]*v[3]) >> 8, 0xff); 1068 e1 = UVec4(v[0], v[1], v[2], 0xff); 1069 break; 1070 1071 case 7: 1072 decodeHDREndpointMode7(e0, e1, v[0], v[1], v[2], v[3]); 1073 break; 1074 1075 case 8: 1076 if (v[1]+v[3]+v[5] >= v[0]+v[2]+v[4]) 1077 { 1078 e0 = UVec4(v[0], v[2], v[4], 0xff); 1079 e1 = UVec4(v[1], v[3], v[5], 0xff); 1080 } 1081 else 1082 { 1083 e0 = blueContract(v[1], v[3], v[5], 0xff).asUint(); 1084 e1 = blueContract(v[0], v[2], v[4], 0xff).asUint(); 1085 } 1086 break; 1087 1088 case 9: 1089 { 1090 deInt32 v0 = (deInt32)v[0]; 1091 deInt32 v1 = (deInt32)v[1]; 1092 deInt32 v2 = (deInt32)v[2]; 1093 deInt32 v3 = (deInt32)v[3]; 1094 deInt32 v4 = (deInt32)v[4]; 1095 deInt32 v5 = (deInt32)v[5]; 1096 bitTransferSigned(v1, v0); 1097 bitTransferSigned(v3, v2); 1098 bitTransferSigned(v5, v4); 1099 1100 if (v1+v3+v5 >= 0) 1101 { 1102 e0 = clampedRGBA(IVec4(v0, v2, v4, 0xff)); 1103 e1 = clampedRGBA(IVec4(v0+v1, v2+v3, v4+v5, 0xff)); 1104 } 1105 else 1106 { 1107 e0 = clampedRGBA(blueContract(v0+v1, v2+v3, v4+v5, 0xff)); 1108 e1 = clampedRGBA(blueContract(v0, v2, v4, 0xff)); 1109 } 1110 break; 1111 } 1112 1113 case 10: 1114 e0 = UVec4((v[0]*v[3]) >> 8, (v[1]*v[3]) >> 8, (v[2]*v[3]) >> 8, v[4]); 1115 e1 = UVec4(v[0], v[1], v[2], v[5]); 1116 break; 1117 1118 case 11: 1119 decodeHDREndpointMode11(e0, e1, v[0], v[1], v[2], v[3], v[4], v[5]); 1120 break; 1121 1122 case 12: 1123 if (v[1]+v[3]+v[5] >= v[0]+v[2]+v[4]) 1124 { 1125 e0 = UVec4(v[0], v[2], v[4], v[6]); 1126 e1 = UVec4(v[1], v[3], v[5], v[7]); 1127 } 1128 else 1129 { 1130 e0 = clampedRGBA(blueContract(v[1], v[3], v[5], v[7])); 1131 e1 = clampedRGBA(blueContract(v[0], v[2], v[4], v[6])); 1132 } 1133 break; 1134 1135 case 13: 1136 { 1137 deInt32 v0 = (deInt32)v[0]; 1138 deInt32 v1 = (deInt32)v[1]; 1139 deInt32 v2 = (deInt32)v[2]; 1140 deInt32 v3 = (deInt32)v[3]; 1141 deInt32 v4 = (deInt32)v[4]; 1142 deInt32 v5 = (deInt32)v[5]; 1143 deInt32 v6 = (deInt32)v[6]; 1144 deInt32 v7 = (deInt32)v[7]; 1145 bitTransferSigned(v1, v0); 1146 bitTransferSigned(v3, v2); 1147 bitTransferSigned(v5, v4); 1148 bitTransferSigned(v7, v6); 1149 1150 if (v1+v3+v5 >= 0) 1151 { 1152 e0 = clampedRGBA(IVec4(v0, v2, v4, v6)); 1153 e1 = clampedRGBA(IVec4(v0+v1, v2+v3, v4+v5, v6+v7)); 1154 } 1155 else 1156 { 1157 e0 = clampedRGBA(blueContract(v0+v1, v2+v3, v4+v5, v6+v7)); 1158 e1 = clampedRGBA(blueContract(v0, v2, v4, v6)); 1159 } 1160 1161 break; 1162 } 1163 1164 case 14: 1165 decodeHDREndpointMode11(e0, e1, v[0], v[1], v[2], v[3], v[4], v[5]); 1166 e0.w() = v[6]; 1167 e1.w() = v[7]; 1168 break; 1169 1170 case 15: 1171 decodeHDREndpointMode15(e0, e1, v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7]); 1172 break; 1173 1174 default: 1175 DE_ASSERT(false); 1176 } 1177 } 1178} 1179 1180void computeColorEndpoints (ColorEndpointPair* dst, const Block128& blockData, const deUint32* endpointModes, int numPartitions, int numColorEndpointValues, const ISEParams& iseParams, int numBitsAvailable) 1181{ 1182 const int colorEndpointDataStart = numPartitions == 1 ? 17 : 29; 1183 ISEDecodedResult colorEndpointData[18]; 1184 1185 { 1186 BitAccessStream dataStream(blockData, colorEndpointDataStart, numBitsAvailable, true); 1187 decodeISE(&colorEndpointData[0], numColorEndpointValues, dataStream, iseParams); 1188 } 1189 1190 { 1191 deUint32 unquantizedEndpoints[18]; 1192 unquantizeColorEndpoints(&unquantizedEndpoints[0], &colorEndpointData[0], numColorEndpointValues, iseParams); 1193 decodeColorEndpoints(dst, &unquantizedEndpoints[0], &endpointModes[0], numPartitions); 1194 } 1195} 1196 1197void unquantizeWeights (deUint32 dst[64], const ISEDecodedResult* weightGrid, const ASTCBlockMode& blockMode) 1198{ 1199 const int numWeights = computeNumWeights(blockMode); 1200 const ISEParams& iseParams = blockMode.weightISEParams; 1201 1202 if (iseParams.mode == ISEMODE_TRIT || iseParams.mode == ISEMODE_QUINT) 1203 { 1204 const int rangeCase = iseParams.numBits*2 + (iseParams.mode == ISEMODE_QUINT ? 1 : 0); 1205 1206 if (rangeCase == 0 || rangeCase == 1) 1207 { 1208 static const deUint32 map0[3] = { 0, 32, 63 }; 1209 static const deUint32 map1[5] = { 0, 16, 32, 47, 63 }; 1210 const deUint32* const map = rangeCase == 0 ? &map0[0] : &map1[0]; 1211 for (int i = 0; i < numWeights; i++) 1212 { 1213 DE_ASSERT(weightGrid[i].v < (rangeCase == 0 ? 3u : 5u)); 1214 dst[i] = map[weightGrid[i].v]; 1215 } 1216 } 1217 else 1218 { 1219 DE_ASSERT(rangeCase <= 6); 1220 static const deUint32 Ca[5] = { 50, 28, 23, 13, 11 }; 1221 const deUint32 C = Ca[rangeCase-2]; 1222 1223 for (int weightNdx = 0; weightNdx < numWeights; weightNdx++) 1224 { 1225 const deUint32 a = getBit(weightGrid[weightNdx].m, 0); 1226 const deUint32 b = getBit(weightGrid[weightNdx].m, 1); 1227 const deUint32 c = getBit(weightGrid[weightNdx].m, 2); 1228 1229 const deUint32 A = a == 0 ? 0 : (1<<7)-1; 1230 const deUint32 B = rangeCase == 2 ? 0 1231 : rangeCase == 3 ? 0 1232 : rangeCase == 4 ? (b << 6) | (b << 2) | (b << 0) 1233 : rangeCase == 5 ? (b << 6) | (b << 1) 1234 : rangeCase == 6 ? (c << 6) | (b << 5) | (c << 1) | (b << 0) 1235 : (deUint32)-1; 1236 1237 dst[weightNdx] = (((weightGrid[weightNdx].tq*C + B) ^ A) >> 2) | (A & 0x20); 1238 } 1239 } 1240 } 1241 else 1242 { 1243 DE_ASSERT(iseParams.mode == ISEMODE_PLAIN_BIT); 1244 1245 for (int weightNdx = 0; weightNdx < numWeights; weightNdx++) 1246 dst[weightNdx] = bitReplicationScale(weightGrid[weightNdx].v, iseParams.numBits, 6); 1247 } 1248 1249 for (int weightNdx = 0; weightNdx < numWeights; weightNdx++) 1250 dst[weightNdx] += dst[weightNdx] > 32 ? 1 : 0; 1251 1252 // Initialize nonexistent weights to poison values 1253 for (int weightNdx = numWeights; weightNdx < 64; weightNdx++) 1254 dst[weightNdx] = ~0u; 1255 1256} 1257 1258void interpolateWeights (TexelWeightPair* dst, const deUint32 (&unquantizedWeights) [64], int blockWidth, int blockHeight, const ASTCBlockMode& blockMode) 1259{ 1260 const int numWeightsPerTexel = blockMode.isDualPlane ? 2 : 1; 1261 const deUint32 scaleX = (1024 + blockWidth/2) / (blockWidth-1); 1262 const deUint32 scaleY = (1024 + blockHeight/2) / (blockHeight-1); 1263 1264 DE_ASSERT(blockMode.weightGridWidth*blockMode.weightGridHeight*numWeightsPerTexel <= DE_LENGTH_OF_ARRAY(unquantizedWeights)); 1265 1266 for (int texelY = 0; texelY < blockHeight; texelY++) 1267 { 1268 for (int texelX = 0; texelX < blockWidth; texelX++) 1269 { 1270 const deUint32 gX = (scaleX*texelX*(blockMode.weightGridWidth-1) + 32) >> 6; 1271 const deUint32 gY = (scaleY*texelY*(blockMode.weightGridHeight-1) + 32) >> 6; 1272 const deUint32 jX = gX >> 4; 1273 const deUint32 jY = gY >> 4; 1274 const deUint32 fX = gX & 0xf; 1275 const deUint32 fY = gY & 0xf; 1276 1277 const deUint32 w11 = (fX*fY + 8) >> 4; 1278 const deUint32 w10 = fY - w11; 1279 const deUint32 w01 = fX - w11; 1280 const deUint32 w00 = 16 - fX - fY + w11; 1281 1282 const deUint32 i00 = jY*blockMode.weightGridWidth + jX; 1283 const deUint32 i01 = i00 + 1; 1284 const deUint32 i10 = i00 + blockMode.weightGridWidth; 1285 const deUint32 i11 = i00 + blockMode.weightGridWidth + 1; 1286 1287 // These addresses can be out of bounds, but respective weights will be 0 then. 1288 DE_ASSERT(deInBounds32(i00, 0, blockMode.weightGridWidth*blockMode.weightGridHeight) || w00 == 0); 1289 DE_ASSERT(deInBounds32(i01, 0, blockMode.weightGridWidth*blockMode.weightGridHeight) || w01 == 0); 1290 DE_ASSERT(deInBounds32(i10, 0, blockMode.weightGridWidth*blockMode.weightGridHeight) || w10 == 0); 1291 DE_ASSERT(deInBounds32(i11, 0, blockMode.weightGridWidth*blockMode.weightGridHeight) || w11 == 0); 1292 1293 for (int texelWeightNdx = 0; texelWeightNdx < numWeightsPerTexel; texelWeightNdx++) 1294 { 1295 // & 0x3f clamps address to bounds of unquantizedWeights 1296 const deUint32 p00 = unquantizedWeights[(i00 * numWeightsPerTexel + texelWeightNdx) & 0x3f]; 1297 const deUint32 p01 = unquantizedWeights[(i01 * numWeightsPerTexel + texelWeightNdx) & 0x3f]; 1298 const deUint32 p10 = unquantizedWeights[(i10 * numWeightsPerTexel + texelWeightNdx) & 0x3f]; 1299 const deUint32 p11 = unquantizedWeights[(i11 * numWeightsPerTexel + texelWeightNdx) & 0x3f]; 1300 1301 dst[texelY*blockWidth + texelX].w[texelWeightNdx] = (p00*w00 + p01*w01 + p10*w10 + p11*w11 + 8) >> 4; 1302 } 1303 } 1304 } 1305} 1306 1307void computeTexelWeights (TexelWeightPair* dst, const Block128& blockData, int blockWidth, int blockHeight, const ASTCBlockMode& blockMode) 1308{ 1309 ISEDecodedResult weightGrid[64]; 1310 1311 { 1312 BitAccessStream dataStream(blockData, 127, computeNumRequiredBits(blockMode.weightISEParams, computeNumWeights(blockMode)), false); 1313 decodeISE(&weightGrid[0], computeNumWeights(blockMode), dataStream, blockMode.weightISEParams); 1314 } 1315 1316 { 1317 deUint32 unquantizedWeights[64]; 1318 unquantizeWeights(&unquantizedWeights[0], &weightGrid[0], blockMode); 1319 interpolateWeights(dst, unquantizedWeights, blockWidth, blockHeight, blockMode); 1320 } 1321} 1322 1323inline deUint32 hash52 (deUint32 v) 1324{ 1325 deUint32 p = v; 1326 p ^= p >> 15; p -= p << 17; p += p << 7; p += p << 4; 1327 p ^= p >> 5; p += p << 16; p ^= p >> 7; p ^= p >> 3; 1328 p ^= p << 6; p ^= p >> 17; 1329 return p; 1330} 1331 1332int computeTexelPartition (deUint32 seedIn, deUint32 xIn, deUint32 yIn, deUint32 zIn, int numPartitions, bool smallBlock) 1333{ 1334 DE_ASSERT(zIn == 0); 1335 const deUint32 x = smallBlock ? xIn << 1 : xIn; 1336 const deUint32 y = smallBlock ? yIn << 1 : yIn; 1337 const deUint32 z = smallBlock ? zIn << 1 : zIn; 1338 const deUint32 seed = seedIn + 1024*(numPartitions-1); 1339 const deUint32 rnum = hash52(seed); 1340 deUint8 seed1 = (deUint8)( rnum & 0xf); 1341 deUint8 seed2 = (deUint8)((rnum >> 4) & 0xf); 1342 deUint8 seed3 = (deUint8)((rnum >> 8) & 0xf); 1343 deUint8 seed4 = (deUint8)((rnum >> 12) & 0xf); 1344 deUint8 seed5 = (deUint8)((rnum >> 16) & 0xf); 1345 deUint8 seed6 = (deUint8)((rnum >> 20) & 0xf); 1346 deUint8 seed7 = (deUint8)((rnum >> 24) & 0xf); 1347 deUint8 seed8 = (deUint8)((rnum >> 28) & 0xf); 1348 deUint8 seed9 = (deUint8)((rnum >> 18) & 0xf); 1349 deUint8 seed10 = (deUint8)((rnum >> 22) & 0xf); 1350 deUint8 seed11 = (deUint8)((rnum >> 26) & 0xf); 1351 deUint8 seed12 = (deUint8)(((rnum >> 30) | (rnum << 2)) & 0xf); 1352 1353 seed1 = (deUint8)(seed1 * seed1 ); 1354 seed2 = (deUint8)(seed2 * seed2 ); 1355 seed3 = (deUint8)(seed3 * seed3 ); 1356 seed4 = (deUint8)(seed4 * seed4 ); 1357 seed5 = (deUint8)(seed5 * seed5 ); 1358 seed6 = (deUint8)(seed6 * seed6 ); 1359 seed7 = (deUint8)(seed7 * seed7 ); 1360 seed8 = (deUint8)(seed8 * seed8 ); 1361 seed9 = (deUint8)(seed9 * seed9 ); 1362 seed10 = (deUint8)(seed10 * seed10); 1363 seed11 = (deUint8)(seed11 * seed11); 1364 seed12 = (deUint8)(seed12 * seed12); 1365 1366 const int shA = (seed & 2) != 0 ? 4 : 5; 1367 const int shB = numPartitions == 3 ? 6 : 5; 1368 const int sh1 = (seed & 1) != 0 ? shA : shB; 1369 const int sh2 = (seed & 1) != 0 ? shB : shA; 1370 const int sh3 = (seed & 0x10) != 0 ? sh1 : sh2; 1371 1372 seed1 = (deUint8)(seed1 >> sh1); 1373 seed2 = (deUint8)(seed2 >> sh2); 1374 seed3 = (deUint8)(seed3 >> sh1); 1375 seed4 = (deUint8)(seed4 >> sh2); 1376 seed5 = (deUint8)(seed5 >> sh1); 1377 seed6 = (deUint8)(seed6 >> sh2); 1378 seed7 = (deUint8)(seed7 >> sh1); 1379 seed8 = (deUint8)(seed8 >> sh2); 1380 seed9 = (deUint8)(seed9 >> sh3); 1381 seed10 = (deUint8)(seed10 >> sh3); 1382 seed11 = (deUint8)(seed11 >> sh3); 1383 seed12 = (deUint8)(seed12 >> sh3); 1384 1385 const int a = 0x3f & (seed1*x + seed2*y + seed11*z + (rnum >> 14)); 1386 const int b = 0x3f & (seed3*x + seed4*y + seed12*z + (rnum >> 10)); 1387 const int c = numPartitions >= 3 ? 0x3f & (seed5*x + seed6*y + seed9*z + (rnum >> 6)) : 0; 1388 const int d = numPartitions >= 4 ? 0x3f & (seed7*x + seed8*y + seed10*z + (rnum >> 2)) : 0; 1389 1390 return a >= b && a >= c && a >= d ? 0 1391 : b >= c && b >= d ? 1 1392 : c >= d ? 2 1393 : 3; 1394} 1395 1396DecompressResult setTexelColors (void* dst, ColorEndpointPair* colorEndpoints, TexelWeightPair* texelWeights, int ccs, deUint32 partitionIndexSeed, 1397 int numPartitions, int blockWidth, int blockHeight, bool isSRGB, bool isLDRMode, const deUint32* colorEndpointModes) 1398{ 1399 const bool smallBlock = blockWidth*blockHeight < 31; 1400 DecompressResult result = DECOMPRESS_RESULT_VALID_BLOCK; 1401 bool isHDREndpoint[4]; 1402 1403 for (int i = 0; i < numPartitions; i++) 1404 isHDREndpoint[i] = isColorEndpointModeHDR(colorEndpointModes[i]); 1405 1406 for (int texelY = 0; texelY < blockHeight; texelY++) 1407 for (int texelX = 0; texelX < blockWidth; texelX++) 1408 { 1409 const int texelNdx = texelY*blockWidth + texelX; 1410 const int colorEndpointNdx = numPartitions == 1 ? 0 : computeTexelPartition(partitionIndexSeed, texelX, texelY, 0, numPartitions, smallBlock); 1411 DE_ASSERT(colorEndpointNdx < numPartitions); 1412 const UVec4& e0 = colorEndpoints[colorEndpointNdx].e0; 1413 const UVec4& e1 = colorEndpoints[colorEndpointNdx].e1; 1414 const TexelWeightPair& weight = texelWeights[texelNdx]; 1415 1416 if (isLDRMode && isHDREndpoint[colorEndpointNdx]) 1417 { 1418 if (isSRGB) 1419 { 1420 ((deUint8*)dst)[texelNdx*4 + 0] = 0xff; 1421 ((deUint8*)dst)[texelNdx*4 + 1] = 0; 1422 ((deUint8*)dst)[texelNdx*4 + 2] = 0xff; 1423 ((deUint8*)dst)[texelNdx*4 + 3] = 0xff; 1424 } 1425 else 1426 { 1427 ((float*)dst)[texelNdx*4 + 0] = 1.0f; 1428 ((float*)dst)[texelNdx*4 + 1] = 0; 1429 ((float*)dst)[texelNdx*4 + 2] = 1.0f; 1430 ((float*)dst)[texelNdx*4 + 3] = 1.0f; 1431 } 1432 1433 result = DECOMPRESS_RESULT_ERROR; 1434 } 1435 else 1436 { 1437 for (int channelNdx = 0; channelNdx < 4; channelNdx++) 1438 { 1439 if (!isHDREndpoint[colorEndpointNdx] || (channelNdx == 3 && colorEndpointModes[colorEndpointNdx] == 14)) // \note Alpha for mode 14 is treated the same as LDR. 1440 { 1441 const deUint32 c0 = (e0[channelNdx] << 8) | (isSRGB ? 0x80 : e0[channelNdx]); 1442 const deUint32 c1 = (e1[channelNdx] << 8) | (isSRGB ? 0x80 : e1[channelNdx]); 1443 const deUint32 w = weight.w[ccs == channelNdx ? 1 : 0]; 1444 const deUint32 c = (c0*(64-w) + c1*w + 32) / 64; 1445 1446 if (isSRGB) 1447 ((deUint8*)dst)[texelNdx*4 + channelNdx] = (deUint8)((c & 0xff00) >> 8); 1448 else 1449 ((float*)dst)[texelNdx*4 + channelNdx] = c == 65535 ? 1.0f : (float)c / 65536.0f; 1450 } 1451 else 1452 { 1453 DE_STATIC_ASSERT((de::meta::TypesSame<deFloat16, deUint16>::Value)); 1454 const deUint32 c0 = e0[channelNdx] << 4; 1455 const deUint32 c1 = e1[channelNdx] << 4; 1456 const deUint32 w = weight.w[ccs == channelNdx ? 1 : 0]; 1457 const deUint32 c = (c0*(64-w) + c1*w + 32) / 64; 1458 const deUint32 e = getBits(c, 11, 15); 1459 const deUint32 m = getBits(c, 0, 10); 1460 const deUint32 mt = m < 512 ? 3*m 1461 : m >= 1536 ? 5*m - 2048 1462 : 4*m - 512; 1463 const deFloat16 cf = (deFloat16)((e << 10) + (mt >> 3)); 1464 1465 ((float*)dst)[texelNdx*4 + channelNdx] = deFloat16To32(isFloat16InfOrNan(cf) ? 0x7bff : cf); 1466 } 1467 } 1468 } 1469 } 1470 1471 return result; 1472} 1473 1474DecompressResult decompressBlock (void* dst, const Block128& blockData, int blockWidth, int blockHeight, bool isSRGB, bool isLDR) 1475{ 1476 DE_ASSERT(isLDR || !isSRGB); 1477 1478 // Decode block mode. 1479 1480 const ASTCBlockMode blockMode = getASTCBlockMode(blockData.getBits(0, 10)); 1481 1482 // Check for block mode errors. 1483 1484 if (blockMode.isError) 1485 { 1486 setASTCErrorColorBlock(dst, blockWidth, blockHeight, isSRGB); 1487 return DECOMPRESS_RESULT_ERROR; 1488 } 1489 1490 // Separate path for void-extent. 1491 1492 if (blockMode.isVoidExtent) 1493 return decodeVoidExtentBlock(dst, blockData, blockWidth, blockHeight, isSRGB, isLDR); 1494 1495 // Compute weight grid values. 1496 1497 const int numWeights = computeNumWeights(blockMode); 1498 const int numWeightDataBits = computeNumRequiredBits(blockMode.weightISEParams, numWeights); 1499 const int numPartitions = (int)blockData.getBits(11, 12) + 1; 1500 1501 // Check for errors in weight grid, partition and dual-plane parameters. 1502 1503 if (numWeights > 64 || 1504 numWeightDataBits > 96 || 1505 numWeightDataBits < 24 || 1506 blockMode.weightGridWidth > blockWidth || 1507 blockMode.weightGridHeight > blockHeight || 1508 (numPartitions == 4 && blockMode.isDualPlane)) 1509 { 1510 setASTCErrorColorBlock(dst, blockWidth, blockHeight, isSRGB); 1511 return DECOMPRESS_RESULT_ERROR; 1512 } 1513 1514 // Compute number of bits available for color endpoint data. 1515 1516 const bool isSingleUniqueCem = numPartitions == 1 || blockData.getBits(23, 24) == 0; 1517 const int numConfigDataBits = (numPartitions == 1 ? 17 : isSingleUniqueCem ? 29 : 25 + 3*numPartitions) + 1518 (blockMode.isDualPlane ? 2 : 0); 1519 const int numBitsForColorEndpoints = 128 - numWeightDataBits - numConfigDataBits; 1520 const int extraCemBitsStart = 127 - numWeightDataBits - (isSingleUniqueCem ? -1 1521 : numPartitions == 4 ? 7 1522 : numPartitions == 3 ? 4 1523 : numPartitions == 2 ? 1 1524 : 0); 1525 // Decode color endpoint modes. 1526 1527 deUint32 colorEndpointModes[4]; 1528 decodeColorEndpointModes(&colorEndpointModes[0], blockData, numPartitions, extraCemBitsStart); 1529 1530 const int numColorEndpointValues = computeNumColorEndpointValues(colorEndpointModes, numPartitions); 1531 1532 // Check for errors in color endpoint value count. 1533 1534 if (numColorEndpointValues > 18 || numBitsForColorEndpoints < deDivRoundUp32(13*numColorEndpointValues, 5)) 1535 { 1536 setASTCErrorColorBlock(dst, blockWidth, blockHeight, isSRGB); 1537 return DECOMPRESS_RESULT_ERROR; 1538 } 1539 1540 // Compute color endpoints. 1541 1542 ColorEndpointPair colorEndpoints[4]; 1543 computeColorEndpoints(&colorEndpoints[0], blockData, &colorEndpointModes[0], numPartitions, numColorEndpointValues, 1544 computeMaximumRangeISEParams(numBitsForColorEndpoints, numColorEndpointValues), numBitsForColorEndpoints); 1545 1546 // Compute texel weights. 1547 1548 TexelWeightPair texelWeights[MAX_BLOCK_WIDTH*MAX_BLOCK_HEIGHT]; 1549 computeTexelWeights(&texelWeights[0], blockData, blockWidth, blockHeight, blockMode); 1550 1551 // Set texel colors. 1552 1553 const int ccs = blockMode.isDualPlane ? (int)blockData.getBits(extraCemBitsStart-2, extraCemBitsStart-1) : -1; 1554 const deUint32 partitionIndexSeed = numPartitions > 1 ? blockData.getBits(13, 22) : (deUint32)-1; 1555 1556 return setTexelColors(dst, &colorEndpoints[0], &texelWeights[0], ccs, partitionIndexSeed, numPartitions, blockWidth, blockHeight, isSRGB, isLDR, &colorEndpointModes[0]); 1557} 1558 1559void decompress (const PixelBufferAccess& dst, const deUint8* data, bool isSRGB, bool isLDR) 1560{ 1561 DE_ASSERT(isLDR || !isSRGB); 1562 1563 const int blockWidth = dst.getWidth(); 1564 const int blockHeight = dst.getHeight(); 1565 1566 union 1567 { 1568 deUint8 sRGB[MAX_BLOCK_WIDTH*MAX_BLOCK_HEIGHT*4]; 1569 float linear[MAX_BLOCK_WIDTH*MAX_BLOCK_HEIGHT*4]; 1570 } decompressedBuffer; 1571 1572 const Block128 blockData(data); 1573 decompressBlock(isSRGB ? (void*)&decompressedBuffer.sRGB[0] : (void*)&decompressedBuffer.linear[0], 1574 blockData, dst.getWidth(), dst.getHeight(), isSRGB, isLDR); 1575 1576 if (isSRGB) 1577 { 1578 for (int i = 0; i < blockHeight; i++) 1579 for (int j = 0; j < blockWidth; j++) 1580 { 1581 dst.setPixel(IVec4(decompressedBuffer.sRGB[(i*blockWidth + j) * 4 + 0], 1582 decompressedBuffer.sRGB[(i*blockWidth + j) * 4 + 1], 1583 decompressedBuffer.sRGB[(i*blockWidth + j) * 4 + 2], 1584 decompressedBuffer.sRGB[(i*blockWidth + j) * 4 + 3]), j, i); 1585 } 1586 } 1587 else 1588 { 1589 for (int i = 0; i < blockHeight; i++) 1590 for (int j = 0; j < blockWidth; j++) 1591 { 1592 dst.setPixel(Vec4(decompressedBuffer.linear[(i*blockWidth + j) * 4 + 0], 1593 decompressedBuffer.linear[(i*blockWidth + j) * 4 + 1], 1594 decompressedBuffer.linear[(i*blockWidth + j) * 4 + 2], 1595 decompressedBuffer.linear[(i*blockWidth + j) * 4 + 3]), j, i); 1596 } 1597 } 1598} 1599 1600// Helper class for setting bits in a 128-bit block. 1601class AssignBlock128 1602{ 1603private: 1604 typedef deUint64 Word; 1605 1606 enum 1607 { 1608 WORD_BYTES = sizeof(Word), 1609 WORD_BITS = 8*WORD_BYTES, 1610 NUM_WORDS = 128 / WORD_BITS 1611 }; 1612 1613 DE_STATIC_ASSERT(128 % WORD_BITS == 0); 1614 1615public: 1616 AssignBlock128 (void) 1617 { 1618 for (int wordNdx = 0; wordNdx < NUM_WORDS; wordNdx++) 1619 m_words[wordNdx] = 0; 1620 } 1621 1622 void setBit (int ndx, deUint32 val) 1623 { 1624 DE_ASSERT(de::inBounds(ndx, 0, 128)); 1625 DE_ASSERT((val & 1) == val); 1626 const int wordNdx = ndx / WORD_BITS; 1627 const int bitNdx = ndx % WORD_BITS; 1628 m_words[wordNdx] = (m_words[wordNdx] & ~((Word)1 << bitNdx)) | ((Word)val << bitNdx); 1629 } 1630 1631 void setBits (int low, int high, deUint32 bits) 1632 { 1633 DE_ASSERT(de::inBounds(low, 0, 128)); 1634 DE_ASSERT(de::inBounds(high, 0, 128)); 1635 DE_ASSERT(de::inRange(high-low+1, 0, 32)); 1636 DE_ASSERT((bits & (((Word)1 << (high-low+1)) - 1)) == bits); 1637 1638 if (high-low+1 == 0) 1639 return; 1640 1641 const int word0Ndx = low / WORD_BITS; 1642 const int word1Ndx = high / WORD_BITS; 1643 const int lowNdxInW0 = low % WORD_BITS; 1644 1645 if (word0Ndx == word1Ndx) 1646 m_words[word0Ndx] = (m_words[word0Ndx] & ~((((Word)1 << (high-low+1)) - 1) << lowNdxInW0)) | ((Word)bits << lowNdxInW0); 1647 else 1648 { 1649 DE_ASSERT(word1Ndx == word0Ndx + 1); 1650 1651 const int highNdxInW1 = high % WORD_BITS; 1652 const int numBitsToSetInW0 = WORD_BITS - lowNdxInW0; 1653 const Word bitsLowMask = ((Word)1 << numBitsToSetInW0) - 1; 1654 1655 m_words[word0Ndx] = (m_words[word0Ndx] & (((Word)1 << lowNdxInW0) - 1)) | (((Word)bits & bitsLowMask) << lowNdxInW0); 1656 m_words[word1Ndx] = (m_words[word1Ndx] & ~(((Word)1 << (highNdxInW1+1)) - 1)) | (((Word)bits & ~bitsLowMask) >> numBitsToSetInW0); 1657 } 1658 } 1659 1660 void assignToMemory (deUint8* dst) const 1661 { 1662 for (int wordNdx = 0; wordNdx < NUM_WORDS; wordNdx++) 1663 { 1664 for (int byteNdx = 0; byteNdx < WORD_BYTES; byteNdx++) 1665 dst[wordNdx*WORD_BYTES + byteNdx] = (deUint8)((m_words[wordNdx] >> (8*byteNdx)) & 0xff); 1666 } 1667 } 1668 1669 void pushBytesToVector (vector<deUint8>& dst) const 1670 { 1671 const int assignStartIndex = (int)dst.size(); 1672 dst.resize(dst.size() + BLOCK_SIZE_BYTES); 1673 assignToMemory(&dst[assignStartIndex]); 1674 } 1675 1676private: 1677 Word m_words[NUM_WORDS]; 1678}; 1679 1680// A helper for sequential access into a AssignBlock128. 1681class BitAssignAccessStream 1682{ 1683public: 1684 BitAssignAccessStream (AssignBlock128& dst, int startNdxInSrc, int length, bool forward) 1685 : m_dst (dst) 1686 , m_startNdxInSrc (startNdxInSrc) 1687 , m_length (length) 1688 , m_forward (forward) 1689 , m_ndx (0) 1690 { 1691 } 1692 1693 // Set the next num bits. Bits at positions greater than or equal to m_length are not touched. 1694 void setNext (int num, deUint32 bits) 1695 { 1696 DE_ASSERT((bits & (((deUint64)1 << num) - 1)) == bits); 1697 1698 if (num == 0 || m_ndx >= m_length) 1699 return; 1700 1701 const int end = m_ndx + num; 1702 const int numBitsToDst = de::max(0, de::min(m_length, end) - m_ndx); 1703 const int low = m_ndx; 1704 const int high = m_ndx + numBitsToDst - 1; 1705 const deUint32 actualBits = getBits(bits, 0, numBitsToDst-1); 1706 1707 m_ndx += num; 1708 1709 return m_forward ? m_dst.setBits(m_startNdxInSrc + low, m_startNdxInSrc + high, actualBits) 1710 : m_dst.setBits(m_startNdxInSrc - high, m_startNdxInSrc - low, reverseBits(actualBits, numBitsToDst)); 1711 } 1712 1713private: 1714 AssignBlock128& m_dst; 1715 const int m_startNdxInSrc; 1716 const int m_length; 1717 const bool m_forward; 1718 1719 int m_ndx; 1720}; 1721 1722struct VoidExtentParams 1723{ 1724 DE_STATIC_ASSERT((de::meta::TypesSame<deFloat16, deUint16>::Value)); 1725 bool isHDR; 1726 deUint16 r; 1727 deUint16 g; 1728 deUint16 b; 1729 deUint16 a; 1730 // \note Currently extent coordinates are all set to all-ones. 1731 1732 VoidExtentParams (bool isHDR_, deUint16 r_, deUint16 g_, deUint16 b_, deUint16 a_) : isHDR(isHDR_), r(r_), g(g_), b(b_), a(a_) {} 1733}; 1734 1735static AssignBlock128 generateVoidExtentBlock (const VoidExtentParams& params) 1736{ 1737 AssignBlock128 block; 1738 1739 block.setBits(0, 8, 0x1fc); // \note Marks void-extent block. 1740 block.setBit(9, params.isHDR); 1741 block.setBits(10, 11, 3); // \note Spec shows that these bits are both set, although they serve no purpose. 1742 1743 // Extent coordinates - currently all-ones. 1744 block.setBits(12, 24, 0x1fff); 1745 block.setBits(25, 37, 0x1fff); 1746 block.setBits(38, 50, 0x1fff); 1747 block.setBits(51, 63, 0x1fff); 1748 1749 DE_ASSERT(!params.isHDR || (!isFloat16InfOrNan(params.r) && 1750 !isFloat16InfOrNan(params.g) && 1751 !isFloat16InfOrNan(params.b) && 1752 !isFloat16InfOrNan(params.a))); 1753 1754 block.setBits(64, 79, params.r); 1755 block.setBits(80, 95, params.g); 1756 block.setBits(96, 111, params.b); 1757 block.setBits(112, 127, params.a); 1758 1759 return block; 1760} 1761 1762// An input array of ISE inputs for an entire ASTC block. Can be given as either single values in the 1763// range [0, maximumValueOfISERange] or as explicit block value specifications. The latter is needed 1764// so we can test all possible values of T and Q in a block, since multiple T or Q values may map 1765// to the same set of decoded values. 1766struct ISEInput 1767{ 1768 struct Block 1769 { 1770 deUint32 tOrQValue; //!< The 8-bit T or 7-bit Q in a trit or quint ISE block. 1771 deUint32 bitValues[5]; 1772 }; 1773 1774 bool isGivenInBlockForm; 1775 union 1776 { 1777 //!< \note 64 comes from the maximum number of weight values in an ASTC block. 1778 deUint32 plain[64]; 1779 Block block[64]; 1780 } value; 1781 1782 ISEInput (void) 1783 : isGivenInBlockForm (false) 1784 { 1785 } 1786}; 1787 1788static inline deUint32 computeISERangeMax (const ISEParams& iseParams) 1789{ 1790 switch (iseParams.mode) 1791 { 1792 case ISEMODE_TRIT: return (1u << iseParams.numBits) * 3 - 1; 1793 case ISEMODE_QUINT: return (1u << iseParams.numBits) * 5 - 1; 1794 case ISEMODE_PLAIN_BIT: return (1u << iseParams.numBits) - 1; 1795 default: 1796 DE_ASSERT(false); 1797 return -1; 1798 } 1799} 1800 1801struct NormalBlockParams 1802{ 1803 int weightGridWidth; 1804 int weightGridHeight; 1805 ISEParams weightISEParams; 1806 bool isDualPlane; 1807 deUint32 ccs; //! \note Irrelevant if !isDualPlane. 1808 int numPartitions; 1809 deUint32 colorEndpointModes[4]; 1810 // \note Below members are irrelevant if numPartitions == 1. 1811 bool isMultiPartSingleCemMode; //! \note If true, the single CEM is at colorEndpointModes[0]. 1812 deUint32 partitionSeed; 1813 1814 NormalBlockParams (void) 1815 : weightGridWidth (-1) 1816 , weightGridHeight (-1) 1817 , weightISEParams (ISEMODE_LAST, -1) 1818 , isDualPlane (true) 1819 , ccs ((deUint32)-1) 1820 , numPartitions (-1) 1821 , isMultiPartSingleCemMode (false) 1822 , partitionSeed ((deUint32)-1) 1823 { 1824 colorEndpointModes[0] = 0; 1825 colorEndpointModes[1] = 0; 1826 colorEndpointModes[2] = 0; 1827 colorEndpointModes[3] = 0; 1828 } 1829}; 1830 1831struct NormalBlockISEInputs 1832{ 1833 ISEInput weight; 1834 ISEInput endpoint; 1835 1836 NormalBlockISEInputs (void) 1837 : weight () 1838 , endpoint () 1839 { 1840 } 1841}; 1842 1843static inline int computeNumWeights (const NormalBlockParams& params) 1844{ 1845 return params.weightGridWidth * params.weightGridHeight * (params.isDualPlane ? 2 : 1); 1846} 1847 1848static inline int computeNumBitsForColorEndpoints (const NormalBlockParams& params) 1849{ 1850 const int numWeightBits = computeNumRequiredBits(params.weightISEParams, computeNumWeights(params)); 1851 const int numConfigDataBits = (params.numPartitions == 1 ? 17 : params.isMultiPartSingleCemMode ? 29 : 25 + 3*params.numPartitions) + 1852 (params.isDualPlane ? 2 : 0); 1853 1854 return 128 - numWeightBits - numConfigDataBits; 1855} 1856 1857static inline int computeNumColorEndpointValues (const deUint32* endpointModes, int numPartitions, bool isMultiPartSingleCemMode) 1858{ 1859 if (isMultiPartSingleCemMode) 1860 return numPartitions * computeNumColorEndpointValues(endpointModes[0]); 1861 else 1862 { 1863 int result = 0; 1864 for (int i = 0; i < numPartitions; i++) 1865 result += computeNumColorEndpointValues(endpointModes[i]); 1866 return result; 1867 } 1868} 1869 1870static inline bool isValidBlockParams (const NormalBlockParams& params, int blockWidth, int blockHeight) 1871{ 1872 const int numWeights = computeNumWeights(params); 1873 const int numWeightBits = computeNumRequiredBits(params.weightISEParams, numWeights); 1874 const int numColorEndpointValues = computeNumColorEndpointValues(¶ms.colorEndpointModes[0], params.numPartitions, params.isMultiPartSingleCemMode); 1875 const int numBitsForColorEndpoints = computeNumBitsForColorEndpoints(params); 1876 1877 return numWeights <= 64 && 1878 de::inRange(numWeightBits, 24, 96) && 1879 params.weightGridWidth <= blockWidth && 1880 params.weightGridHeight <= blockHeight && 1881 !(params.numPartitions == 4 && params.isDualPlane) && 1882 numColorEndpointValues <= 18 && 1883 numBitsForColorEndpoints >= deDivRoundUp32(13*numColorEndpointValues, 5); 1884} 1885 1886// Write bits 0 to 10 of an ASTC block. 1887static void writeBlockMode (AssignBlock128& dst, const NormalBlockParams& blockParams) 1888{ 1889 const deUint32 d = blockParams.isDualPlane != 0; 1890 // r and h initialized in switch below. 1891 deUint32 r; 1892 deUint32 h; 1893 // a, b and blockModeLayoutNdx initialized in block mode layout index detecting loop below. 1894 deUint32 a = (deUint32)-1; 1895 deUint32 b = (deUint32)-1; 1896 int blockModeLayoutNdx; 1897 1898 // Find the values of r and h (ISE range). 1899 switch (computeISERangeMax(blockParams.weightISEParams)) 1900 { 1901 case 1: r = 2; h = 0; break; 1902 case 2: r = 3; h = 0; break; 1903 case 3: r = 4; h = 0; break; 1904 case 4: r = 5; h = 0; break; 1905 case 5: r = 6; h = 0; break; 1906 case 7: r = 7; h = 0; break; 1907 1908 case 9: r = 2; h = 1; break; 1909 case 11: r = 3; h = 1; break; 1910 case 15: r = 4; h = 1; break; 1911 case 19: r = 5; h = 1; break; 1912 case 23: r = 6; h = 1; break; 1913 case 31: r = 7; h = 1; break; 1914 1915 default: 1916 DE_ASSERT(false); 1917 r = (deUint32)-1; 1918 h = (deUint32)-1; 1919 } 1920 1921 // Find block mode layout index, i.e. appropriate row in the "2d block mode layout" table in ASTC spec. 1922 1923 { 1924 enum BlockModeLayoutABVariable { Z=0, A=1, B=2 }; 1925 1926 static const struct BlockModeLayout 1927 { 1928 int aNumBits; 1929 int bNumBits; 1930 BlockModeLayoutABVariable gridWidthVariableTerm; 1931 int gridWidthConstantTerm; 1932 BlockModeLayoutABVariable gridHeightVariableTerm; 1933 int gridHeightConstantTerm; 1934 } blockModeLayouts[] = 1935 { 1936 { 2, 2, B, 4, A, 2}, 1937 { 2, 2, B, 8, A, 2}, 1938 { 2, 2, A, 2, B, 8}, 1939 { 2, 1, A, 2, B, 6}, 1940 { 2, 1, B, 2, A, 2}, 1941 { 2, 0, Z, 12, A, 2}, 1942 { 2, 0, A, 2, Z, 12}, 1943 { 0, 0, Z, 6, Z, 10}, 1944 { 0, 0, Z, 10, Z, 6}, 1945 { 2, 2, A, 6, B, 6} 1946 }; 1947 1948 for (blockModeLayoutNdx = 0; blockModeLayoutNdx < DE_LENGTH_OF_ARRAY(blockModeLayouts); blockModeLayoutNdx++) 1949 { 1950 const BlockModeLayout& layout = blockModeLayouts[blockModeLayoutNdx]; 1951 const int aMax = (1 << layout.aNumBits) - 1; 1952 const int bMax = (1 << layout.bNumBits) - 1; 1953 const int variableOffsetsMax[3] = { 0, aMax, bMax }; 1954 const int widthMin = layout.gridWidthConstantTerm; 1955 const int heightMin = layout.gridHeightConstantTerm; 1956 const int widthMax = widthMin + variableOffsetsMax[layout.gridWidthVariableTerm]; 1957 const int heightMax = heightMin + variableOffsetsMax[layout.gridHeightVariableTerm]; 1958 1959 DE_ASSERT(layout.gridWidthVariableTerm != layout.gridHeightVariableTerm || layout.gridWidthVariableTerm == Z); 1960 1961 if (de::inRange(blockParams.weightGridWidth, widthMin, widthMax) && 1962 de::inRange(blockParams.weightGridHeight, heightMin, heightMax)) 1963 { 1964 deUint32 dummy = 0; 1965 deUint32& widthVariable = layout.gridWidthVariableTerm == A ? a : layout.gridWidthVariableTerm == B ? b : dummy; 1966 deUint32& heightVariable = layout.gridHeightVariableTerm == A ? a : layout.gridHeightVariableTerm == B ? b : dummy; 1967 1968 widthVariable = blockParams.weightGridWidth - layout.gridWidthConstantTerm; 1969 heightVariable = blockParams.weightGridHeight - layout.gridHeightConstantTerm; 1970 1971 break; 1972 } 1973 } 1974 } 1975 1976 // Set block mode bits. 1977 1978 const deUint32 a0 = getBit(a, 0); 1979 const deUint32 a1 = getBit(a, 1); 1980 const deUint32 b0 = getBit(b, 0); 1981 const deUint32 b1 = getBit(b, 1); 1982 const deUint32 r0 = getBit(r, 0); 1983 const deUint32 r1 = getBit(r, 1); 1984 const deUint32 r2 = getBit(r, 2); 1985 1986#define SB(NDX, VAL) dst.setBit((NDX), (VAL)) 1987#define ASSIGN_BITS(B10, B9, B8, B7, B6, B5, B4, B3, B2, B1, B0) do { SB(10,(B10)); SB(9,(B9)); SB(8,(B8)); SB(7,(B7)); SB(6,(B6)); SB(5,(B5)); SB(4,(B4)); SB(3,(B3)); SB(2,(B2)); SB(1,(B1)); SB(0,(B0)); } while (false) 1988 1989 switch (blockModeLayoutNdx) 1990 { 1991 case 0: ASSIGN_BITS(d, h, b1, b0, a1, a0, r0, 0, 0, r2, r1); break; 1992 case 1: ASSIGN_BITS(d, h, b1, b0, a1, a0, r0, 0, 1, r2, r1); break; 1993 case 2: ASSIGN_BITS(d, h, b1, b0, a1, a0, r0, 1, 0, r2, r1); break; 1994 case 3: ASSIGN_BITS(d, h, 0, b, a1, a0, r0, 1, 1, r2, r1); break; 1995 case 4: ASSIGN_BITS(d, h, 1, b, a1, a0, r0, 1, 1, r2, r1); break; 1996 case 5: ASSIGN_BITS(d, h, 0, 0, a1, a0, r0, r2, r1, 0, 0); break; 1997 case 6: ASSIGN_BITS(d, h, 0, 1, a1, a0, r0, r2, r1, 0, 0); break; 1998 case 7: ASSIGN_BITS(d, h, 1, 1, 0, 0, r0, r2, r1, 0, 0); break; 1999 case 8: ASSIGN_BITS(d, h, 1, 1, 0, 1, r0, r2, r1, 0, 0); break; 2000 case 9: ASSIGN_BITS(b1, b0, 1, 0, a1, a0, r0, r2, r1, 0, 0); DE_ASSERT(d == 0 && h == 0); break; 2001 default: 2002 DE_ASSERT(false); 2003 } 2004 2005#undef ASSIGN_BITS 2006#undef SB 2007} 2008 2009// Write color endpoint mode data of an ASTC block. 2010static void writeColorEndpointModes (AssignBlock128& dst, const deUint32* colorEndpointModes, bool isMultiPartSingleCemMode, int numPartitions, int extraCemBitsStart) 2011{ 2012 if (numPartitions == 1) 2013 dst.setBits(13, 16, colorEndpointModes[0]); 2014 else 2015 { 2016 if (isMultiPartSingleCemMode) 2017 { 2018 dst.setBits(23, 24, 0); 2019 dst.setBits(25, 28, colorEndpointModes[0]); 2020 } 2021 else 2022 { 2023 DE_ASSERT(numPartitions > 0); 2024 const deUint32 minCem = *std::min_element(&colorEndpointModes[0], &colorEndpointModes[numPartitions]); 2025 const deUint32 maxCem = *std::max_element(&colorEndpointModes[0], &colorEndpointModes[numPartitions]); 2026 const deUint32 minCemClass = minCem/4; 2027 const deUint32 maxCemClass = maxCem/4; 2028 DE_ASSERT(maxCemClass - minCemClass <= 1); 2029 DE_UNREF(minCemClass); // \note For non-debug builds. 2030 const deUint32 highLevelSelector = de::max(1u, maxCemClass); 2031 2032 dst.setBits(23, 24, highLevelSelector); 2033 2034 for (int partNdx = 0; partNdx < numPartitions; partNdx++) 2035 { 2036 const deUint32 c = colorEndpointModes[partNdx] / 4 == highLevelSelector ? 1 : 0; 2037 const deUint32 m = colorEndpointModes[partNdx] % 4; 2038 const deUint32 lowMBit0Ndx = numPartitions + 2*partNdx; 2039 const deUint32 lowMBit1Ndx = numPartitions + 2*partNdx + 1; 2040 dst.setBit(25 + partNdx, c); 2041 dst.setBit(lowMBit0Ndx < 4 ? 25+lowMBit0Ndx : extraCemBitsStart+lowMBit0Ndx-4, getBit(m, 0)); 2042 dst.setBit(lowMBit1Ndx < 4 ? 25+lowMBit1Ndx : extraCemBitsStart+lowMBit1Ndx-4, getBit(m, 1)); 2043 } 2044 } 2045 } 2046} 2047 2048static void encodeISETritBlock (BitAssignAccessStream& dst, int numBits, bool fromExplicitInputBlock, const ISEInput::Block& blockInput, const deUint32* nonBlockInput, int numValues) 2049{ 2050 // tritBlockTValue[t0][t1][t2][t3][t4] is a value of T (not necessarily the only one) that will yield the given trits when decoded. 2051 static const deUint32 tritBlockTValue[3][3][3][3][3] = 2052 { 2053 { 2054 {{{0, 128, 96}, {32, 160, 224}, {64, 192, 28}}, {{16, 144, 112}, {48, 176, 240}, {80, 208, 156}}, {{3, 131, 99}, {35, 163, 227}, {67, 195, 31}}}, 2055 {{{4, 132, 100}, {36, 164, 228}, {68, 196, 60}}, {{20, 148, 116}, {52, 180, 244}, {84, 212, 188}}, {{19, 147, 115}, {51, 179, 243}, {83, 211, 159}}}, 2056 {{{8, 136, 104}, {40, 168, 232}, {72, 200, 92}}, {{24, 152, 120}, {56, 184, 248}, {88, 216, 220}}, {{12, 140, 108}, {44, 172, 236}, {76, 204, 124}}} 2057 }, 2058 { 2059 {{{1, 129, 97}, {33, 161, 225}, {65, 193, 29}}, {{17, 145, 113}, {49, 177, 241}, {81, 209, 157}}, {{7, 135, 103}, {39, 167, 231}, {71, 199, 63}}}, 2060 {{{5, 133, 101}, {37, 165, 229}, {69, 197, 61}}, {{21, 149, 117}, {53, 181, 245}, {85, 213, 189}}, {{23, 151, 119}, {55, 183, 247}, {87, 215, 191}}}, 2061 {{{9, 137, 105}, {41, 169, 233}, {73, 201, 93}}, {{25, 153, 121}, {57, 185, 249}, {89, 217, 221}}, {{13, 141, 109}, {45, 173, 237}, {77, 205, 125}}} 2062 }, 2063 { 2064 {{{2, 130, 98}, {34, 162, 226}, {66, 194, 30}}, {{18, 146, 114}, {50, 178, 242}, {82, 210, 158}}, {{11, 139, 107}, {43, 171, 235}, {75, 203, 95}}}, 2065 {{{6, 134, 102}, {38, 166, 230}, {70, 198, 62}}, {{22, 150, 118}, {54, 182, 246}, {86, 214, 190}}, {{27, 155, 123}, {59, 187, 251}, {91, 219, 223}}}, 2066 {{{10, 138, 106}, {42, 170, 234}, {74, 202, 94}}, {{26, 154, 122}, {58, 186, 250}, {90, 218, 222}}, {{14, 142, 110}, {46, 174, 238}, {78, 206, 126}}} 2067 } 2068 }; 2069 2070 DE_ASSERT(de::inRange(numValues, 1, 5)); 2071 2072 deUint32 tritParts[5]; 2073 deUint32 bitParts[5]; 2074 2075 for (int i = 0; i < 5; i++) 2076 { 2077 if (i < numValues) 2078 { 2079 if (fromExplicitInputBlock) 2080 { 2081 bitParts[i] = blockInput.bitValues[i]; 2082 tritParts[i] = -1; // \note Won't be used, but silences warning. 2083 } 2084 else 2085 { 2086 // \todo [2016-01-20 pyry] numBits = 0 doesn't make sense 2087 bitParts[i] = numBits > 0 ? getBits(nonBlockInput[i], 0, numBits-1) : 0; 2088 tritParts[i] = nonBlockInput[i] >> numBits; 2089 } 2090 } 2091 else 2092 { 2093 bitParts[i] = 0; 2094 tritParts[i] = 0; 2095 } 2096 } 2097 2098 const deUint32 T = fromExplicitInputBlock ? blockInput.tOrQValue : tritBlockTValue[tritParts[0]] 2099 [tritParts[1]] 2100 [tritParts[2]] 2101 [tritParts[3]] 2102 [tritParts[4]]; 2103 2104 dst.setNext(numBits, bitParts[0]); 2105 dst.setNext(2, getBits(T, 0, 1)); 2106 dst.setNext(numBits, bitParts[1]); 2107 dst.setNext(2, getBits(T, 2, 3)); 2108 dst.setNext(numBits, bitParts[2]); 2109 dst.setNext(1, getBit(T, 4)); 2110 dst.setNext(numBits, bitParts[3]); 2111 dst.setNext(2, getBits(T, 5, 6)); 2112 dst.setNext(numBits, bitParts[4]); 2113 dst.setNext(1, getBit(T, 7)); 2114} 2115 2116static void encodeISEQuintBlock (BitAssignAccessStream& dst, int numBits, bool fromExplicitInputBlock, const ISEInput::Block& blockInput, const deUint32* nonBlockInput, int numValues) 2117{ 2118 // quintBlockQValue[q0][q1][q2] is a value of Q (not necessarily the only one) that will yield the given quints when decoded. 2119 static const deUint32 quintBlockQValue[5][5][5] = 2120 { 2121 {{0, 32, 64, 96, 102}, {8, 40, 72, 104, 110}, {16, 48, 80, 112, 118}, {24, 56, 88, 120, 126}, {5, 37, 69, 101, 39}}, 2122 {{1, 33, 65, 97, 103}, {9, 41, 73, 105, 111}, {17, 49, 81, 113, 119}, {25, 57, 89, 121, 127}, {13, 45, 77, 109, 47}}, 2123 {{2, 34, 66, 98, 70}, {10, 42, 74, 106, 78}, {18, 50, 82, 114, 86}, {26, 58, 90, 122, 94}, {21, 53, 85, 117, 55}}, 2124 {{3, 35, 67, 99, 71}, {11, 43, 75, 107, 79}, {19, 51, 83, 115, 87}, {27, 59, 91, 123, 95}, {29, 61, 93, 125, 63}}, 2125 {{4, 36, 68, 100, 38}, {12, 44, 76, 108, 46}, {20, 52, 84, 116, 54}, {28, 60, 92, 124, 62}, {6, 14, 22, 30, 7}} 2126 }; 2127 2128 DE_ASSERT(de::inRange(numValues, 1, 3)); 2129 2130 deUint32 quintParts[3]; 2131 deUint32 bitParts[3]; 2132 2133 for (int i = 0; i < 3; i++) 2134 { 2135 if (i < numValues) 2136 { 2137 if (fromExplicitInputBlock) 2138 { 2139 bitParts[i] = blockInput.bitValues[i]; 2140 quintParts[i] = -1; // \note Won't be used, but silences warning. 2141 } 2142 else 2143 { 2144 // \todo [2016-01-20 pyry] numBits = 0 doesn't make sense 2145 bitParts[i] = numBits > 0 ? getBits(nonBlockInput[i], 0, numBits-1) : 0; 2146 quintParts[i] = nonBlockInput[i] >> numBits; 2147 } 2148 } 2149 else 2150 { 2151 bitParts[i] = 0; 2152 quintParts[i] = 0; 2153 } 2154 } 2155 2156 const deUint32 Q = fromExplicitInputBlock ? blockInput.tOrQValue : quintBlockQValue[quintParts[0]] 2157 [quintParts[1]] 2158 [quintParts[2]]; 2159 2160 dst.setNext(numBits, bitParts[0]); 2161 dst.setNext(3, getBits(Q, 0, 2)); 2162 dst.setNext(numBits, bitParts[1]); 2163 dst.setNext(2, getBits(Q, 3, 4)); 2164 dst.setNext(numBits, bitParts[2]); 2165 dst.setNext(2, getBits(Q, 5, 6)); 2166} 2167 2168static void encodeISEBitBlock (BitAssignAccessStream& dst, int numBits, deUint32 value) 2169{ 2170 DE_ASSERT(de::inRange(value, 0u, (1u<<numBits)-1)); 2171 dst.setNext(numBits, value); 2172} 2173 2174static void encodeISE (BitAssignAccessStream& dst, const ISEParams& params, const ISEInput& input, int numValues) 2175{ 2176 if (params.mode == ISEMODE_TRIT) 2177 { 2178 const int numBlocks = deDivRoundUp32(numValues, 5); 2179 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++) 2180 { 2181 const int numValuesInBlock = blockNdx == numBlocks-1 ? numValues - 5*(numBlocks-1) : 5; 2182 encodeISETritBlock(dst, params.numBits, input.isGivenInBlockForm, 2183 input.isGivenInBlockForm ? input.value.block[blockNdx] : ISEInput::Block(), 2184 input.isGivenInBlockForm ? DE_NULL : &input.value.plain[5*blockNdx], 2185 numValuesInBlock); 2186 } 2187 } 2188 else if (params.mode == ISEMODE_QUINT) 2189 { 2190 const int numBlocks = deDivRoundUp32(numValues, 3); 2191 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++) 2192 { 2193 const int numValuesInBlock = blockNdx == numBlocks-1 ? numValues - 3*(numBlocks-1) : 3; 2194 encodeISEQuintBlock(dst, params.numBits, input.isGivenInBlockForm, 2195 input.isGivenInBlockForm ? input.value.block[blockNdx] : ISEInput::Block(), 2196 input.isGivenInBlockForm ? DE_NULL : &input.value.plain[3*blockNdx], 2197 numValuesInBlock); 2198 } 2199 } 2200 else 2201 { 2202 DE_ASSERT(params.mode == ISEMODE_PLAIN_BIT); 2203 for (int i = 0; i < numValues; i++) 2204 encodeISEBitBlock(dst, params.numBits, input.isGivenInBlockForm ? input.value.block[i].bitValues[0] : input.value.plain[i]); 2205 } 2206} 2207 2208static void writeWeightData (AssignBlock128& dst, const ISEParams& iseParams, const ISEInput& input, int numWeights) 2209{ 2210 const int numWeightBits = computeNumRequiredBits(iseParams, numWeights); 2211 BitAssignAccessStream access (dst, 127, numWeightBits, false); 2212 encodeISE(access, iseParams, input, numWeights); 2213} 2214 2215static void writeColorEndpointData (AssignBlock128& dst, const ISEParams& iseParams, const ISEInput& input, int numEndpoints, int numBitsForColorEndpoints, int colorEndpointDataStartNdx) 2216{ 2217 BitAssignAccessStream access(dst, colorEndpointDataStartNdx, numBitsForColorEndpoints, true); 2218 encodeISE(access, iseParams, input, numEndpoints); 2219} 2220 2221static AssignBlock128 generateNormalBlock (const NormalBlockParams& blockParams, int blockWidth, int blockHeight, const NormalBlockISEInputs& iseInputs) 2222{ 2223 DE_ASSERT(isValidBlockParams(blockParams, blockWidth, blockHeight)); 2224 DE_UNREF(blockWidth); // \note For non-debug builds. 2225 DE_UNREF(blockHeight); // \note For non-debug builds. 2226 2227 AssignBlock128 block; 2228 const int numWeights = computeNumWeights(blockParams); 2229 const int numWeightBits = computeNumRequiredBits(blockParams.weightISEParams, numWeights); 2230 2231 writeBlockMode(block, blockParams); 2232 2233 block.setBits(11, 12, blockParams.numPartitions - 1); 2234 if (blockParams.numPartitions > 1) 2235 block.setBits(13, 22, blockParams.partitionSeed); 2236 2237 { 2238 const int extraCemBitsStart = 127 - numWeightBits - (blockParams.numPartitions == 1 || blockParams.isMultiPartSingleCemMode ? -1 2239 : blockParams.numPartitions == 4 ? 7 2240 : blockParams.numPartitions == 3 ? 4 2241 : blockParams.numPartitions == 2 ? 1 2242 : 0); 2243 2244 writeColorEndpointModes(block, &blockParams.colorEndpointModes[0], blockParams.isMultiPartSingleCemMode, blockParams.numPartitions, extraCemBitsStart); 2245 2246 if (blockParams.isDualPlane) 2247 block.setBits(extraCemBitsStart-2, extraCemBitsStart-1, blockParams.ccs); 2248 } 2249 2250 writeWeightData(block, blockParams.weightISEParams, iseInputs.weight, numWeights); 2251 2252 { 2253 const int numColorEndpointValues = computeNumColorEndpointValues(&blockParams.colorEndpointModes[0], blockParams.numPartitions, blockParams.isMultiPartSingleCemMode); 2254 const int numBitsForColorEndpoints = computeNumBitsForColorEndpoints(blockParams); 2255 const int colorEndpointDataStartNdx = blockParams.numPartitions == 1 ? 17 : 29; 2256 const ISEParams& colorEndpointISEParams = computeMaximumRangeISEParams(numBitsForColorEndpoints, numColorEndpointValues); 2257 2258 writeColorEndpointData(block, colorEndpointISEParams, iseInputs.endpoint, numColorEndpointValues, numBitsForColorEndpoints, colorEndpointDataStartNdx); 2259 } 2260 2261 return block; 2262} 2263 2264// Generate default ISE inputs for weight and endpoint data - gradient-ish values. 2265static NormalBlockISEInputs generateDefaultISEInputs (const NormalBlockParams& blockParams) 2266{ 2267 NormalBlockISEInputs result; 2268 2269 { 2270 result.weight.isGivenInBlockForm = false; 2271 2272 const int numWeights = computeNumWeights(blockParams); 2273 const int weightRangeMax = computeISERangeMax(blockParams.weightISEParams); 2274 2275 if (blockParams.isDualPlane) 2276 { 2277 for (int i = 0; i < numWeights; i += 2) 2278 result.weight.value.plain[i] = (i*weightRangeMax + (numWeights-1)/2) / (numWeights-1); 2279 2280 for (int i = 1; i < numWeights; i += 2) 2281 result.weight.value.plain[i] = weightRangeMax - (i*weightRangeMax + (numWeights-1)/2) / (numWeights-1); 2282 } 2283 else 2284 { 2285 for (int i = 0; i < numWeights; i++) 2286 result.weight.value.plain[i] = (i*weightRangeMax + (numWeights-1)/2) / (numWeights-1); 2287 } 2288 } 2289 2290 { 2291 result.endpoint.isGivenInBlockForm = false; 2292 2293 const int numColorEndpointValues = computeNumColorEndpointValues(&blockParams.colorEndpointModes[0], blockParams.numPartitions, blockParams.isMultiPartSingleCemMode); 2294 const int numBitsForColorEndpoints = computeNumBitsForColorEndpoints(blockParams); 2295 const ISEParams& colorEndpointISEParams = computeMaximumRangeISEParams(numBitsForColorEndpoints, numColorEndpointValues); 2296 const int colorEndpointRangeMax = computeISERangeMax(colorEndpointISEParams); 2297 2298 for (int i = 0; i < numColorEndpointValues; i++) 2299 result.endpoint.value.plain[i] = (i*colorEndpointRangeMax + (numColorEndpointValues-1)/2) / (numColorEndpointValues-1); 2300 } 2301 2302 return result; 2303} 2304 2305static const ISEParams s_weightISEParamsCandidates[] = 2306{ 2307 ISEParams(ISEMODE_PLAIN_BIT, 1), 2308 ISEParams(ISEMODE_TRIT, 0), 2309 ISEParams(ISEMODE_PLAIN_BIT, 2), 2310 ISEParams(ISEMODE_QUINT, 0), 2311 ISEParams(ISEMODE_TRIT, 1), 2312 ISEParams(ISEMODE_PLAIN_BIT, 3), 2313 ISEParams(ISEMODE_QUINT, 1), 2314 ISEParams(ISEMODE_TRIT, 2), 2315 ISEParams(ISEMODE_PLAIN_BIT, 4), 2316 ISEParams(ISEMODE_QUINT, 2), 2317 ISEParams(ISEMODE_TRIT, 3), 2318 ISEParams(ISEMODE_PLAIN_BIT, 5) 2319}; 2320 2321void generateRandomBlock (deUint8* dst, const IVec3& blockSize, de::Random& rnd) 2322{ 2323 DE_ASSERT(blockSize.z() == 1); 2324 2325 if (rnd.getFloat() < 0.1f) 2326 { 2327 // Void extent block. 2328 const bool isVoidExtentHDR = rnd.getBool(); 2329 const deUint16 r = isVoidExtentHDR ? deFloat32To16(rnd.getFloat(0.0f, 1.0f)) : (deUint16)rnd.getInt(0, 0xffff); 2330 const deUint16 g = isVoidExtentHDR ? deFloat32To16(rnd.getFloat(0.0f, 1.0f)) : (deUint16)rnd.getInt(0, 0xffff); 2331 const deUint16 b = isVoidExtentHDR ? deFloat32To16(rnd.getFloat(0.0f, 1.0f)) : (deUint16)rnd.getInt(0, 0xffff); 2332 const deUint16 a = isVoidExtentHDR ? deFloat32To16(rnd.getFloat(0.0f, 1.0f)) : (deUint16)rnd.getInt(0, 0xffff); 2333 generateVoidExtentBlock(VoidExtentParams(isVoidExtentHDR, r, g, b, a)).assignToMemory(dst); 2334 } 2335 else 2336 { 2337 // Not void extent block. 2338 2339 // Generate block params. 2340 2341 NormalBlockParams blockParams; 2342 2343 do 2344 { 2345 blockParams.weightGridWidth = rnd.getInt(2, blockSize.x()); 2346 blockParams.weightGridHeight = rnd.getInt(2, blockSize.y()); 2347 blockParams.weightISEParams = s_weightISEParamsCandidates[rnd.getInt(0, DE_LENGTH_OF_ARRAY(s_weightISEParamsCandidates)-1)]; 2348 blockParams.numPartitions = rnd.getInt(1, 4); 2349 blockParams.isMultiPartSingleCemMode = rnd.getFloat() < 0.25f; 2350 blockParams.isDualPlane = blockParams.numPartitions != 4 && rnd.getBool(); 2351 blockParams.ccs = rnd.getInt(0, 3); 2352 blockParams.partitionSeed = rnd.getInt(0, 1023); 2353 2354 blockParams.colorEndpointModes[0] = rnd.getInt(0, 15); 2355 2356 { 2357 const int cemDiff = blockParams.isMultiPartSingleCemMode ? 0 2358 : blockParams.colorEndpointModes[0] == 0 ? 1 2359 : blockParams.colorEndpointModes[0] == 15 ? -1 2360 : rnd.getBool() ? 1 : -1; 2361 2362 for (int i = 1; i < blockParams.numPartitions; i++) 2363 blockParams.colorEndpointModes[i] = blockParams.colorEndpointModes[0] + (cemDiff == -1 ? rnd.getInt(-1, 0) : cemDiff == 1 ? rnd.getInt(0, 1) : 0); 2364 } 2365 } while (!isValidBlockParams(blockParams, blockSize.x(), blockSize.y())); 2366 2367 // Generate ISE inputs for both weight and endpoint data. 2368 2369 NormalBlockISEInputs iseInputs; 2370 2371 for (int weightOrEndpoints = 0; weightOrEndpoints <= 1; weightOrEndpoints++) 2372 { 2373 const bool setWeights = weightOrEndpoints == 0; 2374 const int numValues = setWeights ? computeNumWeights(blockParams) : 2375 computeNumColorEndpointValues(&blockParams.colorEndpointModes[0], blockParams.numPartitions, blockParams.isMultiPartSingleCemMode); 2376 const ISEParams iseParams = setWeights ? blockParams.weightISEParams : computeMaximumRangeISEParams(computeNumBitsForColorEndpoints(blockParams), numValues); 2377 ISEInput& iseInput = setWeights ? iseInputs.weight : iseInputs.endpoint; 2378 2379 iseInput.isGivenInBlockForm = rnd.getBool(); 2380 2381 if (iseInput.isGivenInBlockForm) 2382 { 2383 const int numValuesPerISEBlock = iseParams.mode == ISEMODE_TRIT ? 5 2384 : iseParams.mode == ISEMODE_QUINT ? 3 2385 : 1; 2386 const int iseBitMax = (1 << iseParams.numBits) - 1; 2387 const int numISEBlocks = deDivRoundUp32(numValues, numValuesPerISEBlock); 2388 2389 for (int iseBlockNdx = 0; iseBlockNdx < numISEBlocks; iseBlockNdx++) 2390 { 2391 iseInput.value.block[iseBlockNdx].tOrQValue = rnd.getInt(0, 255); 2392 for (int i = 0; i < numValuesPerISEBlock; i++) 2393 iseInput.value.block[iseBlockNdx].bitValues[i] = rnd.getInt(0, iseBitMax); 2394 } 2395 } 2396 else 2397 { 2398 const int rangeMax = computeISERangeMax(iseParams); 2399 2400 for (int valueNdx = 0; valueNdx < numValues; valueNdx++) 2401 iseInput.value.plain[valueNdx] = rnd.getInt(0, rangeMax); 2402 } 2403 } 2404 2405 generateNormalBlock(blockParams, blockSize.x(), blockSize.y(), iseInputs).assignToMemory(dst); 2406 } 2407} 2408 2409} // anonymous 2410 2411// Generate block data for a given BlockTestType and format. 2412void generateBlockCaseTestData (vector<deUint8>& dst, CompressedTexFormat format, BlockTestType testType) 2413{ 2414 DE_ASSERT(isAstcFormat(format)); 2415 DE_ASSERT(!(isAstcSRGBFormat(format) && isBlockTestTypeHDROnly(testType))); 2416 2417 const IVec3 blockSize = getBlockPixelSize(format); 2418 DE_ASSERT(blockSize.z() == 1); 2419 2420 switch (testType) 2421 { 2422 case BLOCK_TEST_TYPE_VOID_EXTENT_LDR: 2423 // Generate a gradient-like set of LDR void-extent blocks. 2424 { 2425 const int numBlocks = 1<<13; 2426 const deUint32 numValues = 1<<16; 2427 dst.reserve(numBlocks*BLOCK_SIZE_BYTES); 2428 2429 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++) 2430 { 2431 const deUint32 baseValue = blockNdx*(numValues-1) / (numBlocks-1); 2432 const deUint16 r = (deUint16)((baseValue + numValues*0/4) % numValues); 2433 const deUint16 g = (deUint16)((baseValue + numValues*1/4) % numValues); 2434 const deUint16 b = (deUint16)((baseValue + numValues*2/4) % numValues); 2435 const deUint16 a = (deUint16)((baseValue + numValues*3/4) % numValues); 2436 AssignBlock128 block; 2437 2438 generateVoidExtentBlock(VoidExtentParams(false, r, g, b, a)).pushBytesToVector(dst); 2439 } 2440 2441 break; 2442 } 2443 2444 case BLOCK_TEST_TYPE_VOID_EXTENT_HDR: 2445 // Generate a gradient-like set of HDR void-extent blocks, with values ranging from the largest finite negative to largest finite positive of fp16. 2446 { 2447 const float minValue = -65504.0f; 2448 const float maxValue = +65504.0f; 2449 const int numBlocks = 1<<13; 2450 dst.reserve(numBlocks*BLOCK_SIZE_BYTES); 2451 2452 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++) 2453 { 2454 const int rNdx = (blockNdx + numBlocks*0/4) % numBlocks; 2455 const int gNdx = (blockNdx + numBlocks*1/4) % numBlocks; 2456 const int bNdx = (blockNdx + numBlocks*2/4) % numBlocks; 2457 const int aNdx = (blockNdx + numBlocks*3/4) % numBlocks; 2458 const deFloat16 r = deFloat32To16(minValue + (float)rNdx * (maxValue - minValue) / (float)(numBlocks-1)); 2459 const deFloat16 g = deFloat32To16(minValue + (float)gNdx * (maxValue - minValue) / (float)(numBlocks-1)); 2460 const deFloat16 b = deFloat32To16(minValue + (float)bNdx * (maxValue - minValue) / (float)(numBlocks-1)); 2461 const deFloat16 a = deFloat32To16(minValue + (float)aNdx * (maxValue - minValue) / (float)(numBlocks-1)); 2462 2463 generateVoidExtentBlock(VoidExtentParams(true, r, g, b, a)).pushBytesToVector(dst); 2464 } 2465 2466 break; 2467 } 2468 2469 case BLOCK_TEST_TYPE_WEIGHT_GRID: 2470 // Generate different combinations of plane count, weight ISE params, and grid size. 2471 { 2472 for (int isDualPlane = 0; isDualPlane <= 1; isDualPlane++) 2473 for (int iseParamsNdx = 0; iseParamsNdx < DE_LENGTH_OF_ARRAY(s_weightISEParamsCandidates); iseParamsNdx++) 2474 for (int weightGridWidth = 2; weightGridWidth <= 12; weightGridWidth++) 2475 for (int weightGridHeight = 2; weightGridHeight <= 12; weightGridHeight++) 2476 { 2477 NormalBlockParams blockParams; 2478 NormalBlockISEInputs iseInputs; 2479 2480 blockParams.weightGridWidth = weightGridWidth; 2481 blockParams.weightGridHeight = weightGridHeight; 2482 blockParams.isDualPlane = isDualPlane != 0; 2483 blockParams.weightISEParams = s_weightISEParamsCandidates[iseParamsNdx]; 2484 blockParams.ccs = 0; 2485 blockParams.numPartitions = 1; 2486 blockParams.colorEndpointModes[0] = 0; 2487 2488 if (isValidBlockParams(blockParams, blockSize.x(), blockSize.y())) 2489 generateNormalBlock(blockParams, blockSize.x(), blockSize.y(), generateDefaultISEInputs(blockParams)).pushBytesToVector(dst); 2490 } 2491 2492 break; 2493 } 2494 2495 case BLOCK_TEST_TYPE_WEIGHT_ISE: 2496 // For each weight ISE param set, generate blocks that cover: 2497 // - each single value of the ISE's range, at each position inside an ISE block 2498 // - for trit and quint ISEs, each single T or Q value of an ISE block 2499 { 2500 for (int iseParamsNdx = 0; iseParamsNdx < DE_LENGTH_OF_ARRAY(s_weightISEParamsCandidates); iseParamsNdx++) 2501 { 2502 const ISEParams& iseParams = s_weightISEParamsCandidates[iseParamsNdx]; 2503 NormalBlockParams blockParams; 2504 2505 blockParams.weightGridWidth = 4; 2506 blockParams.weightGridHeight = 4; 2507 blockParams.weightISEParams = iseParams; 2508 blockParams.numPartitions = 1; 2509 blockParams.isDualPlane = blockParams.weightGridWidth * blockParams.weightGridHeight < 24 ? true : false; 2510 blockParams.ccs = 0; 2511 blockParams.colorEndpointModes[0] = 0; 2512 2513 while (!isValidBlockParams(blockParams, blockSize.x(), blockSize.y())) 2514 { 2515 blockParams.weightGridWidth--; 2516 blockParams.weightGridHeight--; 2517 } 2518 2519 const int numValuesInISEBlock = iseParams.mode == ISEMODE_TRIT ? 5 : iseParams.mode == ISEMODE_QUINT ? 3 : 1; 2520 const int numWeights = computeNumWeights(blockParams); 2521 2522 { 2523 const int numWeightValues = (int)computeISERangeMax(iseParams) + 1; 2524 const int numBlocks = deDivRoundUp32(numWeightValues, numWeights); 2525 NormalBlockISEInputs iseInputs = generateDefaultISEInputs(blockParams); 2526 iseInputs.weight.isGivenInBlockForm = false; 2527 2528 for (int offset = 0; offset < numValuesInISEBlock; offset++) 2529 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++) 2530 { 2531 for (int weightNdx = 0; weightNdx < numWeights; weightNdx++) 2532 iseInputs.weight.value.plain[weightNdx] = (blockNdx*numWeights + weightNdx + offset) % numWeightValues; 2533 2534 generateNormalBlock(blockParams, blockSize.x(), blockSize.y(), iseInputs).pushBytesToVector(dst); 2535 } 2536 } 2537 2538 if (iseParams.mode == ISEMODE_TRIT || iseParams.mode == ISEMODE_QUINT) 2539 { 2540 NormalBlockISEInputs iseInputs = generateDefaultISEInputs(blockParams); 2541 iseInputs.weight.isGivenInBlockForm = true; 2542 2543 const int numTQValues = 1 << (iseParams.mode == ISEMODE_TRIT ? 8 : 7); 2544 const int numISEBlocksPerBlock = deDivRoundUp32(numWeights, numValuesInISEBlock); 2545 const int numBlocks = deDivRoundUp32(numTQValues, numISEBlocksPerBlock); 2546 2547 for (int offset = 0; offset < numValuesInISEBlock; offset++) 2548 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++) 2549 { 2550 for (int iseBlockNdx = 0; iseBlockNdx < numISEBlocksPerBlock; iseBlockNdx++) 2551 { 2552 for (int i = 0; i < numValuesInISEBlock; i++) 2553 iseInputs.weight.value.block[iseBlockNdx].bitValues[i] = 0; 2554 iseInputs.weight.value.block[iseBlockNdx].tOrQValue = (blockNdx*numISEBlocksPerBlock + iseBlockNdx + offset) % numTQValues; 2555 } 2556 2557 generateNormalBlock(blockParams, blockSize.x(), blockSize.y(), iseInputs).pushBytesToVector(dst); 2558 } 2559 } 2560 } 2561 2562 break; 2563 } 2564 2565 case BLOCK_TEST_TYPE_CEMS: 2566 // For each plane count & partition count combination, generate all color endpoint mode combinations. 2567 { 2568 for (int isDualPlane = 0; isDualPlane <= 1; isDualPlane++) 2569 for (int numPartitions = 1; numPartitions <= (isDualPlane != 0 ? 3 : 4); numPartitions++) 2570 { 2571 // Multi-partition, single-CEM mode. 2572 if (numPartitions > 1) 2573 { 2574 for (deUint32 singleCem = 0; singleCem < 16; singleCem++) 2575 { 2576 NormalBlockParams blockParams; 2577 blockParams.weightGridWidth = 4; 2578 blockParams.weightGridHeight = 4; 2579 blockParams.isDualPlane = isDualPlane != 0; 2580 blockParams.ccs = 0; 2581 blockParams.numPartitions = numPartitions; 2582 blockParams.isMultiPartSingleCemMode = true; 2583 blockParams.colorEndpointModes[0] = singleCem; 2584 blockParams.partitionSeed = 634; 2585 2586 for (int iseParamsNdx = 0; iseParamsNdx < DE_LENGTH_OF_ARRAY(s_weightISEParamsCandidates); iseParamsNdx++) 2587 { 2588 blockParams.weightISEParams = s_weightISEParamsCandidates[iseParamsNdx]; 2589 if (isValidBlockParams(blockParams, blockSize.x(), blockSize.y())) 2590 { 2591 generateNormalBlock(blockParams, blockSize.x(), blockSize.y(), generateDefaultISEInputs(blockParams)).pushBytesToVector(dst); 2592 break; 2593 } 2594 } 2595 } 2596 } 2597 2598 // Separate-CEM mode. 2599 for (deUint32 cem0 = 0; cem0 < 16; cem0++) 2600 for (deUint32 cem1 = 0; cem1 < (numPartitions >= 2 ? 16u : 1u); cem1++) 2601 for (deUint32 cem2 = 0; cem2 < (numPartitions >= 3 ? 16u : 1u); cem2++) 2602 for (deUint32 cem3 = 0; cem3 < (numPartitions >= 4 ? 16u : 1u); cem3++) 2603 { 2604 NormalBlockParams blockParams; 2605 blockParams.weightGridWidth = 4; 2606 blockParams.weightGridHeight = 4; 2607 blockParams.isDualPlane = isDualPlane != 0; 2608 blockParams.ccs = 0; 2609 blockParams.numPartitions = numPartitions; 2610 blockParams.isMultiPartSingleCemMode = false; 2611 blockParams.colorEndpointModes[0] = cem0; 2612 blockParams.colorEndpointModes[1] = cem1; 2613 blockParams.colorEndpointModes[2] = cem2; 2614 blockParams.colorEndpointModes[3] = cem3; 2615 blockParams.partitionSeed = 634; 2616 2617 { 2618 const deUint32 minCem = *std::min_element(&blockParams.colorEndpointModes[0], &blockParams.colorEndpointModes[numPartitions]); 2619 const deUint32 maxCem = *std::max_element(&blockParams.colorEndpointModes[0], &blockParams.colorEndpointModes[numPartitions]); 2620 const deUint32 minCemClass = minCem/4; 2621 const deUint32 maxCemClass = maxCem/4; 2622 2623 if (maxCemClass - minCemClass > 1) 2624 continue; 2625 } 2626 2627 for (int iseParamsNdx = 0; iseParamsNdx < DE_LENGTH_OF_ARRAY(s_weightISEParamsCandidates); iseParamsNdx++) 2628 { 2629 blockParams.weightISEParams = s_weightISEParamsCandidates[iseParamsNdx]; 2630 if (isValidBlockParams(blockParams, blockSize.x(), blockSize.y())) 2631 { 2632 generateNormalBlock(blockParams, blockSize.x(), blockSize.y(), generateDefaultISEInputs(blockParams)).pushBytesToVector(dst); 2633 break; 2634 } 2635 } 2636 } 2637 } 2638 2639 break; 2640 } 2641 2642 case BLOCK_TEST_TYPE_PARTITION_SEED: 2643 // Test all partition seeds ("partition pattern indices"). 2644 { 2645 for (int numPartitions = 2; numPartitions <= 4; numPartitions++) 2646 for (deUint32 partitionSeed = 0; partitionSeed < 1<<10; partitionSeed++) 2647 { 2648 NormalBlockParams blockParams; 2649 blockParams.weightGridWidth = 4; 2650 blockParams.weightGridHeight = 4; 2651 blockParams.weightISEParams = ISEParams(ISEMODE_PLAIN_BIT, 2); 2652 blockParams.isDualPlane = false; 2653 blockParams.numPartitions = numPartitions; 2654 blockParams.isMultiPartSingleCemMode = true; 2655 blockParams.colorEndpointModes[0] = 0; 2656 blockParams.partitionSeed = partitionSeed; 2657 2658 generateNormalBlock(blockParams, blockSize.x(), blockSize.y(), generateDefaultISEInputs(blockParams)).pushBytesToVector(dst); 2659 } 2660 2661 break; 2662 } 2663 2664 // \note Fall-through. 2665 case BLOCK_TEST_TYPE_ENDPOINT_VALUE_LDR: 2666 case BLOCK_TEST_TYPE_ENDPOINT_VALUE_HDR_NO_15: 2667 case BLOCK_TEST_TYPE_ENDPOINT_VALUE_HDR_15: 2668 // For each endpoint mode, for each pair of components in the endpoint value, test 10x10 combinations of values for that pair. 2669 // \note Separate modes for HDR and mode 15 due to different color scales and biases. 2670 { 2671 for (deUint32 cem = 0; cem < 16; cem++) 2672 { 2673 const bool isHDRCem = cem == 2 || 2674 cem == 3 || 2675 cem == 7 || 2676 cem == 11 || 2677 cem == 14 || 2678 cem == 15; 2679 2680 if ((testType == BLOCK_TEST_TYPE_ENDPOINT_VALUE_LDR && isHDRCem) || 2681 (testType == BLOCK_TEST_TYPE_ENDPOINT_VALUE_HDR_NO_15 && (!isHDRCem || cem == 15)) || 2682 (testType == BLOCK_TEST_TYPE_ENDPOINT_VALUE_HDR_15 && cem != 15)) 2683 continue; 2684 2685 NormalBlockParams blockParams; 2686 blockParams.weightGridWidth = 3; 2687 blockParams.weightGridHeight = 4; 2688 blockParams.weightISEParams = ISEParams(ISEMODE_PLAIN_BIT, 2); 2689 blockParams.isDualPlane = false; 2690 blockParams.numPartitions = 1; 2691 blockParams.colorEndpointModes[0] = cem; 2692 2693 { 2694 const int numBitsForEndpoints = computeNumBitsForColorEndpoints(blockParams); 2695 const int numEndpointParts = computeNumColorEndpointValues(cem); 2696 const ISEParams endpointISE = computeMaximumRangeISEParams(numBitsForEndpoints, numEndpointParts); 2697 const int endpointISERangeMax = computeISERangeMax(endpointISE); 2698 2699 for (int endpointPartNdx0 = 0; endpointPartNdx0 < numEndpointParts; endpointPartNdx0++) 2700 for (int endpointPartNdx1 = endpointPartNdx0+1; endpointPartNdx1 < numEndpointParts; endpointPartNdx1++) 2701 { 2702 NormalBlockISEInputs iseInputs = generateDefaultISEInputs(blockParams); 2703 const int numEndpointValues = de::min(10, endpointISERangeMax+1); 2704 2705 for (int endpointValueNdx0 = 0; endpointValueNdx0 < numEndpointValues; endpointValueNdx0++) 2706 for (int endpointValueNdx1 = 0; endpointValueNdx1 < numEndpointValues; endpointValueNdx1++) 2707 { 2708 const int endpointValue0 = endpointValueNdx0 * endpointISERangeMax / (numEndpointValues-1); 2709 const int endpointValue1 = endpointValueNdx1 * endpointISERangeMax / (numEndpointValues-1); 2710 2711 iseInputs.endpoint.value.plain[endpointPartNdx0] = endpointValue0; 2712 iseInputs.endpoint.value.plain[endpointPartNdx1] = endpointValue1; 2713 2714 generateNormalBlock(blockParams, blockSize.x(), blockSize.y(), iseInputs).pushBytesToVector(dst); 2715 } 2716 } 2717 } 2718 } 2719 2720 break; 2721 } 2722 2723 case BLOCK_TEST_TYPE_ENDPOINT_ISE: 2724 // Similar to BLOCK_TEST_TYPE_WEIGHT_ISE, see above. 2725 { 2726 static const deUint32 endpointRangeMaximums[] = { 5, 9, 11, 19, 23, 39, 47, 79, 95, 159, 191 }; 2727 2728 for (int endpointRangeNdx = 0; endpointRangeNdx < DE_LENGTH_OF_ARRAY(endpointRangeMaximums); endpointRangeNdx++) 2729 { 2730 bool validCaseGenerated = false; 2731 2732 for (int numPartitions = 1; !validCaseGenerated && numPartitions <= 4; numPartitions++) 2733 for (int isDual = 0; !validCaseGenerated && isDual <= 1; isDual++) 2734 for (int weightISEParamsNdx = 0; !validCaseGenerated && weightISEParamsNdx < DE_LENGTH_OF_ARRAY(s_weightISEParamsCandidates); weightISEParamsNdx++) 2735 for (int weightGridWidth = 2; !validCaseGenerated && weightGridWidth <= 12; weightGridWidth++) 2736 for (int weightGridHeight = 2; !validCaseGenerated && weightGridHeight <= 12; weightGridHeight++) 2737 { 2738 NormalBlockParams blockParams; 2739 blockParams.weightGridWidth = weightGridWidth; 2740 blockParams.weightGridHeight = weightGridHeight; 2741 blockParams.weightISEParams = s_weightISEParamsCandidates[weightISEParamsNdx]; 2742 blockParams.isDualPlane = isDual != 0; 2743 blockParams.ccs = 0; 2744 blockParams.numPartitions = numPartitions; 2745 blockParams.isMultiPartSingleCemMode = true; 2746 blockParams.colorEndpointModes[0] = 12; 2747 blockParams.partitionSeed = 634; 2748 2749 if (isValidBlockParams(blockParams, blockSize.x(), blockSize.y())) 2750 { 2751 const ISEParams endpointISEParams = computeMaximumRangeISEParams(computeNumBitsForColorEndpoints(blockParams), 2752 computeNumColorEndpointValues(&blockParams.colorEndpointModes[0], numPartitions, true)); 2753 2754 if (computeISERangeMax(endpointISEParams) == endpointRangeMaximums[endpointRangeNdx]) 2755 { 2756 validCaseGenerated = true; 2757 2758 const int numColorEndpoints = computeNumColorEndpointValues(&blockParams.colorEndpointModes[0], numPartitions, blockParams.isMultiPartSingleCemMode); 2759 const int numValuesInISEBlock = endpointISEParams.mode == ISEMODE_TRIT ? 5 : endpointISEParams.mode == ISEMODE_QUINT ? 3 : 1; 2760 2761 { 2762 const int numColorEndpointValues = (int)computeISERangeMax(endpointISEParams) + 1; 2763 const int numBlocks = deDivRoundUp32(numColorEndpointValues, numColorEndpoints); 2764 NormalBlockISEInputs iseInputs = generateDefaultISEInputs(blockParams); 2765 iseInputs.endpoint.isGivenInBlockForm = false; 2766 2767 for (int offset = 0; offset < numValuesInISEBlock; offset++) 2768 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++) 2769 { 2770 for (int endpointNdx = 0; endpointNdx < numColorEndpoints; endpointNdx++) 2771 iseInputs.endpoint.value.plain[endpointNdx] = (blockNdx*numColorEndpoints + endpointNdx + offset) % numColorEndpointValues; 2772 2773 generateNormalBlock(blockParams, blockSize.x(), blockSize.y(), iseInputs).pushBytesToVector(dst); 2774 } 2775 } 2776 2777 if (endpointISEParams.mode == ISEMODE_TRIT || endpointISEParams.mode == ISEMODE_QUINT) 2778 { 2779 NormalBlockISEInputs iseInputs = generateDefaultISEInputs(blockParams); 2780 iseInputs.endpoint.isGivenInBlockForm = true; 2781 2782 const int numTQValues = 1 << (endpointISEParams.mode == ISEMODE_TRIT ? 8 : 7); 2783 const int numISEBlocksPerBlock = deDivRoundUp32(numColorEndpoints, numValuesInISEBlock); 2784 const int numBlocks = deDivRoundUp32(numTQValues, numISEBlocksPerBlock); 2785 2786 for (int offset = 0; offset < numValuesInISEBlock; offset++) 2787 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++) 2788 { 2789 for (int iseBlockNdx = 0; iseBlockNdx < numISEBlocksPerBlock; iseBlockNdx++) 2790 { 2791 for (int i = 0; i < numValuesInISEBlock; i++) 2792 iseInputs.endpoint.value.block[iseBlockNdx].bitValues[i] = 0; 2793 iseInputs.endpoint.value.block[iseBlockNdx].tOrQValue = (blockNdx*numISEBlocksPerBlock + iseBlockNdx + offset) % numTQValues; 2794 } 2795 2796 generateNormalBlock(blockParams, blockSize.x(), blockSize.y(), iseInputs).pushBytesToVector(dst); 2797 } 2798 } 2799 } 2800 } 2801 } 2802 2803 DE_ASSERT(validCaseGenerated); 2804 } 2805 2806 break; 2807 } 2808 2809 case BLOCK_TEST_TYPE_CCS: 2810 // For all partition counts, test all values of the CCS (color component selector). 2811 { 2812 for (int numPartitions = 1; numPartitions <= 3; numPartitions++) 2813 for (deUint32 ccs = 0; ccs < 4; ccs++) 2814 { 2815 NormalBlockParams blockParams; 2816 blockParams.weightGridWidth = 3; 2817 blockParams.weightGridHeight = 3; 2818 blockParams.weightISEParams = ISEParams(ISEMODE_PLAIN_BIT, 2); 2819 blockParams.isDualPlane = true; 2820 blockParams.ccs = ccs; 2821 blockParams.numPartitions = numPartitions; 2822 blockParams.isMultiPartSingleCemMode = true; 2823 blockParams.colorEndpointModes[0] = 8; 2824 blockParams.partitionSeed = 634; 2825 2826 generateNormalBlock(blockParams, blockSize.x(), blockSize.y(), generateDefaultISEInputs(blockParams)).pushBytesToVector(dst); 2827 } 2828 2829 break; 2830 } 2831 2832 case BLOCK_TEST_TYPE_RANDOM: 2833 // Generate a number of random (including invalid) blocks. 2834 { 2835 const int numBlocks = 16384; 2836 const deUint32 seed = 1; 2837 2838 dst.resize(numBlocks*BLOCK_SIZE_BYTES); 2839 2840 generateRandomBlocks(&dst[0], numBlocks, format, seed); 2841 2842 break; 2843 } 2844 2845 default: 2846 DE_ASSERT(false); 2847 } 2848} 2849 2850void generateRandomBlocks (deUint8* dst, size_t numBlocks, CompressedTexFormat format, deUint32 seed) 2851{ 2852 const IVec3 blockSize = getBlockPixelSize(format); 2853 de::Random rnd (seed); 2854 size_t numBlocksGenerated = 0; 2855 2856 DE_ASSERT(isAstcFormat(format)); 2857 DE_ASSERT(blockSize.z() == 1); 2858 2859 for (numBlocksGenerated = 0; numBlocksGenerated < numBlocks; numBlocksGenerated++) 2860 { 2861 deUint8* const curBlockPtr = dst + numBlocksGenerated*BLOCK_SIZE_BYTES; 2862 2863 generateRandomBlock(curBlockPtr, blockSize, rnd); 2864 } 2865} 2866 2867void generateRandomValidBlocks (deUint8* dst, size_t numBlocks, CompressedTexFormat format, TexDecompressionParams::AstcMode mode, deUint32 seed) 2868{ 2869 const IVec3 blockSize = getBlockPixelSize(format); 2870 de::Random rnd (seed); 2871 size_t numBlocksGenerated = 0; 2872 2873 DE_ASSERT(isAstcFormat(format)); 2874 DE_ASSERT(blockSize.z() == 1); 2875 2876 for (numBlocksGenerated = 0; numBlocksGenerated < numBlocks; numBlocksGenerated++) 2877 { 2878 deUint8* const curBlockPtr = dst + numBlocksGenerated*BLOCK_SIZE_BYTES; 2879 2880 do 2881 { 2882 generateRandomBlock(curBlockPtr, blockSize, rnd); 2883 } while (!isValidBlock(curBlockPtr, format, mode)); 2884 } 2885} 2886 2887// Generate a number of trivial dummy blocks to fill unneeded space in a texture. 2888void generateDummyVoidExtentBlocks (deUint8* dst, size_t numBlocks) 2889{ 2890 AssignBlock128 block = generateVoidExtentBlock(VoidExtentParams(false, 0, 0, 0, 0)); 2891 for (size_t ndx = 0; ndx < numBlocks; ndx++) 2892 block.assignToMemory(&dst[ndx * BLOCK_SIZE_BYTES]); 2893} 2894 2895void generateDummyNormalBlocks (deUint8* dst, size_t numBlocks, int blockWidth, int blockHeight) 2896{ 2897 NormalBlockParams blockParams; 2898 2899 blockParams.weightGridWidth = 3; 2900 blockParams.weightGridHeight = 3; 2901 blockParams.weightISEParams = ISEParams(ISEMODE_PLAIN_BIT, 5); 2902 blockParams.isDualPlane = false; 2903 blockParams.numPartitions = 1; 2904 blockParams.colorEndpointModes[0] = 8; 2905 2906 NormalBlockISEInputs iseInputs = generateDefaultISEInputs(blockParams); 2907 iseInputs.weight.isGivenInBlockForm = false; 2908 2909 const int numWeights = computeNumWeights(blockParams); 2910 const int weightRangeMax = computeISERangeMax(blockParams.weightISEParams); 2911 2912 for (size_t blockNdx = 0; blockNdx < numBlocks; blockNdx++) 2913 { 2914 for (int weightNdx = 0; weightNdx < numWeights; weightNdx++) 2915 iseInputs.weight.value.plain[weightNdx] = (deUint32)((blockNdx*numWeights + weightNdx) * weightRangeMax / (numBlocks*numWeights-1)); 2916 2917 generateNormalBlock(blockParams, blockWidth, blockHeight, iseInputs).assignToMemory(dst + blockNdx*BLOCK_SIZE_BYTES); 2918 } 2919} 2920 2921bool isValidBlock (const deUint8* data, CompressedTexFormat format, TexDecompressionParams::AstcMode mode) 2922{ 2923 const tcu::IVec3 blockPixelSize = getBlockPixelSize(format); 2924 const bool isSRGB = isAstcSRGBFormat(format); 2925 const bool isLDR = isSRGB || mode == TexDecompressionParams::ASTCMODE_LDR; 2926 2927 // sRGB is not supported in HDR mode 2928 DE_ASSERT(!(mode == TexDecompressionParams::ASTCMODE_HDR && isSRGB)); 2929 2930 union 2931 { 2932 deUint8 sRGB[MAX_BLOCK_WIDTH*MAX_BLOCK_HEIGHT*4]; 2933 float linear[MAX_BLOCK_WIDTH*MAX_BLOCK_HEIGHT*4]; 2934 } tmpBuffer; 2935 const Block128 blockData (data); 2936 const DecompressResult result = decompressBlock((isSRGB ? (void*)&tmpBuffer.sRGB[0] : (void*)&tmpBuffer.linear[0]), 2937 blockData, blockPixelSize.x(), blockPixelSize.y(), isSRGB, isLDR); 2938 2939 return result == DECOMPRESS_RESULT_VALID_BLOCK; 2940} 2941 2942void decompress (const PixelBufferAccess& dst, const deUint8* data, CompressedTexFormat format, TexDecompressionParams::AstcMode mode) 2943{ 2944 const bool isSRGBFormat = isAstcSRGBFormat(format); 2945 2946#if defined(DE_DEBUG) 2947 const tcu::IVec3 blockPixelSize = getBlockPixelSize(format); 2948 2949 DE_ASSERT(dst.getWidth() == blockPixelSize.x() && 2950 dst.getHeight() == blockPixelSize.y() && 2951 dst.getDepth() == blockPixelSize.z()); 2952 DE_ASSERT(mode == TexDecompressionParams::ASTCMODE_LDR || mode == TexDecompressionParams::ASTCMODE_HDR); 2953#endif 2954 2955 // sRGB is not supported in HDR mode 2956 DE_ASSERT(!(mode == TexDecompressionParams::ASTCMODE_HDR && isSRGBFormat)); 2957 2958 decompress(dst, data, isSRGBFormat, isSRGBFormat || mode == TexDecompressionParams::ASTCMODE_LDR); 2959} 2960 2961const char* getBlockTestTypeName (BlockTestType testType) 2962{ 2963 switch (testType) 2964 { 2965 case BLOCK_TEST_TYPE_VOID_EXTENT_LDR: return "void_extent_ldr"; 2966 case BLOCK_TEST_TYPE_VOID_EXTENT_HDR: return "void_extent_hdr"; 2967 case BLOCK_TEST_TYPE_WEIGHT_GRID: return "weight_grid"; 2968 case BLOCK_TEST_TYPE_WEIGHT_ISE: return "weight_ise"; 2969 case BLOCK_TEST_TYPE_CEMS: return "color_endpoint_modes"; 2970 case BLOCK_TEST_TYPE_PARTITION_SEED: return "partition_pattern_index"; 2971 case BLOCK_TEST_TYPE_ENDPOINT_VALUE_LDR: return "endpoint_value_ldr"; 2972 case BLOCK_TEST_TYPE_ENDPOINT_VALUE_HDR_NO_15: return "endpoint_value_hdr_cem_not_15"; 2973 case BLOCK_TEST_TYPE_ENDPOINT_VALUE_HDR_15: return "endpoint_value_hdr_cem_15"; 2974 case BLOCK_TEST_TYPE_ENDPOINT_ISE: return "endpoint_ise"; 2975 case BLOCK_TEST_TYPE_CCS: return "color_component_selector"; 2976 case BLOCK_TEST_TYPE_RANDOM: return "random"; 2977 default: 2978 DE_ASSERT(false); 2979 return DE_NULL; 2980 } 2981} 2982 2983const char* getBlockTestTypeDescription (BlockTestType testType) 2984{ 2985 switch (testType) 2986 { 2987 case BLOCK_TEST_TYPE_VOID_EXTENT_LDR: return "Test void extent block, LDR mode"; 2988 case BLOCK_TEST_TYPE_VOID_EXTENT_HDR: return "Test void extent block, HDR mode"; 2989 case BLOCK_TEST_TYPE_WEIGHT_GRID: return "Test combinations of plane count, weight integer sequence encoding parameters, and weight grid size"; 2990 case BLOCK_TEST_TYPE_WEIGHT_ISE: return "Test different integer sequence encoding block values for weight grid"; 2991 case BLOCK_TEST_TYPE_CEMS: return "Test different color endpoint mode combinations, combined with different plane and partition counts"; 2992 case BLOCK_TEST_TYPE_PARTITION_SEED: return "Test different partition pattern indices"; 2993 case BLOCK_TEST_TYPE_ENDPOINT_VALUE_LDR: return "Test various combinations of each pair of color endpoint values, for each LDR color endpoint mode"; 2994 case BLOCK_TEST_TYPE_ENDPOINT_VALUE_HDR_NO_15: return "Test various combinations of each pair of color endpoint values, for each HDR color endpoint mode other than mode 15"; 2995 case BLOCK_TEST_TYPE_ENDPOINT_VALUE_HDR_15: return "Test various combinations of each pair of color endpoint values, HDR color endpoint mode 15"; 2996 case BLOCK_TEST_TYPE_ENDPOINT_ISE: return "Test different integer sequence encoding block values for color endpoints"; 2997 case BLOCK_TEST_TYPE_CCS: return "Test color component selector, for different partition counts"; 2998 case BLOCK_TEST_TYPE_RANDOM: return "Random block test"; 2999 default: 3000 DE_ASSERT(false); 3001 return DE_NULL; 3002 } 3003} 3004 3005bool isBlockTestTypeHDROnly (BlockTestType testType) 3006{ 3007 return testType == BLOCK_TEST_TYPE_VOID_EXTENT_HDR || 3008 testType == BLOCK_TEST_TYPE_ENDPOINT_VALUE_HDR_NO_15 || 3009 testType == BLOCK_TEST_TYPE_ENDPOINT_VALUE_HDR_15; 3010} 3011 3012Vec4 getBlockTestTypeColorScale (BlockTestType testType) 3013{ 3014 switch (testType) 3015 { 3016 case tcu::astc::BLOCK_TEST_TYPE_VOID_EXTENT_HDR: return Vec4(0.5f/65504.0f); 3017 case tcu::astc::BLOCK_TEST_TYPE_ENDPOINT_VALUE_HDR_NO_15: return Vec4(1.0f/65504.0f, 1.0f/65504.0f, 1.0f/65504.0f, 1.0f); 3018 case tcu::astc::BLOCK_TEST_TYPE_ENDPOINT_VALUE_HDR_15: return Vec4(1.0f/65504.0f); 3019 default: return Vec4(1.0f); 3020 } 3021} 3022 3023Vec4 getBlockTestTypeColorBias (BlockTestType testType) 3024{ 3025 switch (testType) 3026 { 3027 case tcu::astc::BLOCK_TEST_TYPE_VOID_EXTENT_HDR: return Vec4(0.5f); 3028 default: return Vec4(0.0f); 3029 } 3030} 3031 3032} // astc 3033} // tcu 3034