am 18243b3e: Relax modf(Inf) fractional part verification am: d4f9d1bde9
[platform/upstream/VK-GL-CTS.git] / modules / gles3 / functional / es3fASTCDecompressionCases.cpp
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES 3.0 Module
3  * -------------------------------------------------
4  *
5  * Copyright 2014 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 decompression tests
22  *
23  * \todo Parts of the block-generation code are same as in decompression
24  *               code in tcuCompressedTexture.cpp ; could put them to some shared
25  *               ASTC utility file.
26  *
27  * \todo Tests for void extents with nontrivial extent coordinates.
28  *
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  *//*--------------------------------------------------------------------*/
35
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"
51 #include "deString.h"
52 #include "deMemory.h"
53
54 #include "glwFunctions.hpp"
55 #include "glwEnums.hpp"
56
57 #include <vector>
58 #include <string>
59 #include <algorithm>
60
61 using tcu::TestLog;
62 using tcu::CompressedTexture;
63 using tcu::CompressedTexFormat;
64 using tcu::IVec2;
65 using tcu::IVec3;
66 using tcu::IVec4;
67 using tcu::Vec2;
68 using tcu::Vec4;
69 using tcu::Sampler;
70 using tcu::Surface;
71 using std::vector;
72 using std::string;
73
74 namespace deqp
75 {
76
77 using gls::TextureTestUtil::TextureRenderer;
78 using gls::TextureTestUtil::RandomViewport;
79 using gls::TextureTestUtil::ReferenceParams;
80
81 namespace gles3
82 {
83 namespace Functional
84 {
85
86 namespace ASTCDecompressionCaseInternal
87 {
88
89 static const int ASTC_BLOCK_SIZE_BYTES = 128/8;
90
91 static inline int divRoundUp (int a, int b)
92 {
93         return a/b + ((a%b) ? 1 : 0);
94 }
95
96 namespace ASTCBlockGeneratorInternal
97 {
98
99 static inline deUint32 reverseBits (deUint32 src, int numBits)
100 {
101         DE_ASSERT(de::inRange(numBits, 0, 32));
102         deUint32 result = 0;
103         for (int i = 0; i < numBits; i++)
104                 result |= ((src >> i) & 1) << (numBits-1-i);
105         return result;
106 }
107
108 static inline deUint32 getBit (deUint32 src, int ndx)
109 {
110         DE_ASSERT(de::inBounds(ndx, 0, 32));
111         return (src >> ndx) & 1;
112 }
113
114 static inline deUint32 getBits (deUint32 src, int low, int high)
115 {
116         const int numBits = (high-low) + 1;
117         if (numBits == 0)
118                 return 0;
119         DE_ASSERT(de::inRange(numBits, 1, 32));
120         return (src >> low) & ((1u<<numBits)-1);
121 }
122
123 #if defined(DE_DEBUG)
124 static inline bool isFloat16InfOrNan (deFloat16 v)
125 {
126         return getBits(v, 10, 14) == 31;
127 }
128 #endif
129
130 template <typename T, typename Y>
131 struct isSameType                       { enum { V = 0 }; };
132 template <typename T>
133 struct isSameType<T, T>         { enum { V = 1 }; };
134
135 // Helper class for setting bits in a 128-bit block.
136 class AssignBlock128
137 {
138 private:
139         typedef deUint64 Word;
140
141         enum
142         {
143                 WORD_BYTES      = sizeof(Word),
144                 WORD_BITS       = 8*WORD_BYTES,
145                 NUM_WORDS       = 128 / WORD_BITS
146         };
147
148         DE_STATIC_ASSERT(128 % WORD_BITS == 0);
149
150 public:
151         AssignBlock128 (void)
152         {
153                 for (int wordNdx = 0; wordNdx < NUM_WORDS; wordNdx++)
154                         m_words[wordNdx] = 0;
155         }
156
157         void setBit (int ndx, deUint32 val)
158         {
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);
164         }
165
166         void setBits (int low, int high, deUint32 bits)
167         {
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);
172
173                 if (high-low+1 == 0)
174                         return;
175
176                 const int word0Ndx              = low / WORD_BITS;
177                 const int word1Ndx              = high / WORD_BITS;
178                 const int lowNdxInW0    = low % WORD_BITS;
179
180                 if (word0Ndx == word1Ndx)
181                         m_words[word0Ndx] = (m_words[word0Ndx] & ~((((Word)1 << (high-low+1)) - 1) << lowNdxInW0)) | ((Word)bits << lowNdxInW0);
182                 else
183                 {
184                         DE_ASSERT(word1Ndx == word0Ndx + 1);
185
186                         const int       highNdxInW1                     = high % WORD_BITS;
187                         const int       numBitsToSetInW0        = WORD_BITS - lowNdxInW0;
188                         const Word      bitsLowMask                     = ((Word)1 << numBitsToSetInW0) - 1;
189
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);
192                 }
193         }
194
195         void assignToMemory (deUint8* dst) const
196         {
197                 for (int wordNdx = 0; wordNdx < NUM_WORDS; wordNdx++)
198                 {
199                         for (int byteNdx = 0; byteNdx < WORD_BYTES; byteNdx++)
200                                 dst[wordNdx*WORD_BYTES + byteNdx] = (deUint8)((m_words[wordNdx] >> (8*byteNdx)) & 0xff);
201                 }
202         }
203
204         void pushBytesToVector (vector<deUint8>& dst) const
205         {
206                 const int assignStartIndex = (int)dst.size();
207                 dst.resize(dst.size() + ASTC_BLOCK_SIZE_BYTES);
208                 assignToMemory(&dst[assignStartIndex]);
209         }
210
211 private:
212         Word m_words[NUM_WORDS];
213 };
214
215 // A helper for sequential access into a AssignBlock128.
216 class BitAssignAccessStream
217 {
218 public:
219         BitAssignAccessStream (AssignBlock128& dst, int startNdxInSrc, int length, bool forward)
220                 : m_dst                         (dst)
221                 , m_startNdxInSrc       (startNdxInSrc)
222                 , m_length                      (length)
223                 , m_forward                     (forward)
224                 , m_ndx                         (0)
225         {
226         }
227
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)
230         {
231                 DE_ASSERT((bits & (((deUint64)1 << num) - 1)) == bits);
232
233                 if (num == 0 || m_ndx >= m_length)
234                         return;
235
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);
241
242                 m_ndx += num;
243
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));
246         }
247
248 private:
249         AssignBlock128&         m_dst;
250         const int                       m_startNdxInSrc;
251         const int                       m_length;
252         const bool                      m_forward;
253
254         int                                     m_ndx;
255 };
256
257 struct VoidExtentParams
258 {
259         DE_STATIC_ASSERT((isSameType<deFloat16, deUint16>::V));
260         bool            isHDR;
261         deUint16        r;
262         deUint16        g;
263         deUint16        b;
264         deUint16        a;
265         // \note Currently extent coordinates are all set to all-ones.
266
267         VoidExtentParams (bool isHDR_, deUint16 r_, deUint16 g_, deUint16 b_, deUint16 a_) : isHDR(isHDR_), r(r_), g(g_), b(b_), a(a_) {}
268 };
269
270 static AssignBlock128 generateVoidExtentBlock (const VoidExtentParams& params)
271 {
272         AssignBlock128 block;
273
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.
277
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);
283
284         DE_ASSERT(!params.isHDR || (!isFloat16InfOrNan(params.r) &&
285                                                                 !isFloat16InfOrNan(params.g) &&
286                                                                 !isFloat16InfOrNan(params.b) &&
287                                                                 !isFloat16InfOrNan(params.a)));
288
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);
293
294         return block;
295 }
296
297 enum ISEMode
298 {
299         ISEMODE_TRIT = 0,
300         ISEMODE_QUINT,
301         ISEMODE_PLAIN_BIT,
302
303         ISEMODE_LAST
304 };
305
306 struct ISEParams
307 {
308         ISEMode         mode;
309         int                     numBits;
310
311         ISEParams (ISEMode mode_, int numBits_) : mode(mode_), numBits(numBits_) {}
312 };
313
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.
318 struct ISEInput
319 {
320         struct Block
321         {
322                 deUint32 tOrQValue; //!< The 8-bit T or 7-bit Q in a trit or quint ISE block.
323                 deUint32 bitValues[5];
324         };
325
326         bool isGivenInBlockForm;
327         union
328         {
329                 //!< \note 64 comes from the maximum number of weight values in an ASTC block.
330                 deUint32        plain[64];
331                 Block           block[64];
332         } value;
333
334         ISEInput (void)
335                 : isGivenInBlockForm (false)
336         {
337         }
338 };
339
340 static inline int computeNumRequiredBits (const ISEParams& iseParams, int numValues)
341 {
342         switch (iseParams.mode)
343         {
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;
347                 default:
348                         DE_ASSERT(false);
349                         return -1;
350         }
351 }
352
353 static inline deUint32 computeISERangeMax (const ISEParams& iseParams)
354 {
355         switch (iseParams.mode)
356         {
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;
360                 default:
361                         DE_ASSERT(false);
362                         return -1;
363         }
364 }
365
366 struct NormalBlockParams
367 {
368         int                                     weightGridWidth;
369         int                                     weightGridHeight;
370         ISEParams                       weightISEParams;
371         bool                            isDualPlane;
372         deUint32                        ccs; //! \note Irrelevant if !isDualPlane.
373         int                                     numPartitions;
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;
378
379         NormalBlockParams (void)
380                 : weightGridWidth                       (-1)
381                 , weightGridHeight                      (-1)
382                 , weightISEParams                       (ISEMODE_LAST, -1)
383                 , isDualPlane                           (true)
384                 , ccs                                           ((deUint32)-1)
385                 , numPartitions                         (-1)
386                 , isMultiPartSingleCemMode      (false)
387                 , partitionSeed                         ((deUint32)-1)
388         {
389                 colorEndpointModes[0] = 0;
390                 colorEndpointModes[1] = 0;
391                 colorEndpointModes[2] = 0;
392                 colorEndpointModes[3] = 0;
393         }
394 };
395
396 struct NormalBlockISEInputs
397 {
398         ISEInput weight;
399         ISEInput endpoint;
400
401         NormalBlockISEInputs (void)
402                 : weight        ()
403                 , endpoint      ()
404         {
405         }
406 };
407
408 static inline int computeNumWeights (const NormalBlockParams& params)
409 {
410         return params.weightGridWidth * params.weightGridHeight * (params.isDualPlane ? 2 : 1);
411 }
412
413 static inline int computeNumBitsForColorEndpoints (const NormalBlockParams& params)
414 {
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);
418
419         return 128 - numWeightBits - numConfigDataBits;
420 }
421
422 static inline int computeNumColorEndpointValues (deUint32 endpointMode)
423 {
424         DE_ASSERT(endpointMode < 16);
425         return (endpointMode/4 + 1) * 2;
426 }
427
428 static inline int computeNumColorEndpointValues (const deUint32* endpointModes, int numPartitions, bool isMultiPartSingleCemMode)
429 {
430         if (isMultiPartSingleCemMode)
431                 return numPartitions * computeNumColorEndpointValues(endpointModes[0]);
432         else
433         {
434                 int result = 0;
435                 for (int i = 0; i < numPartitions; i++)
436                         result += computeNumColorEndpointValues(endpointModes[i]);
437                 return result;
438         }
439 }
440
441 static inline bool isValidBlockParams (const NormalBlockParams& params, int blockWidth, int blockHeight)
442 {
443         const int numWeights                            = computeNumWeights(params);
444         const int numWeightBits                         = computeNumRequiredBits(params.weightISEParams, numWeights);
445         const int numColorEndpointValues        = computeNumColorEndpointValues(&params.colorEndpointModes[0], params.numPartitions, params.isMultiPartSingleCemMode);
446         const int numBitsForColorEndpoints      = computeNumBitsForColorEndpoints(params);
447
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);
455 }
456
457 // Write bits 0 to 10 of an ASTC block.
458 static void writeBlockMode (AssignBlock128& dst, const NormalBlockParams& blockParams)
459 {
460         const deUint32  d = blockParams.isDualPlane != 0;
461         // r and h initialized in switch below.
462         deUint32                r;
463         deUint32                h;
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;
468
469         // Find the values of r and h (ISE range).
470         switch (computeISERangeMax(blockParams.weightISEParams))
471         {
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;
478
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;
485
486                 default:
487                         DE_ASSERT(false);
488                         r = (deUint32)-1;
489                         h = (deUint32)-1;
490         }
491
492         // Find block mode layout index, i.e. appropriate row in the "2d block mode layout" table in ASTC spec.
493
494         {
495                 enum BlockModeLayoutABVariable { Z=0, A=1, B=2 };
496
497                 static const struct BlockModeLayout
498                 {
499                         int                                                     aNumBits;
500                         int                                                     bNumBits;
501                         BlockModeLayoutABVariable       gridWidthVariableTerm;
502                         int                                                     gridWidthConstantTerm;
503                         BlockModeLayoutABVariable       gridHeightVariableTerm;
504                         int                                                     gridHeightConstantTerm;
505                 } blockModeLayouts[] =
506                 {
507                         { 2, 2,   B,  4,   A,  2},
508                         { 2, 2,   B,  8,   A,  2},
509                         { 2, 2,   A,  2,   B,  8},
510                         { 2, 1,   A,  2,   B,  6},
511                         { 2, 1,   B,  2,   A,  2},
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},
516                         { 2, 2,   A,  6,   B,  6}
517                 };
518
519                 for (blockModeLayoutNdx = 0; blockModeLayoutNdx < DE_LENGTH_OF_ARRAY(blockModeLayouts); blockModeLayoutNdx++)
520                 {
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];
529
530                         DE_ASSERT(layout.gridWidthVariableTerm != layout.gridHeightVariableTerm || layout.gridWidthVariableTerm == Z);
531
532                         if (de::inRange(blockParams.weightGridWidth, widthMin, widthMax) &&
533                                 de::inRange(blockParams.weightGridHeight, heightMin, heightMax))
534                         {
535                                 deUint32        dummy                   = 0;
536                                 deUint32&       widthVariable   = layout.gridWidthVariableTerm == A  ? a : layout.gridWidthVariableTerm == B  ? b : dummy;
537                                 deUint32&       heightVariable  = layout.gridHeightVariableTerm == A ? a : layout.gridHeightVariableTerm == B ? b : dummy;
538
539                                 widthVariable   = blockParams.weightGridWidth  - layout.gridWidthConstantTerm;
540                                 heightVariable  = blockParams.weightGridHeight - layout.gridHeightConstantTerm;
541
542                                 break;
543                         }
544                 }
545         }
546
547         // Set block mode bits.
548
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);
556
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)
559
560         switch (blockModeLayoutNdx)
561         {
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;
572                 default:
573                         DE_ASSERT(false);
574         }
575
576 #undef ASSIGN_BITS
577 #undef SB
578 }
579
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)
582 {
583         if (numPartitions == 1)
584                 dst.setBits(13, 16, colorEndpointModes[0]);
585         else
586         {
587                 if (isMultiPartSingleCemMode)
588                 {
589                         dst.setBits(23, 24, 0);
590                         dst.setBits(25, 28, colorEndpointModes[0]);
591                 }
592                 else
593                 {
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);
602
603                         dst.setBits(23, 24, highLevelSelector);
604
605                         for (int partNdx = 0; partNdx < numPartitions; partNdx++)
606                         {
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));
614                         }
615                 }
616         }
617 }
618
619 static ISEParams computeMaximumRangeISEParams (int numAvailableBits, int numValuesInSequence)
620 {
621         int curBitsForTritMode          = 6;
622         int curBitsForQuintMode         = 5;
623         int curBitsForPlainBitMode      = 8;
624
625         while (true)
626         {
627                 DE_ASSERT(curBitsForTritMode > 0 || curBitsForQuintMode > 0 || curBitsForPlainBitMode > 0);
628
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);
633
634                 if (maxRange == tritRange)
635                 {
636                         const ISEParams params(ISEMODE_TRIT, curBitsForTritMode);
637                         if (computeNumRequiredBits(params, numValuesInSequence) <= numAvailableBits)
638                                 return ISEParams(ISEMODE_TRIT, curBitsForTritMode);
639                         curBitsForTritMode--;
640                 }
641                 else if (maxRange == quintRange)
642                 {
643                         const ISEParams params(ISEMODE_QUINT, curBitsForQuintMode);
644                         if (computeNumRequiredBits(params, numValuesInSequence) <= numAvailableBits)
645                                 return ISEParams(ISEMODE_QUINT, curBitsForQuintMode);
646                         curBitsForQuintMode--;
647                 }
648                 else
649                 {
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--;
655                 }
656         }
657 }
658
659 static void encodeISETritBlock (BitAssignAccessStream& dst, int numBits, bool fromExplicitInputBlock, const ISEInput::Block& blockInput, const deUint32* nonBlockInput, int numValues)
660 {
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] =
663         {
664                 {
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}}}
668                 },
669                 {
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}}}
673                 },
674                 {
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}}}
678                 }
679         };
680
681         DE_ASSERT(de::inRange(numValues, 1, 5));
682
683         deUint32 tritParts[5];
684         deUint32 bitParts[5];
685
686         for (int i = 0; i < 5; i++)
687         {
688                 if (i < numValues)
689                 {
690                         if (fromExplicitInputBlock)
691                         {
692                                 bitParts[i]             = blockInput.bitValues[i];
693                                 tritParts[i]    = -1; // \note Won't be used, but silences warning.
694                         }
695                         else
696                         {
697                                 bitParts[i]             = getBits(nonBlockInput[i], 0, numBits-1);
698                                 tritParts[i]    = nonBlockInput[i] >> numBits;
699                         }
700                 }
701                 else
702                 {
703                         bitParts[i]             = 0;
704                         tritParts[i]    = 0;
705                 }
706         }
707
708         const deUint32 T = fromExplicitInputBlock ? blockInput.tOrQValue : tritBlockTValue[tritParts[0]]
709                                                                                                                                                                           [tritParts[1]]
710                                                                                                                                                                           [tritParts[2]]
711                                                                                                                                                                           [tritParts[3]]
712                                                                                                                                                                           [tritParts[4]];
713
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));
724 }
725
726 static void encodeISEQuintBlock (BitAssignAccessStream& dst, int numBits, bool fromExplicitInputBlock, const ISEInput::Block& blockInput, const deUint32* nonBlockInput, int numValues)
727 {
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] =
730         {
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}}
736         };
737
738         DE_ASSERT(de::inRange(numValues, 1, 3));
739
740         deUint32 quintParts[3];
741         deUint32 bitParts[3];
742
743         for (int i = 0; i < 3; i++)
744         {
745                 if (i < numValues)
746                 {
747                         if (fromExplicitInputBlock)
748                         {
749                                 bitParts[i]             = blockInput.bitValues[i];
750                                 quintParts[i]   = -1; // \note Won't be used, but silences warning.
751                         }
752                         else
753                         {
754                                 bitParts[i]             = getBits(nonBlockInput[i], 0, numBits-1);
755                                 quintParts[i]   = nonBlockInput[i] >> numBits;
756                         }
757                 }
758                 else
759                 {
760                         bitParts[i]             = 0;
761                         quintParts[i]   = 0;
762                 }
763         }
764
765         const deUint32 Q = fromExplicitInputBlock ? blockInput.tOrQValue : quintBlockQValue[quintParts[0]]
766                                                                                                                                                                            [quintParts[1]]
767                                                                                                                                                                            [quintParts[2]];
768
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));
775 }
776
777 static void encodeISEBitBlock (BitAssignAccessStream& dst, int numBits, deUint32 value)
778 {
779         DE_ASSERT(de::inRange(value, 0u, (1u<<numBits)-1));
780         dst.setNext(numBits, value);
781 }
782
783 static void encodeISE (BitAssignAccessStream& dst, const ISEParams& params, const ISEInput& input, int numValues)
784 {
785         if (params.mode == ISEMODE_TRIT)
786         {
787                 const int numBlocks = divRoundUp(numValues, 5);
788                 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
789                 {
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],
794                                                            numValuesInBlock);
795                 }
796         }
797         else if (params.mode == ISEMODE_QUINT)
798         {
799                 const int numBlocks = divRoundUp(numValues, 3);
800                 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
801                 {
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],
806                                                                 numValuesInBlock);
807                 }
808         }
809         else
810         {
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]);
814         }
815 }
816
817 static void writeWeightData (AssignBlock128& dst, const ISEParams& iseParams, const ISEInput& input, int numWeights)
818 {
819         const int                               numWeightBits   = computeNumRequiredBits(iseParams, numWeights);
820         BitAssignAccessStream   access                  (dst, 127, numWeightBits, false);
821         encodeISE(access, iseParams, input, numWeights);
822 }
823
824 static void writeColorEndpointData (AssignBlock128& dst, const ISEParams& iseParams, const ISEInput& input, int numEndpoints, int numBitsForColorEndpoints, int colorEndpointDataStartNdx)
825 {
826         BitAssignAccessStream access(dst, colorEndpointDataStartNdx, numBitsForColorEndpoints, true);
827         encodeISE(access, iseParams, input, numEndpoints);
828 }
829
830 static AssignBlock128 generateNormalBlock (const NormalBlockParams& blockParams, int blockWidth, int blockHeight, const NormalBlockISEInputs& iseInputs)
831 {
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.
835
836         AssignBlock128  block;
837         const int               numWeights              = computeNumWeights(blockParams);
838         const int               numWeightBits   = computeNumRequiredBits(blockParams.weightISEParams, numWeights);
839
840         writeBlockMode(block, blockParams);
841
842         block.setBits(11, 12, blockParams.numPartitions - 1);
843         if (blockParams.numPartitions > 1)
844                 block.setBits(13, 22, blockParams.partitionSeed);
845
846         {
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
851                                                                                                                         : 0);
852
853                 writeColorEndpointModes(block, &blockParams.colorEndpointModes[0], blockParams.isMultiPartSingleCemMode, blockParams.numPartitions, extraCemBitsStart);
854
855                 if (blockParams.isDualPlane)
856                         block.setBits(extraCemBitsStart-2, extraCemBitsStart-1, blockParams.ccs);
857         }
858
859         writeWeightData(block, blockParams.weightISEParams, iseInputs.weight, numWeights);
860
861         {
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);
866
867                 writeColorEndpointData(block, colorEndpointISEParams, iseInputs.endpoint, numColorEndpointValues, numBitsForColorEndpoints, colorEndpointDataStartNdx);
868         }
869
870         return block;
871 }
872
873 // Generate default ISE inputs for weight and endpoint data - gradient-ish values.
874 static NormalBlockISEInputs generateDefaultISEInputs (const NormalBlockParams& blockParams)
875 {
876         NormalBlockISEInputs result;
877
878         {
879                 result.weight.isGivenInBlockForm = false;
880
881                 const int numWeights            = computeNumWeights(blockParams);
882                 const int weightRangeMax        = computeISERangeMax(blockParams.weightISEParams);
883
884                 if (blockParams.isDualPlane)
885                 {
886                         for (int i = 0; i < numWeights; i += 2)
887                                 result.weight.value.plain[i] = (i*weightRangeMax + (numWeights-1)/2) / (numWeights-1);
888
889                         for (int i = 1; i < numWeights; i += 2)
890                                 result.weight.value.plain[i] = weightRangeMax - (i*weightRangeMax + (numWeights-1)/2) / (numWeights-1);
891                 }
892                 else
893                 {
894                         for (int i = 0; i < numWeights; i++)
895                                 result.weight.value.plain[i] = (i*weightRangeMax + (numWeights-1)/2) / (numWeights-1);
896                 }
897         }
898
899         {
900                 result.endpoint.isGivenInBlockForm = false;
901
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);
906
907                 for (int i = 0; i < numColorEndpointValues; i++)
908                         result.endpoint.value.plain[i] = (i*colorEndpointRangeMax + (numColorEndpointValues-1)/2) / (numColorEndpointValues-1);
909         }
910
911         return result;
912 }
913
914 } // ASTCBlockGeneratorInternal
915
916 static Vec4 getBlockTestTypeColorScale (ASTCBlockTestType testType)
917 {
918         switch (testType)
919         {
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);
924         }
925 }
926
927 static Vec4 getBlockTestTypeColorBias (ASTCBlockTestType testType)
928 {
929         switch (testType)
930         {
931                 case ASTCBLOCKTESTTYPE_VOID_EXTENT_HDR:         return Vec4(0.5f);
932                 default:                                                                        return Vec4(0.0f);
933         }
934 }
935
936 // Generate block data for a given ASTCBlockTestType and format.
937 static void generateBlockCaseTestData (vector<deUint8>& dst, CompressedTexFormat format, ASTCBlockTestType testType)
938 {
939         using namespace ASTCBlockGeneratorInternal;
940
941         static const ISEParams weightISEParamsCandidates[] =
942         {
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)
955         };
956
957         DE_ASSERT(tcu::isAstcFormat(format));
958         DE_ASSERT(!(tcu::isAstcSRGBFormat(format) && isBlockTestTypeHDROnly(testType)));
959
960         const IVec3 blockSize = getBlockPixelSize(format);
961         DE_ASSERT(blockSize.z() == 1);
962
963         switch (testType)
964         {
965                 case ASTCBLOCKTESTTYPE_VOID_EXTENT_LDR:
966                 // Generate a gradient-like set of LDR void-extent blocks.
967                 {
968                         const int                       numBlocks       = 1<<13;
969                         const deUint32          numValues       = 1<<16;
970                         dst.reserve(numBlocks*ASTC_BLOCK_SIZE_BYTES);
971
972                         for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
973                         {
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;
980
981                                 generateVoidExtentBlock(VoidExtentParams(false, r, g, b, a)).pushBytesToVector(dst);
982                         }
983
984                         break;
985                 }
986
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.
989                 {
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);
994
995                         for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
996                         {
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));
1005
1006                                 generateVoidExtentBlock(VoidExtentParams(true, r, g, b, a)).pushBytesToVector(dst);
1007                         }
1008
1009                         break;
1010                 }
1011
1012                 case ASTCBLOCKTESTTYPE_WEIGHT_GRID:
1013                 // Generate different combinations of plane count, weight ISE params, and grid size.
1014                 {
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++)
1019                         {
1020                                 NormalBlockParams               blockParams;
1021                                 NormalBlockISEInputs    iseInputs;
1022
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;
1030
1031                                 if (isValidBlockParams(blockParams, blockSize.x(), blockSize.y()))
1032                                         generateNormalBlock(blockParams, blockSize.x(), blockSize.y(), generateDefaultISEInputs(blockParams)).pushBytesToVector(dst);
1033                         }
1034
1035                         break;
1036                 }
1037
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
1042                 {
1043                         for (int iseParamsNdx = 0;      iseParamsNdx < DE_LENGTH_OF_ARRAY(weightISEParamsCandidates);   iseParamsNdx++)
1044                         {
1045                                 const ISEParams&        iseParams = weightISEParamsCandidates[iseParamsNdx];
1046                                 NormalBlockParams       blockParams;
1047
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;
1055
1056                                 while (!isValidBlockParams(blockParams, blockSize.x(), blockSize.y()))
1057                                 {
1058                                         blockParams.weightGridWidth--;
1059                                         blockParams.weightGridHeight--;
1060                                 }
1061
1062                                 const int numValuesInISEBlock   = iseParams.mode == ISEMODE_TRIT ? 5 : iseParams.mode == ISEMODE_QUINT ? 3 : 1;
1063                                 const int numWeights                    = computeNumWeights(blockParams);
1064
1065                                 {
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;
1070
1071                                         for (int offset = 0;    offset < numValuesInISEBlock;   offset++)
1072                                         for (int blockNdx = 0;  blockNdx < numBlocks;                   blockNdx++)
1073                                         {
1074                                                 for (int weightNdx = 0; weightNdx < numWeights; weightNdx++)
1075                                                         iseInputs.weight.value.plain[weightNdx] = (blockNdx*numWeights + weightNdx + offset) % numWeightValues;
1076
1077                                                 generateNormalBlock(blockParams, blockSize.x(), blockSize.y(), iseInputs).pushBytesToVector(dst);
1078                                         }
1079                                 }
1080
1081                                 if (iseParams.mode == ISEMODE_TRIT || iseParams.mode == ISEMODE_QUINT)
1082                                 {
1083                                         NormalBlockISEInputs iseInputs = generateDefaultISEInputs(blockParams);
1084                                         iseInputs.weight.isGivenInBlockForm = true;
1085
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);
1089
1090                                         for (int offset = 0;    offset < numValuesInISEBlock;   offset++)
1091                                         for (int blockNdx = 0;  blockNdx < numBlocks;                   blockNdx++)
1092                                         {
1093                                                 for (int iseBlockNdx = 0; iseBlockNdx < numISEBlocksPerBlock; iseBlockNdx++)
1094                                                 {
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;
1098                                                 }
1099
1100                                                 generateNormalBlock(blockParams, blockSize.x(), blockSize.y(), iseInputs).pushBytesToVector(dst);
1101                                         }
1102                                 }
1103                         }
1104
1105                         break;
1106                 }
1107
1108                 case ASTCBLOCKTESTTYPE_CEMS:
1109                 // For each plane count & partition count combination, generate all color endpoint mode combinations.
1110                 {
1111                         for (int isDualPlane = 0;               isDualPlane <= 1;                                                               isDualPlane++)
1112                         for (int numPartitions = 1;             numPartitions <= (isDualPlane != 0 ? 3 : 4);    numPartitions++)
1113                         {
1114                                 // Multi-partition, single-CEM mode.
1115                                 if (numPartitions > 1)
1116                                 {
1117                                         for (deUint32 singleCem = 0; singleCem < 16; singleCem++)
1118                                         {
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;
1128
1129                                                 for (int iseParamsNdx = 0; iseParamsNdx < DE_LENGTH_OF_ARRAY(weightISEParamsCandidates); iseParamsNdx++)
1130                                                 {
1131                                                         blockParams.weightISEParams = weightISEParamsCandidates[iseParamsNdx];
1132                                                         if (isValidBlockParams(blockParams, blockSize.x(), blockSize.y()))
1133                                                         {
1134                                                                 generateNormalBlock(blockParams, blockSize.x(), blockSize.y(), generateDefaultISEInputs(blockParams)).pushBytesToVector(dst);
1135                                                                 break;
1136                                                         }
1137                                                 }
1138                                         }
1139                                 }
1140
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++)
1146                                 {
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;
1159
1160                                         {
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;
1165
1166                                                 if (maxCemClass - minCemClass > 1)
1167                                                         continue;
1168                                         }
1169
1170                                         for (int iseParamsNdx = 0; iseParamsNdx < DE_LENGTH_OF_ARRAY(weightISEParamsCandidates); iseParamsNdx++)
1171                                         {
1172                                                 blockParams.weightISEParams = weightISEParamsCandidates[iseParamsNdx];
1173                                                 if (isValidBlockParams(blockParams, blockSize.x(), blockSize.y()))
1174                                                 {
1175                                                         generateNormalBlock(blockParams, blockSize.x(), blockSize.y(), generateDefaultISEInputs(blockParams)).pushBytesToVector(dst);
1176                                                         break;
1177                                                 }
1178                                         }
1179                                 }
1180                         }
1181
1182                         break;
1183                 }
1184
1185                 case ASTCBLOCKTESTTYPE_PARTITION_SEED:
1186                 // Test all partition seeds ("partition pattern indices").
1187                 {
1188                         for (int                numPartitions = 2;      numPartitions <= 4;             numPartitions++)
1189                         for (deUint32   partitionSeed = 0;      partitionSeed < 1<<10;  partitionSeed++)
1190                         {
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;
1200
1201                                 generateNormalBlock(blockParams, blockSize.x(), blockSize.y(), generateDefaultISEInputs(blockParams)).pushBytesToVector(dst);
1202                         }
1203
1204                         break;
1205                 }
1206
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.
1213                 {
1214                         for (deUint32 cem = 0; cem < 16; cem++)
1215                         {
1216                                 const bool isHDRCem = cem == 2          ||
1217                                                                           cem == 3              ||
1218                                                                           cem == 7              ||
1219                                                                           cem == 11             ||
1220                                                                           cem == 14             ||
1221                                                                           cem == 15;
1222
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))
1226                                         continue;
1227
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;
1235
1236                                 {
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);
1241
1242                                         for (int endpointPartNdx0 = 0;                                          endpointPartNdx0 < numEndpointParts; endpointPartNdx0++)
1243                                         for (int endpointPartNdx1 = endpointPartNdx0+1;         endpointPartNdx1 < numEndpointParts; endpointPartNdx1++)
1244                                         {
1245                                                 NormalBlockISEInputs    iseInputs                       = generateDefaultISEInputs(blockParams);
1246                                                 const int                               numEndpointValues       = de::min(10, endpointISERangeMax+1);
1247
1248                                                 for (int endpointValueNdx0 = 0; endpointValueNdx0 < numEndpointValues; endpointValueNdx0++)
1249                                                 for (int endpointValueNdx1 = 0; endpointValueNdx1 < numEndpointValues; endpointValueNdx1++)
1250                                                 {
1251                                                         const int endpointValue0 = endpointValueNdx0 * endpointISERangeMax / (numEndpointValues-1);
1252                                                         const int endpointValue1 = endpointValueNdx1 * endpointISERangeMax / (numEndpointValues-1);
1253
1254                                                         iseInputs.endpoint.value.plain[endpointPartNdx0] = endpointValue0;
1255                                                         iseInputs.endpoint.value.plain[endpointPartNdx1] = endpointValue1;
1256
1257                                                         generateNormalBlock(blockParams, blockSize.x(), blockSize.y(), iseInputs).pushBytesToVector(dst);
1258                                                 }
1259                                         }
1260                                 }
1261                         }
1262
1263                         break;
1264                 }
1265
1266                 case ASTCBLOCKTESTTYPE_ENDPOINT_ISE:
1267                 // Similar to ASTCBLOCKTESTTYPE_WEIGHT_ISE, see above.
1268                 {
1269                         static const deUint32 endpointRangeMaximums[] = { 5, 9, 11, 19, 23, 39, 47, 79, 95, 159, 191 };
1270
1271                         for (int endpointRangeNdx = 0; endpointRangeNdx < DE_LENGTH_OF_ARRAY(endpointRangeMaximums); endpointRangeNdx++)
1272                         {
1273                                 bool validCaseGenerated = false;
1274
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++)
1280                                 {
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;
1291
1292                                         if (isValidBlockParams(blockParams, blockSize.x(), blockSize.y()))
1293                                         {
1294                                                 const ISEParams endpointISEParams = computeMaximumRangeISEParams(computeNumBitsForColorEndpoints(blockParams),
1295                                                                                                                                                                                  computeNumColorEndpointValues(&blockParams.colorEndpointModes[0], numPartitions, true));
1296
1297                                                 if (computeISERangeMax(endpointISEParams) == endpointRangeMaximums[endpointRangeNdx])
1298                                                 {
1299                                                         validCaseGenerated = true;
1300
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;
1303
1304                                                         {
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;
1309
1310                                                                 for (int offset = 0;    offset < numValuesInISEBlock;   offset++)
1311                                                                 for (int blockNdx = 0;  blockNdx < numBlocks;                   blockNdx++)
1312                                                                 {
1313                                                                         for (int endpointNdx = 0; endpointNdx < numColorEndpoints; endpointNdx++)
1314                                                                                 iseInputs.endpoint.value.plain[endpointNdx] = (blockNdx*numColorEndpoints + endpointNdx + offset) % numColorEndpointValues;
1315
1316                                                                         generateNormalBlock(blockParams, blockSize.x(), blockSize.y(), iseInputs).pushBytesToVector(dst);
1317                                                                 }
1318                                                         }
1319
1320                                                         if (endpointISEParams.mode == ISEMODE_TRIT || endpointISEParams.mode == ISEMODE_QUINT)
1321                                                         {
1322                                                                 NormalBlockISEInputs iseInputs = generateDefaultISEInputs(blockParams);
1323                                                                 iseInputs.endpoint.isGivenInBlockForm = true;
1324
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);
1328
1329                                                                 for (int offset = 0;    offset < numValuesInISEBlock;   offset++)
1330                                                                 for (int blockNdx = 0;  blockNdx < numBlocks;                   blockNdx++)
1331                                                                 {
1332                                                                         for (int iseBlockNdx = 0; iseBlockNdx < numISEBlocksPerBlock; iseBlockNdx++)
1333                                                                         {
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;
1337                                                                         }
1338
1339                                                                         generateNormalBlock(blockParams, blockSize.x(), blockSize.y(), iseInputs).pushBytesToVector(dst);
1340                                                                 }
1341                                                         }
1342                                                 }
1343                                         }
1344                                 }
1345
1346                                 DE_ASSERT(validCaseGenerated);
1347                         }
1348
1349                         break;
1350                 }
1351
1352                 case ASTCBLOCKTESTTYPE_CCS:
1353                 // For all partition counts, test all values of the CCS (color component selector).
1354                 {
1355                         for (int                numPartitions = 1;              numPartitions <= 3;             numPartitions++)
1356                         for (deUint32   ccs = 0;                                ccs < 4;                                ccs++)
1357                         {
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;
1368
1369                                 generateNormalBlock(blockParams, blockSize.x(), blockSize.y(), generateDefaultISEInputs(blockParams)).pushBytesToVector(dst);
1370                         }
1371
1372                         break;
1373                 }
1374
1375                 case ASTCBLOCKTESTTYPE_RANDOM:
1376                 // Generate a number of random (but valid) blocks.
1377                 {
1378                         const int               numBlocks                       = 16384;
1379                         de::Random              rnd                                     (1);
1380                         int                             numBlocksGenerated      = 0;
1381
1382                         dst.reserve(numBlocks*ASTC_BLOCK_SIZE_BYTES);
1383
1384                         for (numBlocksGenerated = 0; numBlocksGenerated < numBlocks; numBlocksGenerated++)
1385                         {
1386                                 if (rnd.getFloat() < 0.1f)
1387                                 {
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);
1395                                 }
1396                                 else
1397                                 {
1398                                         // Not void extent block.
1399
1400                                         // Generate block params.
1401
1402                                         NormalBlockParams blockParams;
1403
1404                                         do
1405                                         {
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);
1414
1415                                                 blockParams.colorEndpointModes[0] = rnd.getInt(0, 15);
1416
1417                                                 {
1418                                                         const int cemDiff = blockParams.isMultiPartSingleCemMode                ? 0
1419                                                                                                 : blockParams.colorEndpointModes[0] == 0        ? 1
1420                                                                                                 : blockParams.colorEndpointModes[0] == 15       ? -1
1421                                                                                                 : rnd.getBool()                                                         ? 1 : -1;
1422
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);
1425                                                 }
1426                                         } while (!isValidBlockParams(blockParams, blockSize.x(), blockSize.y()));
1427
1428                                         // Generate ISE inputs for both weight and endpoint data.
1429
1430                                         NormalBlockISEInputs iseInputs;
1431
1432                                         for (int weightOrEndpoints = 0; weightOrEndpoints <= 1; weightOrEndpoints++)
1433                                         {
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;
1439
1440                                                 iseInput.isGivenInBlockForm = rnd.getBool();
1441
1442                                                 if (iseInput.isGivenInBlockForm)
1443                                                 {
1444                                                         const int numValuesPerISEBlock  = iseParams.mode == ISEMODE_TRIT        ? 5
1445                                                                                                                         : iseParams.mode == ISEMODE_QUINT       ? 3
1446                                                                                                                         :                                                                         1;
1447                                                         const int iseBitMax                             = (1 << iseParams.numBits) - 1;
1448                                                         const int numISEBlocks                  = divRoundUp(numValues, numValuesPerISEBlock);
1449
1450                                                         for (int iseBlockNdx = 0; iseBlockNdx < numISEBlocks; iseBlockNdx++)
1451                                                         {
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);
1455                                                         }
1456                                                 }
1457                                                 else
1458                                                 {
1459                                                         const int rangeMax = computeISERangeMax(iseParams);
1460
1461                                                         for (int valueNdx = 0; valueNdx < numValues; valueNdx++)
1462                                                                 iseInput.value.plain[valueNdx] = rnd.getInt(0, rangeMax);
1463                                                 }
1464                                         }
1465
1466                                         generateNormalBlock(blockParams, blockSize.x(), blockSize.y(), iseInputs).pushBytesToVector(dst);
1467                                 }
1468                         }
1469
1470                         break;
1471                 }
1472
1473                 default:
1474                         DE_ASSERT(false);
1475         }
1476 }
1477
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)
1480 {
1481         string result;
1482         result += "  Hexadecimal (big endian: upper left hex digit is block bits 127 to 124):";
1483
1484         {
1485                 static const char* const hexDigits = "0123456789ABCDEF";
1486
1487                 for (int i = ASTC_BLOCK_SIZE_BYTES-1; i >= 0; i--)
1488                 {
1489                         if ((i+1) % 2 == 0)
1490                                 result += "\n    ";
1491                         else
1492                                 result += "  ";
1493
1494                         result += hexDigits[(data[i] & 0xf0) >> 4];
1495                         result += " ";
1496                         result += hexDigits[(data[i] & 0x0f) >> 0];
1497                 }
1498         }
1499
1500         result += "\n\n  Binary (big endian: upper left bit is block bit 127):";
1501
1502         for (int i = ASTC_BLOCK_SIZE_BYTES-1; i >= 0; i--)
1503         {
1504                 if ((i+1) % 2 == 0)
1505                         result += "\n    ";
1506                 else
1507                         result += "  ";
1508
1509                 for (int j = 8-1; j >= 0; j--)
1510                 {
1511                         if (j == 3)
1512                                 result += " ";
1513
1514                         result += (data[i] >> j) & 1 ? "1" : "0";
1515                 }
1516         }
1517
1518         result += "\n";
1519
1520         return result;
1521 }
1522
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,
1531                                                                 IVec4&                          maxDiffDst)
1532 {
1533         TCU_CHECK_INTERNAL(reference.getWidth() == result.getWidth() && reference.getHeight() == result.getHeight());
1534
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();
1539
1540         DE_ASSERT(width % blockSize.x() == 0 && height % blockSize.y() == 0);
1541
1542         errorMaskDst.setSize(width, height);
1543
1544         firstFailedBlockCoordDst        = IVec2(-1, -1);
1545         maxDiffDst                                      = IVec4(0);
1546
1547         for (int y = 0; y < height; y++)
1548         for (int x = 0; x < width; x++)
1549         {
1550                 const IVec2 blockCoord = IVec2(x, y) / blockSize;
1551
1552                 if (blockCoord.y()*numXBlocks + blockCoord.x() < numNonDummyBlocks)
1553                 {
1554                         const IVec4 refPix = reference.getPixel(x, y).toIVec();
1555
1556                         if (refPix == IVec4(255, 0, 255, 255))
1557                         {
1558                                 // ASTC error color - allow anything in result.
1559                                 errorMaskDst.setPixel(x, y, tcu::RGBA(255, 0, 255, 255));
1560                                 continue;
1561                         }
1562
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));
1566
1567                         maxDiffDst = tcu::max(maxDiffDst, diff);
1568
1569                         errorMaskDst.setPixel(x, y, isOk ? tcu::RGBA::green() : tcu::RGBA::red());
1570
1571                         if (!isOk && firstFailedBlockCoordDst.x() == -1)
1572                                 firstFailedBlockCoordDst = blockCoord;
1573                 }
1574         }
1575
1576         return boolAll(lessThanEqual(maxDiffDst, threshold));
1577 }
1578
1579 enum ASTCSupportLevel
1580 {
1581         // \note Ordered from smallest subset to full, for convenient comparison.
1582         ASTCSUPPORTLEVEL_NONE = 0,
1583         ASTCSUPPORTLEVEL_LDR,
1584         ASTCSUPPORTLEVEL_HDR,
1585         ASTCSUPPORTLEVEL_FULL
1586 };
1587
1588 static inline ASTCSupportLevel getASTCSupportLevel (const glu::ContextInfo& contextInfo)
1589 {
1590         const vector<string>& extensions = contextInfo.getExtensions();
1591
1592         ASTCSupportLevel maxLevel = ASTCSUPPORTLEVEL_NONE;
1593
1594         for (int extNdx = 0; extNdx < (int)extensions.size(); extNdx++)
1595         {
1596                 const string& ext = extensions[extNdx];
1597
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);
1602         }
1603
1604         return maxLevel;
1605 }
1606
1607 // Class handling the common rendering stuff of ASTC cases.
1608 class ASTCRenderer2D
1609 {
1610 public:
1611                                                                 ASTCRenderer2D          (Context&                               context,
1612                                                                                                          CompressedTexFormat    format,
1613                                                                                                          deUint32                               randomSeed);
1614
1615                                                                 ~ASTCRenderer2D         (void);
1616
1617         void                                            initialize                      (int minRenderWidth, int minRenderHeight, const Vec4& colorScale, const Vec4& colorBias);
1618         void                                            clear                           (void);
1619
1620         void                                            render                          (Surface&                                       referenceDst,
1621                                                                                                          Surface&                                       resultDst,
1622                                                                                                          const glu::Texture2D&          texture,
1623                                                                                                          const tcu::TextureFormat&      uncompressedFormat);
1624
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;  }
1628
1629 private:
1630         Context&                                        m_context;
1631         TextureRenderer                         m_renderer;
1632
1633         const CompressedTexFormat       m_format;
1634         const IVec2                                     m_blockSize;
1635         ASTCSupportLevel                        m_astcSupport;
1636         Vec4                                            m_colorScale;
1637         Vec4                                            m_colorBias;
1638
1639         de::Random                                      m_rnd;
1640
1641         bool                                            m_initialized;
1642 };
1643
1644 } // ASTCDecompressionCaseInternal
1645
1646 using namespace ASTCDecompressionCaseInternal;
1647
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)
1653         , m_format                      (format)
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)
1660 {
1661         DE_ASSERT(tcu::getBlockPixelSize(format).z() == 1);
1662 }
1663
1664 ASTCRenderer2D::~ASTCRenderer2D (void)
1665 {
1666         clear();
1667 }
1668
1669 void ASTCRenderer2D::initialize (int minRenderWidth, int minRenderHeight, const Vec4& colorScale, const Vec4& colorBias)
1670 {
1671         DE_ASSERT(!m_initialized);
1672
1673         const tcu::RenderTarget&        renderTarget    = m_context.getRenderTarget();
1674         TestLog&                                        log                             = m_context.getTestContext().getLog();
1675
1676         m_astcSupport   = getASTCSupportLevel(m_context.getContextInfo());
1677         m_colorScale    = colorScale;
1678         m_colorBias             = colorBias;
1679
1680         switch (m_astcSupport)
1681         {
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;
1686                 default:
1687                         DE_ASSERT(false);
1688         }
1689
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));
1692
1693         log << TestLog::Message << "Using color scale and bias: result = raw * " << colorScale << " + " << colorBias << TestLog::EndMessage;
1694
1695         m_initialized = true;
1696 }
1697
1698 void ASTCRenderer2D::clear (void)
1699 {
1700         m_renderer.clear();
1701 }
1702
1703 void ASTCRenderer2D::render (Surface& referenceDst, Surface& resultDst, const glu::Texture2D& texture, const tcu::TextureFormat& uncompressedFormat)
1704 {
1705         DE_ASSERT(m_initialized);
1706
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));
1715
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;
1720
1721         // Setup base viewport.
1722         gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
1723
1724         // Bind to unit 0.
1725         gl.activeTexture(GL_TEXTURE0);
1726         gl.bindTexture(GL_TEXTURE_2D, texture.getGLTexture());
1727
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);
1733
1734         GLU_EXPECT_NO_ERROR(gl.getError(), "Set texturing state");
1735
1736         // Issue GL draws.
1737         m_renderer.renderQuad(0, &texCoord[0], renderParams);
1738         gl.flush();
1739
1740         // Compute reference.
1741         sampleTexture(gls::TextureTestUtil::SurfaceAccess(referenceDst, renderCtx.getRenderTarget().getPixelFormat()), texture.getRefTexture(), &texCoord[0], renderParams);
1742
1743         // Read GL-rendered image.
1744         glu::readPixels(renderCtx, viewport.x, viewport.y, resultDst.getAccess());
1745 }
1746
1747 ASTCBlockCase2D::ASTCBlockCase2D (Context&                                      context,
1748                                                                   const char*                           name,
1749                                                                   const char*                           description,
1750                                                                   ASTCBlockTestType                     testType,
1751                                                                   CompressedTexFormat           format)
1752         : TestCase                              (context, name, description)
1753         , m_testType                    (testType)
1754         , m_format                              (format)
1755         , m_numBlocksTested             (0)
1756         , m_currentIteration    (0)
1757         , m_renderer                    (new ASTCRenderer2D(context, format, deStringHash(getName())))
1758 {
1759         DE_ASSERT(!(tcu::isAstcSRGBFormat(m_format) && isBlockTestTypeHDROnly(m_testType))); // \note There is no HDR sRGB mode, so these would be redundant.
1760 }
1761
1762 ASTCBlockCase2D::~ASTCBlockCase2D (void)
1763 {
1764         ASTCBlockCase2D::deinit();
1765 }
1766
1767 void ASTCBlockCase2D::init (void)
1768 {
1769         m_renderer->initialize(64, 64, getBlockTestTypeColorScale(m_testType), getBlockTestTypeColorBias(m_testType));
1770
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);
1774
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;
1777 }
1778
1779 void ASTCBlockCase2D::deinit (void)
1780 {
1781         m_renderer->clear();
1782         m_blockData.clear();
1783 }
1784
1785 ASTCBlockCase2D::IterateResult ASTCBlockCase2D::iterate (void)
1786 {
1787         TestLog&                                                log                                             = m_testCtx.getLog();
1788
1789         if (m_renderer->getASTCSupport() == ASTCSUPPORTLEVEL_LDR && isBlockTestTypeHDROnly(m_testType))
1790         {
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");
1793                 return STOP;
1794         }
1795
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);
1809
1810         if (m_currentIteration == 0)
1811         {
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;
1817         }
1818
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);
1823
1824         // Create texture and render.
1825
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);
1829
1830         m_renderer->render(referenceFrame, renderedFrame, texture, getUncompressedFormat(compressed.getFormat()));
1831
1832         // Compare and log.
1833         // \note Since a case can draw quite many images, only log the first iteration and failures.
1834
1835         {
1836                 Surface         errorMask;
1837                 IVec2           firstFailedBlockCoord;
1838                 IVec4           maxDiff;
1839                 const bool      compareOk = compareBlockImages(referenceFrame, renderedFrame, threshold, blockSize, curNumNonDummyBlocks, firstFailedBlockCoord, errorMask, maxDiff);
1840
1841                 if (m_currentIteration == 0 || !compareOk)
1842                 {
1843                         const char* const               imageSetName    = "ComparisonResult";
1844                         const char* const               imageSetDesc    = "Comparison Result";
1845
1846                         {
1847                                 tcu::ScopedLogSection section(log, "Iteration " + de::toString(m_currentIteration),
1848                                                                                                         "Blocks " + de::toString(m_numBlocksTested) + " to " + de::toString(m_numBlocksTested + curNumNonDummyBlocks - 1));
1849
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;
1852
1853                                 if (!compareOk)
1854                                 {
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;
1861
1862                                         const int blockNdx = m_numBlocksTested + firstFailedBlockCoord.y()*numXBlocksPerImage + firstFailedBlockCoord.x();
1863                                         DE_ASSERT(blockNdx < totalNumBlocks);
1864
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;
1867
1868                                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
1869                                         return STOP;
1870                                 }
1871                                 else
1872                                 {
1873                                         log << TestLog::ImageSet(imageSetName, imageSetDesc)
1874                                                 << TestLog::Image("Result", "Result", renderedFrame)
1875                                                 << TestLog::EndImageSet;
1876                                 }
1877                         }
1878
1879                         if (m_numBlocksTested + curNumNonDummyBlocks < totalNumBlocks)
1880                                 log << TestLog::Message << "Note: not logging further images unless reference comparison fails" << TestLog::EndMessage;
1881                 }
1882         }
1883
1884         m_currentIteration++;
1885         m_numBlocksTested += curNumNonDummyBlocks;
1886
1887         if (m_numBlocksTested >= totalNumBlocks)
1888         {
1889                 DE_ASSERT(m_numBlocksTested == totalNumBlocks);
1890                 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1891                 return STOP;
1892         }
1893
1894         return CONTINUE;
1895 }
1896
1897 // Generate a number of trivial dummy blocks to fill unneeded space in a texture.
1898 void ASTCBlockCase2D::generateDummyBlocks (deUint8* dst, int num)
1899 {
1900         using namespace ASTCBlockGeneratorInternal;
1901
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]);
1905 }
1906
1907 ASTCBlockSizeRemainderCase2D::ASTCBlockSizeRemainderCase2D (Context&                    context,
1908                                                                                                                         const char*                     name,
1909                                                                                                                         const char*                     description,
1910                                                                                                                         CompressedTexFormat     format)
1911         : TestCase                              (context, name, description)
1912         , m_format                              (format)
1913         , m_currentIteration    (0)
1914         , m_renderer                    (new ASTCRenderer2D(context, format, deStringHash(getName())))
1915 {
1916 }
1917
1918 ASTCBlockSizeRemainderCase2D::~ASTCBlockSizeRemainderCase2D (void)
1919 {
1920         ASTCBlockSizeRemainderCase2D::deinit();
1921 }
1922
1923 void ASTCBlockSizeRemainderCase2D::init (void)
1924 {
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));
1927 }
1928
1929 void ASTCBlockSizeRemainderCase2D::deinit (void)
1930 {
1931         m_renderer->clear();
1932 }
1933
1934 ASTCBlockSizeRemainderCase2D::IterateResult ASTCBlockSizeRemainderCase2D::iterate (void)
1935 {
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);
1948
1949         DE_ASSERT(compressed.getDataSize() == totalNumBlocks*ASTC_BLOCK_SIZE_BYTES);
1950         generateDefaultBlockData((deUint8*)compressed.getData(), totalNumBlocks, blockSize.x(), blockSize.y());
1951
1952         // Create texture and render.
1953
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));
1957
1958         m_renderer->render(referenceFrame, renderedFrame, texture, getUncompressedFormat(compressed.getFormat()));
1959
1960         {
1961                 // Compare and log.
1962
1963                 tcu::ScopedLogSection section(log, "Iteration " + de::toString(m_currentIteration),
1964                                                                                    "Remainder " + de::toString(curRemainderX) + "x" + de::toString(curRemainderY));
1965
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;
1973
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);
1976
1977                 if (!compareOk)
1978                 {
1979                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
1980                         return STOP;
1981                 }
1982         }
1983
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;
1986
1987         m_currentIteration++;
1988
1989         if (m_currentIteration >= blockSize.x()*blockSize.y())
1990         {
1991                 DE_ASSERT(m_currentIteration == blockSize.x()*blockSize.y());
1992                 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1993                 return STOP;
1994         }
1995         return CONTINUE;
1996 }
1997
1998 void ASTCBlockSizeRemainderCase2D::generateDefaultBlockData (deUint8* dst, int numBlocks, int blockWidth, int blockHeight)
1999 {
2000         using namespace ASTCBlockGeneratorInternal;
2001
2002         NormalBlockParams blockParams;
2003
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;
2010
2011         NormalBlockISEInputs iseInputs = generateDefaultISEInputs(blockParams);
2012         iseInputs.weight.isGivenInBlockForm = false;
2013
2014         const int numWeights            = computeNumWeights(blockParams);
2015         const int weightRangeMax        = computeISERangeMax(blockParams.weightISEParams);
2016
2017         for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
2018         {
2019                 for (int weightNdx = 0; weightNdx < numWeights; weightNdx++)
2020                         iseInputs.weight.value.plain[weightNdx] = (blockNdx*numWeights + weightNdx) * weightRangeMax / (numBlocks*numWeights-1);
2021
2022                 generateNormalBlock(blockParams, blockWidth, blockHeight, iseInputs).assignToMemory(dst + blockNdx*ASTC_BLOCK_SIZE_BYTES);
2023         }
2024 }
2025
2026 const char* getBlockTestTypeName (ASTCBlockTestType testType)
2027 {
2028         switch (testType)
2029         {
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";
2042                 default:
2043                         DE_ASSERT(false);
2044                         return DE_NULL;
2045         }
2046 }
2047
2048 const char* getBlockTestTypeDescription (ASTCBlockTestType testType)
2049 {
2050         switch (testType)
2051         {
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";
2064                 default:
2065                         DE_ASSERT(false);
2066                         return DE_NULL;
2067         }
2068 }
2069
2070 bool isBlockTestTypeHDROnly (ASTCBlockTestType testType)
2071 {
2072         return testType == ASTCBLOCKTESTTYPE_VOID_EXTENT_HDR                    ||
2073                    testType == ASTCBLOCKTESTTYPE_ENDPOINT_VALUE_HDR_NO_15       ||
2074                    testType == ASTCBLOCKTESTTYPE_ENDPOINT_VALUE_HDR_15;
2075 }
2076
2077 } // Functional
2078 } // gles3
2079 } // deqp