1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 3.0 Module
3 * -------------------------------------------------
5 * Copyright 2014 The Android Open Source Project
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 * \brief ASTC decompression tests
23 * \todo Parts of the block-generation code are same as in decompression
24 * code in tcuCompressedTexture.cpp ; could put them to some shared
27 * \todo Tests for void extents with nontrivial extent coordinates.
29 * \todo Better checking of the error color. Currently legitimate error
30 * pixels are just ignored in image comparison; however, spec says
31 * that error color is either magenta or all-NaNs. Can NaNs cause
32 * troubles, or can we assume that NaNs are well-supported in shader
33 * if the implementation chooses NaNs as error color?
34 *//*--------------------------------------------------------------------*/
36 #include "es3fASTCDecompressionCases.hpp"
37 #include "gluTexture.hpp"
38 #include "gluPixelTransfer.hpp"
39 #include "gluStrUtil.hpp"
40 #include "gluTextureUtil.hpp"
41 #include "glsTextureTestUtil.hpp"
42 #include "tcuCompressedTexture.hpp"
43 #include "tcuTestLog.hpp"
44 #include "tcuTextureUtil.hpp"
45 #include "tcuSurface.hpp"
46 #include "tcuVectorUtil.hpp"
47 #include "tcuImageCompare.hpp"
48 #include "deStringUtil.hpp"
49 #include "deRandom.hpp"
50 #include "deFloat16.h"
54 #include "glwFunctions.hpp"
55 #include "glwEnums.hpp"
62 using tcu::CompressedTexture;
63 using tcu::CompressedTexFormat;
77 using gls::TextureTestUtil::TextureRenderer;
78 using gls::TextureTestUtil::RandomViewport;
79 using gls::TextureTestUtil::ReferenceParams;
86 namespace ASTCDecompressionCaseInternal
89 static const int ASTC_BLOCK_SIZE_BYTES = 128/8;
91 static inline int divRoundUp (int a, int b)
93 return a/b + ((a%b) ? 1 : 0);
96 namespace ASTCBlockGeneratorInternal
99 static inline deUint32 reverseBits (deUint32 src, int numBits)
101 DE_ASSERT(de::inRange(numBits, 0, 32));
103 for (int i = 0; i < numBits; i++)
104 result |= ((src >> i) & 1) << (numBits-1-i);
108 static inline deUint32 getBit (deUint32 src, int ndx)
110 DE_ASSERT(de::inBounds(ndx, 0, 32));
111 return (src >> ndx) & 1;
114 static inline deUint32 getBits (deUint32 src, int low, int high)
116 const int numBits = (high-low) + 1;
119 DE_ASSERT(de::inRange(numBits, 1, 32));
120 return (src >> low) & ((1u<<numBits)-1);
123 #if defined(DE_DEBUG)
124 static inline bool isFloat16InfOrNan (deFloat16 v)
126 return getBits(v, 10, 14) == 31;
130 template <typename T, typename Y>
131 struct isSameType { enum { V = 0 }; };
132 template <typename T>
133 struct isSameType<T, T> { enum { V = 1 }; };
135 // Helper class for setting bits in a 128-bit block.
139 typedef deUint64 Word;
143 WORD_BYTES = sizeof(Word),
144 WORD_BITS = 8*WORD_BYTES,
145 NUM_WORDS = 128 / WORD_BITS
148 DE_STATIC_ASSERT(128 % WORD_BITS == 0);
151 AssignBlock128 (void)
153 for (int wordNdx = 0; wordNdx < NUM_WORDS; wordNdx++)
154 m_words[wordNdx] = 0;
157 void setBit (int ndx, deUint32 val)
159 DE_ASSERT(de::inBounds(ndx, 0, 128));
160 DE_ASSERT((val & 1) == val);
161 const int wordNdx = ndx / WORD_BITS;
162 const int bitNdx = ndx % WORD_BITS;
163 m_words[wordNdx] = (m_words[wordNdx] & ~((Word)1 << bitNdx)) | ((Word)val << bitNdx);
166 void setBits (int low, int high, deUint32 bits)
168 DE_ASSERT(de::inBounds(low, 0, 128));
169 DE_ASSERT(de::inBounds(high, 0, 128));
170 DE_ASSERT(de::inRange(high-low+1, 0, 32));
171 DE_ASSERT((bits & (((Word)1 << (high-low+1)) - 1)) == bits);
176 const int word0Ndx = low / WORD_BITS;
177 const int word1Ndx = high / WORD_BITS;
178 const int lowNdxInW0 = low % WORD_BITS;
180 if (word0Ndx == word1Ndx)
181 m_words[word0Ndx] = (m_words[word0Ndx] & ~((((Word)1 << (high-low+1)) - 1) << lowNdxInW0)) | ((Word)bits << lowNdxInW0);
184 DE_ASSERT(word1Ndx == word0Ndx + 1);
186 const int highNdxInW1 = high % WORD_BITS;
187 const int numBitsToSetInW0 = WORD_BITS - lowNdxInW0;
188 const Word bitsLowMask = ((Word)1 << numBitsToSetInW0) - 1;
190 m_words[word0Ndx] = (m_words[word0Ndx] & (((Word)1 << lowNdxInW0) - 1)) | (((Word)bits & bitsLowMask) << lowNdxInW0);
191 m_words[word1Ndx] = (m_words[word1Ndx] & ~(((Word)1 << (highNdxInW1+1)) - 1)) | (((Word)bits & ~bitsLowMask) >> numBitsToSetInW0);
195 void assignToMemory (deUint8* dst) const
197 for (int wordNdx = 0; wordNdx < NUM_WORDS; wordNdx++)
199 for (int byteNdx = 0; byteNdx < WORD_BYTES; byteNdx++)
200 dst[wordNdx*WORD_BYTES + byteNdx] = (deUint8)((m_words[wordNdx] >> (8*byteNdx)) & 0xff);
204 void pushBytesToVector (vector<deUint8>& dst) const
206 const int assignStartIndex = (int)dst.size();
207 dst.resize(dst.size() + ASTC_BLOCK_SIZE_BYTES);
208 assignToMemory(&dst[assignStartIndex]);
212 Word m_words[NUM_WORDS];
215 // A helper for sequential access into a AssignBlock128.
216 class BitAssignAccessStream
219 BitAssignAccessStream (AssignBlock128& dst, int startNdxInSrc, int length, bool forward)
221 , m_startNdxInSrc (startNdxInSrc)
223 , m_forward (forward)
228 // Set the next num bits. Bits at positions greater than or equal to m_length are not touched.
229 void setNext (int num, deUint32 bits)
231 DE_ASSERT((bits & (((deUint64)1 << num) - 1)) == bits);
233 if (num == 0 || m_ndx >= m_length)
236 const int end = m_ndx + num;
237 const int numBitsToDst = de::max(0, de::min(m_length, end) - m_ndx);
238 const int low = m_ndx;
239 const int high = m_ndx + numBitsToDst - 1;
240 const deUint32 actualBits = getBits(bits, 0, numBitsToDst-1);
244 return m_forward ? m_dst.setBits(m_startNdxInSrc + low, m_startNdxInSrc + high, actualBits)
245 : m_dst.setBits(m_startNdxInSrc - high, m_startNdxInSrc - low, reverseBits(actualBits, numBitsToDst));
249 AssignBlock128& m_dst;
250 const int m_startNdxInSrc;
252 const bool m_forward;
257 struct VoidExtentParams
259 DE_STATIC_ASSERT((isSameType<deFloat16, deUint16>::V));
265 // \note Currently extent coordinates are all set to all-ones.
267 VoidExtentParams (bool isHDR_, deUint16 r_, deUint16 g_, deUint16 b_, deUint16 a_) : isHDR(isHDR_), r(r_), g(g_), b(b_), a(a_) {}
270 static AssignBlock128 generateVoidExtentBlock (const VoidExtentParams& params)
272 AssignBlock128 block;
274 block.setBits(0, 8, 0x1fc); // \note Marks void-extent block.
275 block.setBit(9, params.isHDR);
276 block.setBits(10, 11, 3); // \note Spec shows that these bits are both set, although they serve no purpose.
278 // Extent coordinates - currently all-ones.
279 block.setBits(12, 24, 0x1fff);
280 block.setBits(25, 37, 0x1fff);
281 block.setBits(38, 50, 0x1fff);
282 block.setBits(51, 63, 0x1fff);
284 DE_ASSERT(!params.isHDR || (!isFloat16InfOrNan(params.r) &&
285 !isFloat16InfOrNan(params.g) &&
286 !isFloat16InfOrNan(params.b) &&
287 !isFloat16InfOrNan(params.a)));
289 block.setBits(64, 79, params.r);
290 block.setBits(80, 95, params.g);
291 block.setBits(96, 111, params.b);
292 block.setBits(112, 127, params.a);
311 ISEParams (ISEMode mode_, int numBits_) : mode(mode_), numBits(numBits_) {}
314 // An input array of ISE inputs for an entire ASTC block. Can be given as either single values in the
315 // range [0, maximumValueOfISERange] or as explicit block value specifications. The latter is needed
316 // so we can test all possible values of T and Q in a block, since multiple T or Q values may map
317 // to the same set of decoded values.
322 deUint32 tOrQValue; //!< The 8-bit T or 7-bit Q in a trit or quint ISE block.
323 deUint32 bitValues[5];
326 bool isGivenInBlockForm;
329 //!< \note 64 comes from the maximum number of weight values in an ASTC block.
335 : isGivenInBlockForm (false)
340 static inline int computeNumRequiredBits (const ISEParams& iseParams, int numValues)
342 switch (iseParams.mode)
344 case ISEMODE_TRIT: return divRoundUp(numValues*8, 5) + numValues*iseParams.numBits;
345 case ISEMODE_QUINT: return divRoundUp(numValues*7, 3) + numValues*iseParams.numBits;
346 case ISEMODE_PLAIN_BIT: return numValues*iseParams.numBits;
353 static inline deUint32 computeISERangeMax (const ISEParams& iseParams)
355 switch (iseParams.mode)
357 case ISEMODE_TRIT: return (1u << iseParams.numBits) * 3 - 1;
358 case ISEMODE_QUINT: return (1u << iseParams.numBits) * 5 - 1;
359 case ISEMODE_PLAIN_BIT: return (1u << iseParams.numBits) - 1;
366 struct NormalBlockParams
369 int weightGridHeight;
370 ISEParams weightISEParams;
372 deUint32 ccs; //! \note Irrelevant if !isDualPlane.
374 deUint32 colorEndpointModes[4];
375 // \note Below members are irrelevant if numPartitions == 1.
376 bool isMultiPartSingleCemMode; //! \note If true, the single CEM is at colorEndpointModes[0].
377 deUint32 partitionSeed;
379 NormalBlockParams (void)
380 : weightGridWidth (-1)
381 , weightGridHeight (-1)
382 , weightISEParams (ISEMODE_LAST, -1)
386 , isMultiPartSingleCemMode (false)
387 , partitionSeed ((deUint32)-1)
389 colorEndpointModes[0] = 0;
390 colorEndpointModes[1] = 0;
391 colorEndpointModes[2] = 0;
392 colorEndpointModes[3] = 0;
396 struct NormalBlockISEInputs
401 NormalBlockISEInputs (void)
408 static inline int computeNumWeights (const NormalBlockParams& params)
410 return params.weightGridWidth * params.weightGridHeight * (params.isDualPlane ? 2 : 1);
413 static inline int computeNumBitsForColorEndpoints (const NormalBlockParams& params)
415 const int numWeightBits = computeNumRequiredBits(params.weightISEParams, computeNumWeights(params));
416 const int numConfigDataBits = (params.numPartitions == 1 ? 17 : params.isMultiPartSingleCemMode ? 29 : 25 + 3*params.numPartitions) +
417 (params.isDualPlane ? 2 : 0);
419 return 128 - numWeightBits - numConfigDataBits;
422 static inline int computeNumColorEndpointValues (deUint32 endpointMode)
424 DE_ASSERT(endpointMode < 16);
425 return (endpointMode/4 + 1) * 2;
428 static inline int computeNumColorEndpointValues (const deUint32* endpointModes, int numPartitions, bool isMultiPartSingleCemMode)
430 if (isMultiPartSingleCemMode)
431 return numPartitions * computeNumColorEndpointValues(endpointModes[0]);
435 for (int i = 0; i < numPartitions; i++)
436 result += computeNumColorEndpointValues(endpointModes[i]);
441 static inline bool isValidBlockParams (const NormalBlockParams& params, int blockWidth, int blockHeight)
443 const int numWeights = computeNumWeights(params);
444 const int numWeightBits = computeNumRequiredBits(params.weightISEParams, numWeights);
445 const int numColorEndpointValues = computeNumColorEndpointValues(¶ms.colorEndpointModes[0], params.numPartitions, params.isMultiPartSingleCemMode);
446 const int numBitsForColorEndpoints = computeNumBitsForColorEndpoints(params);
448 return numWeights <= 64 &&
449 de::inRange(numWeightBits, 24, 96) &&
450 params.weightGridWidth <= blockWidth &&
451 params.weightGridHeight <= blockHeight &&
452 !(params.numPartitions == 4 && params.isDualPlane) &&
453 numColorEndpointValues <= 18 &&
454 numBitsForColorEndpoints >= divRoundUp(13*numColorEndpointValues, 5);
457 // Write bits 0 to 10 of an ASTC block.
458 static void writeBlockMode (AssignBlock128& dst, const NormalBlockParams& blockParams)
460 const deUint32 d = blockParams.isDualPlane != 0;
461 // r and h initialized in switch below.
464 // a, b and blockModeLayoutNdx initialized in block mode layout index detecting loop below.
465 deUint32 a = (deUint32)-1;
466 deUint32 b = (deUint32)-1;
467 int blockModeLayoutNdx;
469 // Find the values of r and h (ISE range).
470 switch (computeISERangeMax(blockParams.weightISEParams))
472 case 1: r = 2; h = 0; break;
473 case 2: r = 3; h = 0; break;
474 case 3: r = 4; h = 0; break;
475 case 4: r = 5; h = 0; break;
476 case 5: r = 6; h = 0; break;
477 case 7: r = 7; h = 0; break;
479 case 9: r = 2; h = 1; break;
480 case 11: r = 3; h = 1; break;
481 case 15: r = 4; h = 1; break;
482 case 19: r = 5; h = 1; break;
483 case 23: r = 6; h = 1; break;
484 case 31: r = 7; h = 1; break;
492 // Find block mode layout index, i.e. appropriate row in the "2d block mode layout" table in ASTC spec.
495 enum BlockModeLayoutABVariable { Z=0, A=1, B=2 };
497 static const struct BlockModeLayout
501 BlockModeLayoutABVariable gridWidthVariableTerm;
502 int gridWidthConstantTerm;
503 BlockModeLayoutABVariable gridHeightVariableTerm;
504 int gridHeightConstantTerm;
505 } blockModeLayouts[] =
512 { 2, 0, Z, 12, A, 2},
513 { 2, 0, A, 2, Z, 12},
514 { 0, 0, Z, 6, Z, 10},
515 { 0, 0, Z, 10, Z, 6},
519 for (blockModeLayoutNdx = 0; blockModeLayoutNdx < DE_LENGTH_OF_ARRAY(blockModeLayouts); blockModeLayoutNdx++)
521 const BlockModeLayout& layout = blockModeLayouts[blockModeLayoutNdx];
522 const int aMax = (1 << layout.aNumBits) - 1;
523 const int bMax = (1 << layout.bNumBits) - 1;
524 const int variableOffsetsMax[3] = { 0, aMax, bMax };
525 const int widthMin = layout.gridWidthConstantTerm;
526 const int heightMin = layout.gridHeightConstantTerm;
527 const int widthMax = widthMin + variableOffsetsMax[layout.gridWidthVariableTerm];
528 const int heightMax = heightMin + variableOffsetsMax[layout.gridHeightVariableTerm];
530 DE_ASSERT(layout.gridWidthVariableTerm != layout.gridHeightVariableTerm || layout.gridWidthVariableTerm == Z);
532 if (de::inRange(blockParams.weightGridWidth, widthMin, widthMax) &&
533 de::inRange(blockParams.weightGridHeight, heightMin, heightMax))
536 deUint32& widthVariable = layout.gridWidthVariableTerm == A ? a : layout.gridWidthVariableTerm == B ? b : dummy;
537 deUint32& heightVariable = layout.gridHeightVariableTerm == A ? a : layout.gridHeightVariableTerm == B ? b : dummy;
539 widthVariable = blockParams.weightGridWidth - layout.gridWidthConstantTerm;
540 heightVariable = blockParams.weightGridHeight - layout.gridHeightConstantTerm;
547 // Set block mode bits.
549 const deUint32 a0 = getBit(a, 0);
550 const deUint32 a1 = getBit(a, 1);
551 const deUint32 b0 = getBit(b, 0);
552 const deUint32 b1 = getBit(b, 1);
553 const deUint32 r0 = getBit(r, 0);
554 const deUint32 r1 = getBit(r, 1);
555 const deUint32 r2 = getBit(r, 2);
557 #define SB(NDX, VAL) dst.setBit((NDX), (VAL))
558 #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)
560 switch (blockModeLayoutNdx)
562 case 0: ASSIGN_BITS(d, h, b1, b0, a1, a0, r0, 0, 0, r2, r1); break;
563 case 1: ASSIGN_BITS(d, h, b1, b0, a1, a0, r0, 0, 1, r2, r1); break;
564 case 2: ASSIGN_BITS(d, h, b1, b0, a1, a0, r0, 1, 0, r2, r1); break;
565 case 3: ASSIGN_BITS(d, h, 0, b, a1, a0, r0, 1, 1, r2, r1); break;
566 case 4: ASSIGN_BITS(d, h, 1, b, a1, a0, r0, 1, 1, r2, r1); break;
567 case 5: ASSIGN_BITS(d, h, 0, 0, a1, a0, r0, r2, r1, 0, 0); break;
568 case 6: ASSIGN_BITS(d, h, 0, 1, a1, a0, r0, r2, r1, 0, 0); break;
569 case 7: ASSIGN_BITS(d, h, 1, 1, 0, 0, r0, r2, r1, 0, 0); break;
570 case 8: ASSIGN_BITS(d, h, 1, 1, 0, 1, r0, r2, r1, 0, 0); break;
571 case 9: ASSIGN_BITS(b1, b0, 1, 0, a1, a0, r0, r2, r1, 0, 0); DE_ASSERT(d == 0 && h == 0); break;
580 // Write color endpoint mode data of an ASTC block.
581 static void writeColorEndpointModes (AssignBlock128& dst, const deUint32* colorEndpointModes, bool isMultiPartSingleCemMode, int numPartitions, int extraCemBitsStart)
583 if (numPartitions == 1)
584 dst.setBits(13, 16, colorEndpointModes[0]);
587 if (isMultiPartSingleCemMode)
589 dst.setBits(23, 24, 0);
590 dst.setBits(25, 28, colorEndpointModes[0]);
594 DE_ASSERT(numPartitions > 0);
595 const deUint32 minCem = *std::min_element(&colorEndpointModes[0], &colorEndpointModes[numPartitions]);
596 const deUint32 maxCem = *std::max_element(&colorEndpointModes[0], &colorEndpointModes[numPartitions]);
597 const deUint32 minCemClass = minCem/4;
598 const deUint32 maxCemClass = maxCem/4;
599 DE_ASSERT(maxCemClass - minCemClass <= 1);
600 DE_UNREF(minCemClass); // \note For non-debug builds.
601 const deUint32 highLevelSelector = de::max(1u, maxCemClass);
603 dst.setBits(23, 24, highLevelSelector);
605 for (int partNdx = 0; partNdx < numPartitions; partNdx++)
607 const deUint32 c = colorEndpointModes[partNdx] / 4 == highLevelSelector ? 1 : 0;
608 const deUint32 m = colorEndpointModes[partNdx] % 4;
609 const deUint32 lowMBit0Ndx = numPartitions + 2*partNdx;
610 const deUint32 lowMBit1Ndx = numPartitions + 2*partNdx + 1;
611 dst.setBit(25 + partNdx, c);
612 dst.setBit(lowMBit0Ndx < 4 ? 25+lowMBit0Ndx : extraCemBitsStart+lowMBit0Ndx-4, getBit(m, 0));
613 dst.setBit(lowMBit1Ndx < 4 ? 25+lowMBit1Ndx : extraCemBitsStart+lowMBit1Ndx-4, getBit(m, 1));
619 static ISEParams computeMaximumRangeISEParams (int numAvailableBits, int numValuesInSequence)
621 int curBitsForTritMode = 6;
622 int curBitsForQuintMode = 5;
623 int curBitsForPlainBitMode = 8;
627 DE_ASSERT(curBitsForTritMode > 0 || curBitsForQuintMode > 0 || curBitsForPlainBitMode > 0);
629 const int tritRange = curBitsForTritMode > 0 ? (3 << curBitsForTritMode) - 1 : -1;
630 const int quintRange = curBitsForQuintMode > 0 ? (5 << curBitsForQuintMode) - 1 : -1;
631 const int plainBitRange = curBitsForPlainBitMode > 0 ? (1 << curBitsForPlainBitMode) - 1 : -1;
632 const int maxRange = de::max(de::max(tritRange, quintRange), plainBitRange);
634 if (maxRange == tritRange)
636 const ISEParams params(ISEMODE_TRIT, curBitsForTritMode);
637 if (computeNumRequiredBits(params, numValuesInSequence) <= numAvailableBits)
638 return ISEParams(ISEMODE_TRIT, curBitsForTritMode);
639 curBitsForTritMode--;
641 else if (maxRange == quintRange)
643 const ISEParams params(ISEMODE_QUINT, curBitsForQuintMode);
644 if (computeNumRequiredBits(params, numValuesInSequence) <= numAvailableBits)
645 return ISEParams(ISEMODE_QUINT, curBitsForQuintMode);
646 curBitsForQuintMode--;
650 const ISEParams params(ISEMODE_PLAIN_BIT, curBitsForPlainBitMode);
651 DE_ASSERT(maxRange == plainBitRange);
652 if (computeNumRequiredBits(params, numValuesInSequence) <= numAvailableBits)
653 return ISEParams(ISEMODE_PLAIN_BIT, curBitsForPlainBitMode);
654 curBitsForPlainBitMode--;
659 static void encodeISETritBlock (BitAssignAccessStream& dst, int numBits, bool fromExplicitInputBlock, const ISEInput::Block& blockInput, const deUint32* nonBlockInput, int numValues)
661 // tritBlockTValue[t0][t1][t2][t3][t4] is a value of T (not necessarily the only one) that will yield the given trits when decoded.
662 static const deUint32 tritBlockTValue[3][3][3][3][3] =
665 {{{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}}},
666 {{{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}}},
667 {{{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}}}
670 {{{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}}},
671 {{{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}}},
672 {{{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}}}
675 {{{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}}},
676 {{{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}}},
677 {{{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}}}
681 DE_ASSERT(de::inRange(numValues, 1, 5));
683 deUint32 tritParts[5];
684 deUint32 bitParts[5];
686 for (int i = 0; i < 5; i++)
690 if (fromExplicitInputBlock)
692 bitParts[i] = blockInput.bitValues[i];
693 tritParts[i] = -1; // \note Won't be used, but silences warning.
697 bitParts[i] = getBits(nonBlockInput[i], 0, numBits-1);
698 tritParts[i] = nonBlockInput[i] >> numBits;
708 const deUint32 T = fromExplicitInputBlock ? blockInput.tOrQValue : tritBlockTValue[tritParts[0]]
714 dst.setNext(numBits, bitParts[0]);
715 dst.setNext(2, getBits(T, 0, 1));
716 dst.setNext(numBits, bitParts[1]);
717 dst.setNext(2, getBits(T, 2, 3));
718 dst.setNext(numBits, bitParts[2]);
719 dst.setNext(1, getBit(T, 4));
720 dst.setNext(numBits, bitParts[3]);
721 dst.setNext(2, getBits(T, 5, 6));
722 dst.setNext(numBits, bitParts[4]);
723 dst.setNext(1, getBit(T, 7));
726 static void encodeISEQuintBlock (BitAssignAccessStream& dst, int numBits, bool fromExplicitInputBlock, const ISEInput::Block& blockInput, const deUint32* nonBlockInput, int numValues)
728 // quintBlockQValue[q0][q1][q2] is a value of Q (not necessarily the only one) that will yield the given quints when decoded.
729 static const deUint32 quintBlockQValue[5][5][5] =
731 {{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}},
732 {{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}},
733 {{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}},
734 {{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}},
735 {{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}}
738 DE_ASSERT(de::inRange(numValues, 1, 3));
740 deUint32 quintParts[3];
741 deUint32 bitParts[3];
743 for (int i = 0; i < 3; i++)
747 if (fromExplicitInputBlock)
749 bitParts[i] = blockInput.bitValues[i];
750 quintParts[i] = -1; // \note Won't be used, but silences warning.
754 bitParts[i] = getBits(nonBlockInput[i], 0, numBits-1);
755 quintParts[i] = nonBlockInput[i] >> numBits;
765 const deUint32 Q = fromExplicitInputBlock ? blockInput.tOrQValue : quintBlockQValue[quintParts[0]]
769 dst.setNext(numBits, bitParts[0]);
770 dst.setNext(3, getBits(Q, 0, 2));
771 dst.setNext(numBits, bitParts[1]);
772 dst.setNext(2, getBits(Q, 3, 4));
773 dst.setNext(numBits, bitParts[2]);
774 dst.setNext(2, getBits(Q, 5, 6));
777 static void encodeISEBitBlock (BitAssignAccessStream& dst, int numBits, deUint32 value)
779 DE_ASSERT(de::inRange(value, 0u, (1u<<numBits)-1));
780 dst.setNext(numBits, value);
783 static void encodeISE (BitAssignAccessStream& dst, const ISEParams& params, const ISEInput& input, int numValues)
785 if (params.mode == ISEMODE_TRIT)
787 const int numBlocks = divRoundUp(numValues, 5);
788 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
790 const int numValuesInBlock = blockNdx == numBlocks-1 ? numValues - 5*(numBlocks-1) : 5;
791 encodeISETritBlock(dst, params.numBits, input.isGivenInBlockForm,
792 input.isGivenInBlockForm ? input.value.block[blockNdx] : ISEInput::Block(),
793 input.isGivenInBlockForm ? DE_NULL : &input.value.plain[5*blockNdx],
797 else if (params.mode == ISEMODE_QUINT)
799 const int numBlocks = divRoundUp(numValues, 3);
800 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
802 const int numValuesInBlock = blockNdx == numBlocks-1 ? numValues - 3*(numBlocks-1) : 3;
803 encodeISEQuintBlock(dst, params.numBits, input.isGivenInBlockForm,
804 input.isGivenInBlockForm ? input.value.block[blockNdx] : ISEInput::Block(),
805 input.isGivenInBlockForm ? DE_NULL : &input.value.plain[3*blockNdx],
811 DE_ASSERT(params.mode == ISEMODE_PLAIN_BIT);
812 for (int i = 0; i < numValues; i++)
813 encodeISEBitBlock(dst, params.numBits, input.isGivenInBlockForm ? input.value.block[i].bitValues[0] : input.value.plain[i]);
817 static void writeWeightData (AssignBlock128& dst, const ISEParams& iseParams, const ISEInput& input, int numWeights)
819 const int numWeightBits = computeNumRequiredBits(iseParams, numWeights);
820 BitAssignAccessStream access (dst, 127, numWeightBits, false);
821 encodeISE(access, iseParams, input, numWeights);
824 static void writeColorEndpointData (AssignBlock128& dst, const ISEParams& iseParams, const ISEInput& input, int numEndpoints, int numBitsForColorEndpoints, int colorEndpointDataStartNdx)
826 BitAssignAccessStream access(dst, colorEndpointDataStartNdx, numBitsForColorEndpoints, true);
827 encodeISE(access, iseParams, input, numEndpoints);
830 static AssignBlock128 generateNormalBlock (const NormalBlockParams& blockParams, int blockWidth, int blockHeight, const NormalBlockISEInputs& iseInputs)
832 DE_ASSERT(isValidBlockParams(blockParams, blockWidth, blockHeight));
833 DE_UNREF(blockWidth); // \note For non-debug builds.
834 DE_UNREF(blockHeight); // \note For non-debug builds.
836 AssignBlock128 block;
837 const int numWeights = computeNumWeights(blockParams);
838 const int numWeightBits = computeNumRequiredBits(blockParams.weightISEParams, numWeights);
840 writeBlockMode(block, blockParams);
842 block.setBits(11, 12, blockParams.numPartitions - 1);
843 if (blockParams.numPartitions > 1)
844 block.setBits(13, 22, blockParams.partitionSeed);
847 const int extraCemBitsStart = 127 - numWeightBits - (blockParams.numPartitions == 1 || blockParams.isMultiPartSingleCemMode ? -1
848 : blockParams.numPartitions == 4 ? 7
849 : blockParams.numPartitions == 3 ? 4
850 : blockParams.numPartitions == 2 ? 1
853 writeColorEndpointModes(block, &blockParams.colorEndpointModes[0], blockParams.isMultiPartSingleCemMode, blockParams.numPartitions, extraCemBitsStart);
855 if (blockParams.isDualPlane)
856 block.setBits(extraCemBitsStart-2, extraCemBitsStart-1, blockParams.ccs);
859 writeWeightData(block, blockParams.weightISEParams, iseInputs.weight, numWeights);
862 const int numColorEndpointValues = computeNumColorEndpointValues(&blockParams.colorEndpointModes[0], blockParams.numPartitions, blockParams.isMultiPartSingleCemMode);
863 const int numBitsForColorEndpoints = computeNumBitsForColorEndpoints(blockParams);
864 const int colorEndpointDataStartNdx = blockParams.numPartitions == 1 ? 17 : 29;
865 const ISEParams& colorEndpointISEParams = computeMaximumRangeISEParams(numBitsForColorEndpoints, numColorEndpointValues);
867 writeColorEndpointData(block, colorEndpointISEParams, iseInputs.endpoint, numColorEndpointValues, numBitsForColorEndpoints, colorEndpointDataStartNdx);
873 // Generate default ISE inputs for weight and endpoint data - gradient-ish values.
874 static NormalBlockISEInputs generateDefaultISEInputs (const NormalBlockParams& blockParams)
876 NormalBlockISEInputs result;
879 result.weight.isGivenInBlockForm = false;
881 const int numWeights = computeNumWeights(blockParams);
882 const int weightRangeMax = computeISERangeMax(blockParams.weightISEParams);
884 if (blockParams.isDualPlane)
886 for (int i = 0; i < numWeights; i += 2)
887 result.weight.value.plain[i] = (i*weightRangeMax + (numWeights-1)/2) / (numWeights-1);
889 for (int i = 1; i < numWeights; i += 2)
890 result.weight.value.plain[i] = weightRangeMax - (i*weightRangeMax + (numWeights-1)/2) / (numWeights-1);
894 for (int i = 0; i < numWeights; i++)
895 result.weight.value.plain[i] = (i*weightRangeMax + (numWeights-1)/2) / (numWeights-1);
900 result.endpoint.isGivenInBlockForm = false;
902 const int numColorEndpointValues = computeNumColorEndpointValues(&blockParams.colorEndpointModes[0], blockParams.numPartitions, blockParams.isMultiPartSingleCemMode);
903 const int numBitsForColorEndpoints = computeNumBitsForColorEndpoints(blockParams);
904 const ISEParams& colorEndpointISEParams = computeMaximumRangeISEParams(numBitsForColorEndpoints, numColorEndpointValues);
905 const int colorEndpointRangeMax = computeISERangeMax(colorEndpointISEParams);
907 for (int i = 0; i < numColorEndpointValues; i++)
908 result.endpoint.value.plain[i] = (i*colorEndpointRangeMax + (numColorEndpointValues-1)/2) / (numColorEndpointValues-1);
914 } // ASTCBlockGeneratorInternal
916 static Vec4 getBlockTestTypeColorScale (ASTCBlockTestType testType)
920 case ASTCBLOCKTESTTYPE_VOID_EXTENT_HDR: return Vec4(0.5f/65504.0f);
921 case ASTCBLOCKTESTTYPE_ENDPOINT_VALUE_HDR_NO_15: return Vec4(1.0f/65504.0f, 1.0f/65504.0f, 1.0f/65504.0f, 1.0f);
922 case ASTCBLOCKTESTTYPE_ENDPOINT_VALUE_HDR_15: return Vec4(1.0f/65504.0f);
923 default: return Vec4(1.0f);
927 static Vec4 getBlockTestTypeColorBias (ASTCBlockTestType testType)
931 case ASTCBLOCKTESTTYPE_VOID_EXTENT_HDR: return Vec4(0.5f);
932 default: return Vec4(0.0f);
936 // Generate block data for a given ASTCBlockTestType and format.
937 static void generateBlockCaseTestData (vector<deUint8>& dst, CompressedTexFormat format, ASTCBlockTestType testType)
939 using namespace ASTCBlockGeneratorInternal;
941 static const ISEParams weightISEParamsCandidates[] =
943 ISEParams(ISEMODE_PLAIN_BIT, 1),
944 ISEParams(ISEMODE_TRIT, 0),
945 ISEParams(ISEMODE_PLAIN_BIT, 2),
946 ISEParams(ISEMODE_QUINT, 0),
947 ISEParams(ISEMODE_TRIT, 1),
948 ISEParams(ISEMODE_PLAIN_BIT, 3),
949 ISEParams(ISEMODE_QUINT, 1),
950 ISEParams(ISEMODE_TRIT, 2),
951 ISEParams(ISEMODE_PLAIN_BIT, 4),
952 ISEParams(ISEMODE_QUINT, 2),
953 ISEParams(ISEMODE_TRIT, 3),
954 ISEParams(ISEMODE_PLAIN_BIT, 5)
957 DE_ASSERT(tcu::isAstcFormat(format));
958 DE_ASSERT(!(tcu::isAstcSRGBFormat(format) && isBlockTestTypeHDROnly(testType)));
960 const IVec3 blockSize = getBlockPixelSize(format);
961 DE_ASSERT(blockSize.z() == 1);
965 case ASTCBLOCKTESTTYPE_VOID_EXTENT_LDR:
966 // Generate a gradient-like set of LDR void-extent blocks.
968 const int numBlocks = 1<<13;
969 const deUint32 numValues = 1<<16;
970 dst.reserve(numBlocks*ASTC_BLOCK_SIZE_BYTES);
972 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
974 const deUint32 baseValue = blockNdx*(numValues-1) / (numBlocks-1);
975 const deUint16 r = (deUint16)((baseValue + numValues*0/4) % numValues);
976 const deUint16 g = (deUint16)((baseValue + numValues*1/4) % numValues);
977 const deUint16 b = (deUint16)((baseValue + numValues*2/4) % numValues);
978 const deUint16 a = (deUint16)((baseValue + numValues*3/4) % numValues);
979 AssignBlock128 block;
981 generateVoidExtentBlock(VoidExtentParams(false, r, g, b, a)).pushBytesToVector(dst);
987 case ASTCBLOCKTESTTYPE_VOID_EXTENT_HDR:
988 // Generate a gradient-like set of HDR void-extent blocks, with values ranging from the largest finite negative to largest finite positive of fp16.
990 const float minValue = -65504.0f;
991 const float maxValue = +65504.0f;
992 const int numBlocks = 1<<13;
993 dst.reserve(numBlocks*ASTC_BLOCK_SIZE_BYTES);
995 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
997 const int rNdx = (blockNdx + numBlocks*0/4) % numBlocks;
998 const int gNdx = (blockNdx + numBlocks*1/4) % numBlocks;
999 const int bNdx = (blockNdx + numBlocks*2/4) % numBlocks;
1000 const int aNdx = (blockNdx + numBlocks*3/4) % numBlocks;
1001 const deFloat16 r = deFloat32To16(minValue + (float)rNdx * (maxValue - minValue) / (float)(numBlocks-1));
1002 const deFloat16 g = deFloat32To16(minValue + (float)gNdx * (maxValue - minValue) / (float)(numBlocks-1));
1003 const deFloat16 b = deFloat32To16(minValue + (float)bNdx * (maxValue - minValue) / (float)(numBlocks-1));
1004 const deFloat16 a = deFloat32To16(minValue + (float)aNdx * (maxValue - minValue) / (float)(numBlocks-1));
1006 generateVoidExtentBlock(VoidExtentParams(true, r, g, b, a)).pushBytesToVector(dst);
1012 case ASTCBLOCKTESTTYPE_WEIGHT_GRID:
1013 // Generate different combinations of plane count, weight ISE params, and grid size.
1015 for (int isDualPlane = 0; isDualPlane <= 1; isDualPlane++)
1016 for (int iseParamsNdx = 0; iseParamsNdx < DE_LENGTH_OF_ARRAY(weightISEParamsCandidates); iseParamsNdx++)
1017 for (int weightGridWidth = 2; weightGridWidth <= 12; weightGridWidth++)
1018 for (int weightGridHeight = 2; weightGridHeight <= 12; weightGridHeight++)
1020 NormalBlockParams blockParams;
1021 NormalBlockISEInputs iseInputs;
1023 blockParams.weightGridWidth = weightGridWidth;
1024 blockParams.weightGridHeight = weightGridHeight;
1025 blockParams.isDualPlane = isDualPlane != 0;
1026 blockParams.weightISEParams = weightISEParamsCandidates[iseParamsNdx];
1027 blockParams.ccs = 0;
1028 blockParams.numPartitions = 1;
1029 blockParams.colorEndpointModes[0] = 0;
1031 if (isValidBlockParams(blockParams, blockSize.x(), blockSize.y()))
1032 generateNormalBlock(blockParams, blockSize.x(), blockSize.y(), generateDefaultISEInputs(blockParams)).pushBytesToVector(dst);
1038 case ASTCBLOCKTESTTYPE_WEIGHT_ISE:
1039 // For each weight ISE param set, generate blocks that cover:
1040 // - each single value of the ISE's range, at each position inside an ISE block
1041 // - for trit and quint ISEs, each single T or Q value of an ISE block
1043 for (int iseParamsNdx = 0; iseParamsNdx < DE_LENGTH_OF_ARRAY(weightISEParamsCandidates); iseParamsNdx++)
1045 const ISEParams& iseParams = weightISEParamsCandidates[iseParamsNdx];
1046 NormalBlockParams blockParams;
1048 blockParams.weightGridWidth = 4;
1049 blockParams.weightGridHeight = 4;
1050 blockParams.weightISEParams = iseParams;
1051 blockParams.numPartitions = 1;
1052 blockParams.isDualPlane = blockParams.weightGridWidth * blockParams.weightGridHeight < 24 ? true : false;
1053 blockParams.ccs = 0;
1054 blockParams.colorEndpointModes[0] = 0;
1056 while (!isValidBlockParams(blockParams, blockSize.x(), blockSize.y()))
1058 blockParams.weightGridWidth--;
1059 blockParams.weightGridHeight--;
1062 const int numValuesInISEBlock = iseParams.mode == ISEMODE_TRIT ? 5 : iseParams.mode == ISEMODE_QUINT ? 3 : 1;
1063 const int numWeights = computeNumWeights(blockParams);
1066 const int numWeightValues = (int)computeISERangeMax(iseParams) + 1;
1067 const int numBlocks = divRoundUp(numWeightValues, numWeights);
1068 NormalBlockISEInputs iseInputs = generateDefaultISEInputs(blockParams);
1069 iseInputs.weight.isGivenInBlockForm = false;
1071 for (int offset = 0; offset < numValuesInISEBlock; offset++)
1072 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
1074 for (int weightNdx = 0; weightNdx < numWeights; weightNdx++)
1075 iseInputs.weight.value.plain[weightNdx] = (blockNdx*numWeights + weightNdx + offset) % numWeightValues;
1077 generateNormalBlock(blockParams, blockSize.x(), blockSize.y(), iseInputs).pushBytesToVector(dst);
1081 if (iseParams.mode == ISEMODE_TRIT || iseParams.mode == ISEMODE_QUINT)
1083 NormalBlockISEInputs iseInputs = generateDefaultISEInputs(blockParams);
1084 iseInputs.weight.isGivenInBlockForm = true;
1086 const int numTQValues = 1 << (iseParams.mode == ISEMODE_TRIT ? 8 : 7);
1087 const int numISEBlocksPerBlock = divRoundUp(numWeights, numValuesInISEBlock);
1088 const int numBlocks = divRoundUp(numTQValues, numISEBlocksPerBlock);
1090 for (int offset = 0; offset < numValuesInISEBlock; offset++)
1091 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
1093 for (int iseBlockNdx = 0; iseBlockNdx < numISEBlocksPerBlock; iseBlockNdx++)
1095 for (int i = 0; i < numValuesInISEBlock; i++)
1096 iseInputs.weight.value.block[iseBlockNdx].bitValues[i] = 0;
1097 iseInputs.weight.value.block[iseBlockNdx].tOrQValue = (blockNdx*numISEBlocksPerBlock + iseBlockNdx + offset) % numTQValues;
1100 generateNormalBlock(blockParams, blockSize.x(), blockSize.y(), iseInputs).pushBytesToVector(dst);
1108 case ASTCBLOCKTESTTYPE_CEMS:
1109 // For each plane count & partition count combination, generate all color endpoint mode combinations.
1111 for (int isDualPlane = 0; isDualPlane <= 1; isDualPlane++)
1112 for (int numPartitions = 1; numPartitions <= (isDualPlane != 0 ? 3 : 4); numPartitions++)
1114 // Multi-partition, single-CEM mode.
1115 if (numPartitions > 1)
1117 for (deUint32 singleCem = 0; singleCem < 16; singleCem++)
1119 NormalBlockParams blockParams;
1120 blockParams.weightGridWidth = 4;
1121 blockParams.weightGridHeight = 4;
1122 blockParams.isDualPlane = isDualPlane != 0;
1123 blockParams.ccs = 0;
1124 blockParams.numPartitions = numPartitions;
1125 blockParams.isMultiPartSingleCemMode = true;
1126 blockParams.colorEndpointModes[0] = singleCem;
1127 blockParams.partitionSeed = 634;
1129 for (int iseParamsNdx = 0; iseParamsNdx < DE_LENGTH_OF_ARRAY(weightISEParamsCandidates); iseParamsNdx++)
1131 blockParams.weightISEParams = weightISEParamsCandidates[iseParamsNdx];
1132 if (isValidBlockParams(blockParams, blockSize.x(), blockSize.y()))
1134 generateNormalBlock(blockParams, blockSize.x(), blockSize.y(), generateDefaultISEInputs(blockParams)).pushBytesToVector(dst);
1141 // Separate-CEM mode.
1142 for (deUint32 cem0 = 0; cem0 < 16; cem0++)
1143 for (deUint32 cem1 = 0; cem1 < (numPartitions >= 2 ? 16u : 1u); cem1++)
1144 for (deUint32 cem2 = 0; cem2 < (numPartitions >= 3 ? 16u : 1u); cem2++)
1145 for (deUint32 cem3 = 0; cem3 < (numPartitions >= 4 ? 16u : 1u); cem3++)
1147 NormalBlockParams blockParams;
1148 blockParams.weightGridWidth = 4;
1149 blockParams.weightGridHeight = 4;
1150 blockParams.isDualPlane = isDualPlane != 0;
1151 blockParams.ccs = 0;
1152 blockParams.numPartitions = numPartitions;
1153 blockParams.isMultiPartSingleCemMode = false;
1154 blockParams.colorEndpointModes[0] = cem0;
1155 blockParams.colorEndpointModes[1] = cem1;
1156 blockParams.colorEndpointModes[2] = cem2;
1157 blockParams.colorEndpointModes[3] = cem3;
1158 blockParams.partitionSeed = 634;
1161 const deUint32 minCem = *std::min_element(&blockParams.colorEndpointModes[0], &blockParams.colorEndpointModes[numPartitions]);
1162 const deUint32 maxCem = *std::max_element(&blockParams.colorEndpointModes[0], &blockParams.colorEndpointModes[numPartitions]);
1163 const deUint32 minCemClass = minCem/4;
1164 const deUint32 maxCemClass = maxCem/4;
1166 if (maxCemClass - minCemClass > 1)
1170 for (int iseParamsNdx = 0; iseParamsNdx < DE_LENGTH_OF_ARRAY(weightISEParamsCandidates); iseParamsNdx++)
1172 blockParams.weightISEParams = weightISEParamsCandidates[iseParamsNdx];
1173 if (isValidBlockParams(blockParams, blockSize.x(), blockSize.y()))
1175 generateNormalBlock(blockParams, blockSize.x(), blockSize.y(), generateDefaultISEInputs(blockParams)).pushBytesToVector(dst);
1185 case ASTCBLOCKTESTTYPE_PARTITION_SEED:
1186 // Test all partition seeds ("partition pattern indices").
1188 for (int numPartitions = 2; numPartitions <= 4; numPartitions++)
1189 for (deUint32 partitionSeed = 0; partitionSeed < 1<<10; partitionSeed++)
1191 NormalBlockParams blockParams;
1192 blockParams.weightGridWidth = 4;
1193 blockParams.weightGridHeight = 4;
1194 blockParams.weightISEParams = ISEParams(ISEMODE_PLAIN_BIT, 2);
1195 blockParams.isDualPlane = false;
1196 blockParams.numPartitions = numPartitions;
1197 blockParams.isMultiPartSingleCemMode = true;
1198 blockParams.colorEndpointModes[0] = 0;
1199 blockParams.partitionSeed = partitionSeed;
1201 generateNormalBlock(blockParams, blockSize.x(), blockSize.y(), generateDefaultISEInputs(blockParams)).pushBytesToVector(dst);
1207 // \note Fall-through.
1208 case ASTCBLOCKTESTTYPE_ENDPOINT_VALUE_LDR:
1209 case ASTCBLOCKTESTTYPE_ENDPOINT_VALUE_HDR_NO_15:
1210 case ASTCBLOCKTESTTYPE_ENDPOINT_VALUE_HDR_15:
1211 // For each endpoint mode, for each pair of components in the endpoint value, test 10x10 combinations of values for that pair.
1212 // \note Separate modes for HDR and mode 15 due to different color scales and biases.
1214 for (deUint32 cem = 0; cem < 16; cem++)
1216 const bool isHDRCem = cem == 2 ||
1223 if ((testType == ASTCBLOCKTESTTYPE_ENDPOINT_VALUE_LDR && isHDRCem) ||
1224 (testType == ASTCBLOCKTESTTYPE_ENDPOINT_VALUE_HDR_NO_15 && (!isHDRCem || cem == 15)) ||
1225 (testType == ASTCBLOCKTESTTYPE_ENDPOINT_VALUE_HDR_15 && cem != 15))
1228 NormalBlockParams blockParams;
1229 blockParams.weightGridWidth = 3;
1230 blockParams.weightGridHeight = 4;
1231 blockParams.weightISEParams = ISEParams(ISEMODE_PLAIN_BIT, 2);
1232 blockParams.isDualPlane = false;
1233 blockParams.numPartitions = 1;
1234 blockParams.colorEndpointModes[0] = cem;
1237 const int numBitsForEndpoints = computeNumBitsForColorEndpoints(blockParams);
1238 const int numEndpointParts = computeNumColorEndpointValues(cem);
1239 const ISEParams endpointISE = computeMaximumRangeISEParams(numBitsForEndpoints, numEndpointParts);
1240 const int endpointISERangeMax = computeISERangeMax(endpointISE);
1242 for (int endpointPartNdx0 = 0; endpointPartNdx0 < numEndpointParts; endpointPartNdx0++)
1243 for (int endpointPartNdx1 = endpointPartNdx0+1; endpointPartNdx1 < numEndpointParts; endpointPartNdx1++)
1245 NormalBlockISEInputs iseInputs = generateDefaultISEInputs(blockParams);
1246 const int numEndpointValues = de::min(10, endpointISERangeMax+1);
1248 for (int endpointValueNdx0 = 0; endpointValueNdx0 < numEndpointValues; endpointValueNdx0++)
1249 for (int endpointValueNdx1 = 0; endpointValueNdx1 < numEndpointValues; endpointValueNdx1++)
1251 const int endpointValue0 = endpointValueNdx0 * endpointISERangeMax / (numEndpointValues-1);
1252 const int endpointValue1 = endpointValueNdx1 * endpointISERangeMax / (numEndpointValues-1);
1254 iseInputs.endpoint.value.plain[endpointPartNdx0] = endpointValue0;
1255 iseInputs.endpoint.value.plain[endpointPartNdx1] = endpointValue1;
1257 generateNormalBlock(blockParams, blockSize.x(), blockSize.y(), iseInputs).pushBytesToVector(dst);
1266 case ASTCBLOCKTESTTYPE_ENDPOINT_ISE:
1267 // Similar to ASTCBLOCKTESTTYPE_WEIGHT_ISE, see above.
1269 static const deUint32 endpointRangeMaximums[] = { 5, 9, 11, 19, 23, 39, 47, 79, 95, 159, 191 };
1271 for (int endpointRangeNdx = 0; endpointRangeNdx < DE_LENGTH_OF_ARRAY(endpointRangeMaximums); endpointRangeNdx++)
1273 bool validCaseGenerated = false;
1275 for (int numPartitions = 1; !validCaseGenerated && numPartitions <= 4; numPartitions++)
1276 for (int isDual = 0; !validCaseGenerated && isDual <= 1; isDual++)
1277 for (int weightISEParamsNdx = 0; !validCaseGenerated && weightISEParamsNdx < DE_LENGTH_OF_ARRAY(weightISEParamsCandidates); weightISEParamsNdx++)
1278 for (int weightGridWidth = 2; !validCaseGenerated && weightGridWidth <= 12; weightGridWidth++)
1279 for (int weightGridHeight = 2; !validCaseGenerated && weightGridHeight <= 12; weightGridHeight++)
1281 NormalBlockParams blockParams;
1282 blockParams.weightGridWidth = weightGridWidth;
1283 blockParams.weightGridHeight = weightGridHeight;
1284 blockParams.weightISEParams = weightISEParamsCandidates[weightISEParamsNdx];
1285 blockParams.isDualPlane = isDual != 0;
1286 blockParams.ccs = 0;
1287 blockParams.numPartitions = numPartitions;
1288 blockParams.isMultiPartSingleCemMode = true;
1289 blockParams.colorEndpointModes[0] = 12;
1290 blockParams.partitionSeed = 634;
1292 if (isValidBlockParams(blockParams, blockSize.x(), blockSize.y()))
1294 const ISEParams endpointISEParams = computeMaximumRangeISEParams(computeNumBitsForColorEndpoints(blockParams),
1295 computeNumColorEndpointValues(&blockParams.colorEndpointModes[0], numPartitions, true));
1297 if (computeISERangeMax(endpointISEParams) == endpointRangeMaximums[endpointRangeNdx])
1299 validCaseGenerated = true;
1301 const int numColorEndpoints = computeNumColorEndpointValues(&blockParams.colorEndpointModes[0], numPartitions, blockParams.isMultiPartSingleCemMode);
1302 const int numValuesInISEBlock = endpointISEParams.mode == ISEMODE_TRIT ? 5 : endpointISEParams.mode == ISEMODE_QUINT ? 3 : 1;
1305 const int numColorEndpointValues = (int)computeISERangeMax(endpointISEParams) + 1;
1306 const int numBlocks = divRoundUp(numColorEndpointValues, numColorEndpoints);
1307 NormalBlockISEInputs iseInputs = generateDefaultISEInputs(blockParams);
1308 iseInputs.endpoint.isGivenInBlockForm = false;
1310 for (int offset = 0; offset < numValuesInISEBlock; offset++)
1311 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
1313 for (int endpointNdx = 0; endpointNdx < numColorEndpoints; endpointNdx++)
1314 iseInputs.endpoint.value.plain[endpointNdx] = (blockNdx*numColorEndpoints + endpointNdx + offset) % numColorEndpointValues;
1316 generateNormalBlock(blockParams, blockSize.x(), blockSize.y(), iseInputs).pushBytesToVector(dst);
1320 if (endpointISEParams.mode == ISEMODE_TRIT || endpointISEParams.mode == ISEMODE_QUINT)
1322 NormalBlockISEInputs iseInputs = generateDefaultISEInputs(blockParams);
1323 iseInputs.endpoint.isGivenInBlockForm = true;
1325 const int numTQValues = 1 << (endpointISEParams.mode == ISEMODE_TRIT ? 8 : 7);
1326 const int numISEBlocksPerBlock = divRoundUp(numColorEndpoints, numValuesInISEBlock);
1327 const int numBlocks = divRoundUp(numTQValues, numISEBlocksPerBlock);
1329 for (int offset = 0; offset < numValuesInISEBlock; offset++)
1330 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
1332 for (int iseBlockNdx = 0; iseBlockNdx < numISEBlocksPerBlock; iseBlockNdx++)
1334 for (int i = 0; i < numValuesInISEBlock; i++)
1335 iseInputs.endpoint.value.block[iseBlockNdx].bitValues[i] = 0;
1336 iseInputs.endpoint.value.block[iseBlockNdx].tOrQValue = (blockNdx*numISEBlocksPerBlock + iseBlockNdx + offset) % numTQValues;
1339 generateNormalBlock(blockParams, blockSize.x(), blockSize.y(), iseInputs).pushBytesToVector(dst);
1346 DE_ASSERT(validCaseGenerated);
1352 case ASTCBLOCKTESTTYPE_CCS:
1353 // For all partition counts, test all values of the CCS (color component selector).
1355 for (int numPartitions = 1; numPartitions <= 3; numPartitions++)
1356 for (deUint32 ccs = 0; ccs < 4; ccs++)
1358 NormalBlockParams blockParams;
1359 blockParams.weightGridWidth = 3;
1360 blockParams.weightGridHeight = 3;
1361 blockParams.weightISEParams = ISEParams(ISEMODE_PLAIN_BIT, 2);
1362 blockParams.isDualPlane = true;
1363 blockParams.ccs = ccs;
1364 blockParams.numPartitions = numPartitions;
1365 blockParams.isMultiPartSingleCemMode = true;
1366 blockParams.colorEndpointModes[0] = 8;
1367 blockParams.partitionSeed = 634;
1369 generateNormalBlock(blockParams, blockSize.x(), blockSize.y(), generateDefaultISEInputs(blockParams)).pushBytesToVector(dst);
1375 case ASTCBLOCKTESTTYPE_RANDOM:
1376 // Generate a number of random (but valid) blocks.
1378 const int numBlocks = 16384;
1380 int numBlocksGenerated = 0;
1382 dst.reserve(numBlocks*ASTC_BLOCK_SIZE_BYTES);
1384 for (numBlocksGenerated = 0; numBlocksGenerated < numBlocks; numBlocksGenerated++)
1386 if (rnd.getFloat() < 0.1f)
1388 // Void extent block.
1389 const bool isVoidExtentHDR = rnd.getBool();
1390 const deUint16 r = isVoidExtentHDR ? deFloat32To16(rnd.getFloat(0.0f, 1.0f)) : (deUint16)rnd.getInt(0, 0xffff);
1391 const deUint16 g = isVoidExtentHDR ? deFloat32To16(rnd.getFloat(0.0f, 1.0f)) : (deUint16)rnd.getInt(0, 0xffff);
1392 const deUint16 b = isVoidExtentHDR ? deFloat32To16(rnd.getFloat(0.0f, 1.0f)) : (deUint16)rnd.getInt(0, 0xffff);
1393 const deUint16 a = isVoidExtentHDR ? deFloat32To16(rnd.getFloat(0.0f, 1.0f)) : (deUint16)rnd.getInt(0, 0xffff);
1394 generateVoidExtentBlock(VoidExtentParams(isVoidExtentHDR, r, g, b, a)).pushBytesToVector(dst);
1398 // Not void extent block.
1400 // Generate block params.
1402 NormalBlockParams blockParams;
1406 blockParams.weightGridWidth = rnd.getInt(2, blockSize.x());
1407 blockParams.weightGridHeight = rnd.getInt(2, blockSize.y());
1408 blockParams.weightISEParams = weightISEParamsCandidates[rnd.getInt(0, DE_LENGTH_OF_ARRAY(weightISEParamsCandidates)-1)];
1409 blockParams.numPartitions = rnd.getInt(1, 4);
1410 blockParams.isMultiPartSingleCemMode = rnd.getFloat() < 0.25f;
1411 blockParams.isDualPlane = blockParams.numPartitions != 4 && rnd.getBool();
1412 blockParams.ccs = rnd.getInt(0, 3);
1413 blockParams.partitionSeed = rnd.getInt(0, 1023);
1415 blockParams.colorEndpointModes[0] = rnd.getInt(0, 15);
1418 const int cemDiff = blockParams.isMultiPartSingleCemMode ? 0
1419 : blockParams.colorEndpointModes[0] == 0 ? 1
1420 : blockParams.colorEndpointModes[0] == 15 ? -1
1421 : rnd.getBool() ? 1 : -1;
1423 for (int i = 1; i < blockParams.numPartitions; i++)
1424 blockParams.colorEndpointModes[i] = blockParams.colorEndpointModes[0] + (cemDiff == -1 ? rnd.getInt(-1, 0) : cemDiff == 1 ? rnd.getInt(0, 1) : 0);
1426 } while (!isValidBlockParams(blockParams, blockSize.x(), blockSize.y()));
1428 // Generate ISE inputs for both weight and endpoint data.
1430 NormalBlockISEInputs iseInputs;
1432 for (int weightOrEndpoints = 0; weightOrEndpoints <= 1; weightOrEndpoints++)
1434 const bool setWeights = weightOrEndpoints == 0;
1435 const int numValues = setWeights ? computeNumWeights(blockParams) :
1436 computeNumColorEndpointValues(&blockParams.colorEndpointModes[0], blockParams.numPartitions, blockParams.isMultiPartSingleCemMode);
1437 const ISEParams iseParams = setWeights ? blockParams.weightISEParams : computeMaximumRangeISEParams(computeNumBitsForColorEndpoints(blockParams), numValues);
1438 ISEInput& iseInput = setWeights ? iseInputs.weight : iseInputs.endpoint;
1440 iseInput.isGivenInBlockForm = rnd.getBool();
1442 if (iseInput.isGivenInBlockForm)
1444 const int numValuesPerISEBlock = iseParams.mode == ISEMODE_TRIT ? 5
1445 : iseParams.mode == ISEMODE_QUINT ? 3
1447 const int iseBitMax = (1 << iseParams.numBits) - 1;
1448 const int numISEBlocks = divRoundUp(numValues, numValuesPerISEBlock);
1450 for (int iseBlockNdx = 0; iseBlockNdx < numISEBlocks; iseBlockNdx++)
1452 iseInput.value.block[iseBlockNdx].tOrQValue = rnd.getInt(0, 255);
1453 for (int i = 0; i < numValuesPerISEBlock; i++)
1454 iseInput.value.block[iseBlockNdx].bitValues[i] = rnd.getInt(0, iseBitMax);
1459 const int rangeMax = computeISERangeMax(iseParams);
1461 for (int valueNdx = 0; valueNdx < numValues; valueNdx++)
1462 iseInput.value.plain[valueNdx] = rnd.getInt(0, rangeMax);
1466 generateNormalBlock(blockParams, blockSize.x(), blockSize.y(), iseInputs).pushBytesToVector(dst);
1478 // Get a string describing the data of an ASTC block. Currently contains just hex and bin dumps of the block.
1479 static string astcBlockDataStr (const deUint8* data)
1482 result += " Hexadecimal (big endian: upper left hex digit is block bits 127 to 124):";
1485 static const char* const hexDigits = "0123456789ABCDEF";
1487 for (int i = ASTC_BLOCK_SIZE_BYTES-1; i >= 0; i--)
1494 result += hexDigits[(data[i] & 0xf0) >> 4];
1496 result += hexDigits[(data[i] & 0x0f) >> 0];
1500 result += "\n\n Binary (big endian: upper left bit is block bit 127):";
1502 for (int i = ASTC_BLOCK_SIZE_BYTES-1; i >= 0; i--)
1509 for (int j = 8-1; j >= 0; j--)
1514 result += (data[i] >> j) & 1 ? "1" : "0";
1523 // Compare reference and result block images, reporting also the position of the first non-matching block.
1524 static bool compareBlockImages (const Surface& reference,
1525 const Surface& result,
1526 const tcu::RGBA& thresholdRGBA,
1527 const IVec2& blockSize,
1528 int numNonDummyBlocks,
1529 IVec2& firstFailedBlockCoordDst,
1530 Surface& errorMaskDst,
1533 TCU_CHECK_INTERNAL(reference.getWidth() == result.getWidth() && reference.getHeight() == result.getHeight());
1535 const int width = result.getWidth();
1536 const int height = result.getHeight();
1537 const IVec4 threshold = thresholdRGBA.toIVec();
1538 const int numXBlocks = width / blockSize.x();
1540 DE_ASSERT(width % blockSize.x() == 0 && height % blockSize.y() == 0);
1542 errorMaskDst.setSize(width, height);
1544 firstFailedBlockCoordDst = IVec2(-1, -1);
1545 maxDiffDst = IVec4(0);
1547 for (int y = 0; y < height; y++)
1548 for (int x = 0; x < width; x++)
1550 const IVec2 blockCoord = IVec2(x, y) / blockSize;
1552 if (blockCoord.y()*numXBlocks + blockCoord.x() < numNonDummyBlocks)
1554 const IVec4 refPix = reference.getPixel(x, y).toIVec();
1556 if (refPix == IVec4(255, 0, 255, 255))
1558 // ASTC error color - allow anything in result.
1559 errorMaskDst.setPixel(x, y, tcu::RGBA(255, 0, 255, 255));
1563 const IVec4 resPix = result.getPixel(x, y).toIVec();
1564 const IVec4 diff = tcu::abs(refPix - resPix);
1565 const bool isOk = tcu::boolAll(tcu::lessThanEqual(diff, threshold));
1567 maxDiffDst = tcu::max(maxDiffDst, diff);
1569 errorMaskDst.setPixel(x, y, isOk ? tcu::RGBA::green() : tcu::RGBA::red());
1571 if (!isOk && firstFailedBlockCoordDst.x() == -1)
1572 firstFailedBlockCoordDst = blockCoord;
1576 return boolAll(lessThanEqual(maxDiffDst, threshold));
1579 enum ASTCSupportLevel
1581 // \note Ordered from smallest subset to full, for convenient comparison.
1582 ASTCSUPPORTLEVEL_NONE = 0,
1583 ASTCSUPPORTLEVEL_LDR,
1584 ASTCSUPPORTLEVEL_HDR,
1585 ASTCSUPPORTLEVEL_FULL
1588 static inline ASTCSupportLevel getASTCSupportLevel (const glu::ContextInfo& contextInfo)
1590 const vector<string>& extensions = contextInfo.getExtensions();
1592 ASTCSupportLevel maxLevel = ASTCSUPPORTLEVEL_NONE;
1594 for (int extNdx = 0; extNdx < (int)extensions.size(); extNdx++)
1596 const string& ext = extensions[extNdx];
1598 maxLevel = de::max(maxLevel, ext == "GL_KHR_texture_compression_astc_ldr" ? ASTCSUPPORTLEVEL_LDR
1599 : ext == "GL_KHR_texture_compression_astc_hdr" ? ASTCSUPPORTLEVEL_HDR
1600 : ext == "GL_OES_texture_compression_astc" ? ASTCSUPPORTLEVEL_FULL
1601 : ASTCSUPPORTLEVEL_NONE);
1607 // Class handling the common rendering stuff of ASTC cases.
1608 class ASTCRenderer2D
1611 ASTCRenderer2D (Context& context,
1612 CompressedTexFormat format,
1613 deUint32 randomSeed);
1615 ~ASTCRenderer2D (void);
1617 void initialize (int minRenderWidth, int minRenderHeight, const Vec4& colorScale, const Vec4& colorBias);
1620 void render (Surface& referenceDst,
1622 const glu::Texture2D& texture,
1623 const tcu::TextureFormat& uncompressedFormat);
1625 CompressedTexFormat getFormat (void) const { return m_format; }
1626 IVec2 getBlockSize (void) const { return m_blockSize; }
1627 ASTCSupportLevel getASTCSupport (void) const { DE_ASSERT(m_initialized); return m_astcSupport; }
1631 TextureRenderer m_renderer;
1633 const CompressedTexFormat m_format;
1634 const IVec2 m_blockSize;
1635 ASTCSupportLevel m_astcSupport;
1644 } // ASTCDecompressionCaseInternal
1646 using namespace ASTCDecompressionCaseInternal;
1648 ASTCRenderer2D::ASTCRenderer2D (Context& context,
1649 CompressedTexFormat format,
1650 deUint32 randomSeed)
1651 : m_context (context)
1652 , m_renderer (context.getRenderContext(), context.getTestContext().getLog(), glu::GLSL_VERSION_300_ES, glu::PRECISION_HIGHP)
1654 , m_blockSize (tcu::getBlockPixelSize(format).xy())
1655 , m_astcSupport (ASTCSUPPORTLEVEL_NONE)
1656 , m_colorScale (-1.0f)
1657 , m_colorBias (-1.0f)
1658 , m_rnd (randomSeed)
1659 , m_initialized (false)
1661 DE_ASSERT(tcu::getBlockPixelSize(format).z() == 1);
1664 ASTCRenderer2D::~ASTCRenderer2D (void)
1669 void ASTCRenderer2D::initialize (int minRenderWidth, int minRenderHeight, const Vec4& colorScale, const Vec4& colorBias)
1671 DE_ASSERT(!m_initialized);
1673 const tcu::RenderTarget& renderTarget = m_context.getRenderTarget();
1674 TestLog& log = m_context.getTestContext().getLog();
1676 m_astcSupport = getASTCSupportLevel(m_context.getContextInfo());
1677 m_colorScale = colorScale;
1678 m_colorBias = colorBias;
1680 switch (m_astcSupport)
1682 case ASTCSUPPORTLEVEL_NONE: log << TestLog::Message << "No ASTC support detected" << TestLog::EndMessage; throw tcu::NotSupportedError("ASTC not supported");
1683 case ASTCSUPPORTLEVEL_LDR: log << TestLog::Message << "LDR ASTC support detected" << TestLog::EndMessage; break;
1684 case ASTCSUPPORTLEVEL_HDR: log << TestLog::Message << "HDR ASTC support detected" << TestLog::EndMessage; break;
1685 case ASTCSUPPORTLEVEL_FULL: log << TestLog::Message << "Full ASTC support detected" << TestLog::EndMessage; break;
1690 if (renderTarget.getWidth() < minRenderWidth || renderTarget.getHeight() < minRenderHeight)
1691 throw tcu::NotSupportedError("Render target must be at least " + de::toString(minRenderWidth) + "x" + de::toString(minRenderHeight));
1693 log << TestLog::Message << "Using color scale and bias: result = raw * " << colorScale << " + " << colorBias << TestLog::EndMessage;
1695 m_initialized = true;
1698 void ASTCRenderer2D::clear (void)
1703 void ASTCRenderer2D::render (Surface& referenceDst, Surface& resultDst, const glu::Texture2D& texture, const tcu::TextureFormat& uncompressedFormat)
1705 DE_ASSERT(m_initialized);
1707 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1708 const glu::RenderContext& renderCtx = m_context.getRenderContext();
1709 const int textureWidth = texture.getRefTexture().getWidth();
1710 const int textureHeight = texture.getRefTexture().getHeight();
1711 const RandomViewport viewport (renderCtx.getRenderTarget(), textureWidth, textureHeight, m_rnd.getUint32());
1712 ReferenceParams renderParams (gls::TextureTestUtil::TEXTURETYPE_2D);
1713 vector<float> texCoord;
1714 gls::TextureTestUtil::computeQuadTexCoord2D(texCoord, Vec2(0.0f, 0.0f), Vec2(1.0f, 1.0f));
1716 renderParams.samplerType = gls::TextureTestUtil::getSamplerType(uncompressedFormat);
1717 renderParams.sampler = Sampler(Sampler::CLAMP_TO_EDGE, Sampler::CLAMP_TO_EDGE, Sampler::CLAMP_TO_EDGE, Sampler::NEAREST, Sampler::NEAREST);
1718 renderParams.colorScale = m_colorScale;
1719 renderParams.colorBias = m_colorBias;
1721 // Setup base viewport.
1722 gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
1725 gl.activeTexture(GL_TEXTURE0);
1726 gl.bindTexture(GL_TEXTURE_2D, texture.getGLTexture());
1728 // Setup nearest neighbor filtering and clamp-to-edge.
1729 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1730 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1731 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1732 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1734 GLU_EXPECT_NO_ERROR(gl.getError(), "Set texturing state");
1737 m_renderer.renderQuad(0, &texCoord[0], renderParams);
1740 // Compute reference.
1741 sampleTexture(gls::TextureTestUtil::SurfaceAccess(referenceDst, renderCtx.getRenderTarget().getPixelFormat()), texture.getRefTexture(), &texCoord[0], renderParams);
1743 // Read GL-rendered image.
1744 glu::readPixels(renderCtx, viewport.x, viewport.y, resultDst.getAccess());
1747 ASTCBlockCase2D::ASTCBlockCase2D (Context& context,
1749 const char* description,
1750 ASTCBlockTestType testType,
1751 CompressedTexFormat format)
1752 : TestCase (context, name, description)
1753 , m_testType (testType)
1755 , m_numBlocksTested (0)
1756 , m_currentIteration (0)
1757 , m_renderer (new ASTCRenderer2D(context, format, deStringHash(getName())))
1759 DE_ASSERT(!(tcu::isAstcSRGBFormat(m_format) && isBlockTestTypeHDROnly(m_testType))); // \note There is no HDR sRGB mode, so these would be redundant.
1762 ASTCBlockCase2D::~ASTCBlockCase2D (void)
1764 ASTCBlockCase2D::deinit();
1767 void ASTCBlockCase2D::init (void)
1769 m_renderer->initialize(64, 64, getBlockTestTypeColorScale(m_testType), getBlockTestTypeColorBias(m_testType));
1771 generateBlockCaseTestData(m_blockData, m_format, m_testType);
1772 DE_ASSERT(!m_blockData.empty());
1773 DE_ASSERT(m_blockData.size() % ASTC_BLOCK_SIZE_BYTES == 0);
1775 m_testCtx.getLog() << TestLog::Message << "Total " << m_blockData.size() / ASTC_BLOCK_SIZE_BYTES << " blocks to test" << TestLog::EndMessage
1776 << TestLog::Message << "Note: Legitimate ASTC error pixels will be ignored when comparing to reference" << TestLog::EndMessage;
1779 void ASTCBlockCase2D::deinit (void)
1781 m_renderer->clear();
1782 m_blockData.clear();
1785 ASTCBlockCase2D::IterateResult ASTCBlockCase2D::iterate (void)
1787 TestLog& log = m_testCtx.getLog();
1789 if (m_renderer->getASTCSupport() == ASTCSUPPORTLEVEL_LDR && isBlockTestTypeHDROnly(m_testType))
1791 log << TestLog::Message << "Passing the case immediately, since only LDR support was detected and test only contains HDR blocks" << TestLog::EndMessage;
1792 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1796 const IVec2 blockSize = m_renderer->getBlockSize();
1797 const int totalNumBlocks = (int)m_blockData.size() / ASTC_BLOCK_SIZE_BYTES;
1798 const int numXBlocksPerImage = de::min(m_context.getRenderTarget().getWidth(), 512) / blockSize.x();
1799 const int numYBlocksPerImage = de::min(m_context.getRenderTarget().getHeight(), 512) / blockSize.y();
1800 const int numBlocksPerImage = numXBlocksPerImage * numYBlocksPerImage;
1801 const int imageWidth = numXBlocksPerImage * blockSize.x();
1802 const int imageHeight = numYBlocksPerImage * blockSize.y();
1803 const int numBlocksRemaining = totalNumBlocks - m_numBlocksTested;
1804 const int curNumNonDummyBlocks = de::min(numBlocksPerImage, numBlocksRemaining);
1805 const int curNumDummyBlocks = numBlocksPerImage - curNumNonDummyBlocks;
1806 const glu::RenderContext& renderCtx = m_context.getRenderContext();
1807 const tcu::RGBA threshold = renderCtx.getRenderTarget().getPixelFormat().getColorThreshold() + (tcu::isAstcSRGBFormat(m_format) ? tcu::RGBA(2,2,2,2) : tcu::RGBA(1,1,1,1));
1808 tcu::CompressedTexture compressed (m_format, imageWidth, imageHeight);
1810 if (m_currentIteration == 0)
1812 log << TestLog::Message << "Using texture of size "
1813 << imageWidth << "x" << imageHeight
1814 << ", with " << numXBlocksPerImage << " block columns and " << numYBlocksPerImage << " block rows "
1815 << ", with block size " << blockSize.x() << "x" << blockSize.y()
1816 << TestLog::EndMessage;
1819 DE_ASSERT(compressed.getDataSize() == numBlocksPerImage*ASTC_BLOCK_SIZE_BYTES);
1820 deMemcpy(compressed.getData(), &m_blockData[m_numBlocksTested*ASTC_BLOCK_SIZE_BYTES], curNumNonDummyBlocks*ASTC_BLOCK_SIZE_BYTES);
1821 if (curNumDummyBlocks > 1)
1822 generateDummyBlocks((deUint8*)compressed.getData() + curNumNonDummyBlocks*ASTC_BLOCK_SIZE_BYTES, curNumDummyBlocks);
1824 // Create texture and render.
1826 glu::Texture2D texture (renderCtx, m_context.getContextInfo(), 1, &compressed, tcu::TexDecompressionParams((m_renderer->getASTCSupport() == ASTCSUPPORTLEVEL_LDR ? tcu::TexDecompressionParams::ASTCMODE_LDR : tcu::TexDecompressionParams::ASTCMODE_HDR)));
1827 Surface renderedFrame (imageWidth, imageHeight);
1828 Surface referenceFrame (imageWidth, imageHeight);
1830 m_renderer->render(referenceFrame, renderedFrame, texture, getUncompressedFormat(compressed.getFormat()));
1833 // \note Since a case can draw quite many images, only log the first iteration and failures.
1837 IVec2 firstFailedBlockCoord;
1839 const bool compareOk = compareBlockImages(referenceFrame, renderedFrame, threshold, blockSize, curNumNonDummyBlocks, firstFailedBlockCoord, errorMask, maxDiff);
1841 if (m_currentIteration == 0 || !compareOk)
1843 const char* const imageSetName = "ComparisonResult";
1844 const char* const imageSetDesc = "Comparison Result";
1847 tcu::ScopedLogSection section(log, "Iteration " + de::toString(m_currentIteration),
1848 "Blocks " + de::toString(m_numBlocksTested) + " to " + de::toString(m_numBlocksTested + curNumNonDummyBlocks - 1));
1850 if (curNumDummyBlocks > 0)
1851 log << TestLog::Message << "Note: Only the first " << curNumNonDummyBlocks << " blocks in the image are relevant; rest " << curNumDummyBlocks << " are dummies and not checked" << TestLog::EndMessage;
1855 log << TestLog::Message << "Image comparison failed: max difference = " << maxDiff << ", threshold = " << threshold << TestLog::EndMessage
1856 << TestLog::ImageSet(imageSetName, imageSetDesc)
1857 << TestLog::Image("Result", "Result", renderedFrame)
1858 << TestLog::Image("Reference", "Reference", referenceFrame)
1859 << TestLog::Image("ErrorMask", "Error mask", errorMask)
1860 << TestLog::EndImageSet;
1862 const int blockNdx = m_numBlocksTested + firstFailedBlockCoord.y()*numXBlocksPerImage + firstFailedBlockCoord.x();
1863 DE_ASSERT(blockNdx < totalNumBlocks);
1865 log << TestLog::Message << "First failed block at column " << firstFailedBlockCoord.x() << " and row " << firstFailedBlockCoord.y() << TestLog::EndMessage
1866 << TestLog::Message << "Data of first failed block:\n" << astcBlockDataStr(&m_blockData[blockNdx*ASTC_BLOCK_SIZE_BYTES]) << TestLog::EndMessage;
1868 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
1873 log << TestLog::ImageSet(imageSetName, imageSetDesc)
1874 << TestLog::Image("Result", "Result", renderedFrame)
1875 << TestLog::EndImageSet;
1879 if (m_numBlocksTested + curNumNonDummyBlocks < totalNumBlocks)
1880 log << TestLog::Message << "Note: not logging further images unless reference comparison fails" << TestLog::EndMessage;
1884 m_currentIteration++;
1885 m_numBlocksTested += curNumNonDummyBlocks;
1887 if (m_numBlocksTested >= totalNumBlocks)
1889 DE_ASSERT(m_numBlocksTested == totalNumBlocks);
1890 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1897 // Generate a number of trivial dummy blocks to fill unneeded space in a texture.
1898 void ASTCBlockCase2D::generateDummyBlocks (deUint8* dst, int num)
1900 using namespace ASTCBlockGeneratorInternal;
1902 AssignBlock128 block = generateVoidExtentBlock(VoidExtentParams(false, 0, 0, 0, 0));
1903 for (int i = 0; i < num; i++)
1904 block.assignToMemory(&dst[i * ASTC_BLOCK_SIZE_BYTES]);
1907 ASTCBlockSizeRemainderCase2D::ASTCBlockSizeRemainderCase2D (Context& context,
1909 const char* description,
1910 CompressedTexFormat format)
1911 : TestCase (context, name, description)
1913 , m_currentIteration (0)
1914 , m_renderer (new ASTCRenderer2D(context, format, deStringHash(getName())))
1918 ASTCBlockSizeRemainderCase2D::~ASTCBlockSizeRemainderCase2D (void)
1920 ASTCBlockSizeRemainderCase2D::deinit();
1923 void ASTCBlockSizeRemainderCase2D::init (void)
1925 const IVec2 blockSize = m_renderer->getBlockSize();
1926 m_renderer->initialize(MAX_NUM_BLOCKS_X*blockSize.x(), MAX_NUM_BLOCKS_Y*blockSize.y(), Vec4(1.0f), Vec4(0.0f));
1929 void ASTCBlockSizeRemainderCase2D::deinit (void)
1931 m_renderer->clear();
1934 ASTCBlockSizeRemainderCase2D::IterateResult ASTCBlockSizeRemainderCase2D::iterate (void)
1936 TestLog& log = m_testCtx.getLog();
1937 const IVec2 blockSize = m_renderer->getBlockSize();
1938 const int curRemainderX = m_currentIteration % blockSize.x();
1939 const int curRemainderY = m_currentIteration / blockSize.x();
1940 const int imageWidth = (MAX_NUM_BLOCKS_X-1)*blockSize.x() + curRemainderX;
1941 const int imageHeight = (MAX_NUM_BLOCKS_Y-1)*blockSize.y() + curRemainderY;
1942 const int numBlocksX = divRoundUp(imageWidth, blockSize.x());
1943 const int numBlocksY = divRoundUp(imageHeight, blockSize.y());
1944 const int totalNumBlocks = numBlocksX * numBlocksY;
1945 const glu::RenderContext& renderCtx = m_context.getRenderContext();
1946 const tcu::RGBA threshold = renderCtx.getRenderTarget().getPixelFormat().getColorThreshold() + (tcu::isAstcSRGBFormat(m_format) ? tcu::RGBA(2,2,2,2) : tcu::RGBA(1,1,1,1));
1947 tcu::CompressedTexture compressed (m_format, imageWidth, imageHeight);
1949 DE_ASSERT(compressed.getDataSize() == totalNumBlocks*ASTC_BLOCK_SIZE_BYTES);
1950 generateDefaultBlockData((deUint8*)compressed.getData(), totalNumBlocks, blockSize.x(), blockSize.y());
1952 // Create texture and render.
1954 Surface renderedFrame (imageWidth, imageHeight);
1955 Surface referenceFrame (imageWidth, imageHeight);
1956 glu::Texture2D texture (renderCtx, m_context.getContextInfo(), 1, &compressed, tcu::TexDecompressionParams(m_renderer->getASTCSupport() == ASTCSUPPORTLEVEL_LDR ? tcu::TexDecompressionParams::ASTCMODE_LDR : tcu::TexDecompressionParams::ASTCMODE_HDR));
1958 m_renderer->render(referenceFrame, renderedFrame, texture, getUncompressedFormat(compressed.getFormat()));
1963 tcu::ScopedLogSection section(log, "Iteration " + de::toString(m_currentIteration),
1964 "Remainder " + de::toString(curRemainderX) + "x" + de::toString(curRemainderY));
1966 log << TestLog::Message << "Using texture of size "
1967 << imageWidth << "x" << imageHeight
1968 << " and block size "
1969 << blockSize.x() << "x" << blockSize.y()
1970 << "; the x and y remainders are "
1971 << curRemainderX << " and " << curRemainderY << " respectively"
1972 << TestLog::EndMessage;
1974 const bool compareOk = tcu::pixelThresholdCompare(m_testCtx.getLog(), "ComparisonResult", "Comparison Result", referenceFrame, renderedFrame, threshold,
1975 m_currentIteration == 0 ? tcu::COMPARE_LOG_RESULT : tcu::COMPARE_LOG_ON_ERROR);
1979 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
1984 if (m_currentIteration == 0 && m_currentIteration+1 < blockSize.x()*blockSize.y())
1985 log << TestLog::Message << "Note: not logging further images unless reference comparison fails" << TestLog::EndMessage;
1987 m_currentIteration++;
1989 if (m_currentIteration >= blockSize.x()*blockSize.y())
1991 DE_ASSERT(m_currentIteration == blockSize.x()*blockSize.y());
1992 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1998 void ASTCBlockSizeRemainderCase2D::generateDefaultBlockData (deUint8* dst, int numBlocks, int blockWidth, int blockHeight)
2000 using namespace ASTCBlockGeneratorInternal;
2002 NormalBlockParams blockParams;
2004 blockParams.weightGridWidth = 3;
2005 blockParams.weightGridHeight = 3;
2006 blockParams.weightISEParams = ISEParams(ISEMODE_PLAIN_BIT, 5);
2007 blockParams.isDualPlane = false;
2008 blockParams.numPartitions = 1;
2009 blockParams.colorEndpointModes[0] = 8;
2011 NormalBlockISEInputs iseInputs = generateDefaultISEInputs(blockParams);
2012 iseInputs.weight.isGivenInBlockForm = false;
2014 const int numWeights = computeNumWeights(blockParams);
2015 const int weightRangeMax = computeISERangeMax(blockParams.weightISEParams);
2017 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
2019 for (int weightNdx = 0; weightNdx < numWeights; weightNdx++)
2020 iseInputs.weight.value.plain[weightNdx] = (blockNdx*numWeights + weightNdx) * weightRangeMax / (numBlocks*numWeights-1);
2022 generateNormalBlock(blockParams, blockWidth, blockHeight, iseInputs).assignToMemory(dst + blockNdx*ASTC_BLOCK_SIZE_BYTES);
2026 const char* getBlockTestTypeName (ASTCBlockTestType testType)
2030 case ASTCBLOCKTESTTYPE_VOID_EXTENT_LDR: return "void_extent_ldr";
2031 case ASTCBLOCKTESTTYPE_VOID_EXTENT_HDR: return "void_extent_hdr";
2032 case ASTCBLOCKTESTTYPE_WEIGHT_GRID: return "weight_grid";
2033 case ASTCBLOCKTESTTYPE_WEIGHT_ISE: return "weight_ise";
2034 case ASTCBLOCKTESTTYPE_CEMS: return "color_endpoint_modes";
2035 case ASTCBLOCKTESTTYPE_PARTITION_SEED: return "partition_pattern_index";
2036 case ASTCBLOCKTESTTYPE_ENDPOINT_VALUE_LDR: return "endpoint_value_ldr";
2037 case ASTCBLOCKTESTTYPE_ENDPOINT_VALUE_HDR_NO_15: return "endpoint_value_hdr_cem_not_15";
2038 case ASTCBLOCKTESTTYPE_ENDPOINT_VALUE_HDR_15: return "endpoint_value_hdr_cem_15";
2039 case ASTCBLOCKTESTTYPE_ENDPOINT_ISE: return "endpoint_ise";
2040 case ASTCBLOCKTESTTYPE_CCS: return "color_component_selector";
2041 case ASTCBLOCKTESTTYPE_RANDOM: return "random";
2048 const char* getBlockTestTypeDescription (ASTCBlockTestType testType)
2052 case ASTCBLOCKTESTTYPE_VOID_EXTENT_LDR: return "Test void extent block, LDR mode";
2053 case ASTCBLOCKTESTTYPE_VOID_EXTENT_HDR: return "Test void extent block, HDR mode";
2054 case ASTCBLOCKTESTTYPE_WEIGHT_GRID: return "Test combinations of plane count, weight integer sequence encoding parameters, and weight grid size";
2055 case ASTCBLOCKTESTTYPE_WEIGHT_ISE: return "Test different integer sequence encoding block values for weight grid";
2056 case ASTCBLOCKTESTTYPE_CEMS: return "Test different color endpoint mode combinations, combined with different plane and partition counts";
2057 case ASTCBLOCKTESTTYPE_PARTITION_SEED: return "Test different partition pattern indices";
2058 case ASTCBLOCKTESTTYPE_ENDPOINT_VALUE_LDR: return "Test various combinations of each pair of color endpoint values, for each LDR color endpoint mode";
2059 case ASTCBLOCKTESTTYPE_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";
2060 case ASTCBLOCKTESTTYPE_ENDPOINT_VALUE_HDR_15: return "Test various combinations of each pair of color endpoint values, HDR color endpoint mode 15";
2061 case ASTCBLOCKTESTTYPE_ENDPOINT_ISE: return "Test different integer sequence encoding block values for color endpoints";
2062 case ASTCBLOCKTESTTYPE_CCS: return "Test color component selector, for different partition counts";
2063 case ASTCBLOCKTESTTYPE_RANDOM: return "Random block test";
2070 bool isBlockTestTypeHDROnly (ASTCBlockTestType testType)
2072 return testType == ASTCBLOCKTESTTYPE_VOID_EXTENT_HDR ||
2073 testType == ASTCBLOCKTESTTYPE_ENDPOINT_VALUE_HDR_NO_15 ||
2074 testType == ASTCBLOCKTESTTYPE_ENDPOINT_VALUE_HDR_15;