Home | History | Annotate | Download | only in functional
      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::IVec2;
     64 using tcu::IVec3;
     65 using tcu::IVec4;
     66 using tcu::Vec2;
     67 using tcu::Vec4;
     68 using tcu::Sampler;
     69 using tcu::Surface;
     70 using std::vector;
     71 using std::string;
     72 
     73 namespace deqp
     74 {
     75 
     76 using gls::TextureTestUtil::TextureRenderer;
     77 using gls::TextureTestUtil::RandomViewport;
     78 using gls::TextureTestUtil::ReferenceParams;
     79 
     80 namespace gles3
     81 {
     82 namespace Functional
     83 {
     84 
     85 namespace ASTCDecompressionCaseInternal
     86 {
     87 
     88 static const int ASTC_BLOCK_SIZE_BYTES = 128/8;
     89 
     90 static inline int divRoundUp (int a, int b)
     91 {
     92 	return a/b + ((a%b) ? 1 : 0);
     93 }
     94 
     95 namespace ASTCBlockGeneratorInternal
     96 {
     97 
     98 static inline deUint32 reverseBits (deUint32 src, int numBits)
     99 {
    100 	DE_ASSERT(de::inRange(numBits, 0, 32));
    101 	deUint32 result = 0;
    102 	for (int i = 0; i < numBits; i++)
    103 		result |= ((src >> i) & 1) << (numBits-1-i);
    104 	return result;
    105 }
    106 
    107 static inline deUint32 getBit (deUint32 src, int ndx)
    108 {
    109 	DE_ASSERT(de::inBounds(ndx, 0, 32));
    110 	return (src >> ndx) & 1;
    111 }
    112 
    113 static inline deUint32 getBits (deUint32 src, int low, int high)
    114 {
    115 	const int numBits = (high-low) + 1;
    116 	if (numBits == 0)
    117 		return 0;
    118 	DE_ASSERT(de::inRange(numBits, 1, 32));
    119 	return (src >> low) & ((1u<<numBits)-1);
    120 }
    121 
    122 #if defined(DE_DEBUG)
    123 static inline bool isFloat16InfOrNan (deFloat16 v)
    124 {
    125 	return getBits(v, 10, 14) == 31;
    126 }
    127 #endif
    128 
    129 template <typename T, typename Y>
    130 struct isSameType			{ enum { V = 0 }; };
    131 template <typename T>
    132 struct isSameType<T, T>		{ enum { V = 1 }; };
    133 
    134 // Helper class for setting bits in a 128-bit block.
    135 class AssignBlock128
    136 {
    137 private:
    138 	typedef deUint64 Word;
    139 
    140 	enum
    141 	{
    142 		WORD_BYTES	= sizeof(Word),
    143 		WORD_BITS	= 8*WORD_BYTES,
    144 		NUM_WORDS	= 128 / WORD_BITS
    145 	};
    146 
    147 	DE_STATIC_ASSERT(128 % WORD_BITS == 0);
    148 
    149 public:
    150 	AssignBlock128 (void)
    151 	{
    152 		for (int wordNdx = 0; wordNdx < NUM_WORDS; wordNdx++)
    153 			m_words[wordNdx] = 0;
    154 	}
    155 
    156 	void setBit (int ndx, deUint32 val)
    157 	{
    158 		DE_ASSERT(de::inBounds(ndx, 0, 128));
    159 		DE_ASSERT((val & 1) == val);
    160 		const int wordNdx	= ndx / WORD_BITS;
    161 		const int bitNdx	= ndx % WORD_BITS;
    162 		m_words[wordNdx] = (m_words[wordNdx] & ~((Word)1 << bitNdx)) | ((Word)val << bitNdx);
    163 	}
    164 
    165 	void setBits (int low, int high, deUint32 bits)
    166 	{
    167 		DE_ASSERT(de::inBounds(low, 0, 128));
    168 		DE_ASSERT(de::inBounds(high, 0, 128));
    169 		DE_ASSERT(de::inRange(high-low+1, 0, 32));
    170 		DE_ASSERT((bits & (((Word)1 << (high-low+1)) - 1)) == bits);
    171 
    172 		if (high-low+1 == 0)
    173 			return;
    174 
    175 		const int word0Ndx		= low / WORD_BITS;
    176 		const int word1Ndx		= high / WORD_BITS;
    177 		const int lowNdxInW0	= low % WORD_BITS;
    178 
    179 		if (word0Ndx == word1Ndx)
    180 			m_words[word0Ndx] = (m_words[word0Ndx] & ~((((Word)1 << (high-low+1)) - 1) << lowNdxInW0)) | ((Word)bits << lowNdxInW0);
    181 		else
    182 		{
    183 			DE_ASSERT(word1Ndx == word0Ndx + 1);
    184 
    185 			const int	highNdxInW1			= high % WORD_BITS;
    186 			const int	numBitsToSetInW0	= WORD_BITS - lowNdxInW0;
    187 			const Word	bitsLowMask			= ((Word)1 << numBitsToSetInW0) - 1;
    188 
    189 			m_words[word0Ndx] = (m_words[word0Ndx] & (((Word)1 << lowNdxInW0) - 1))			| (((Word)bits & bitsLowMask) << lowNdxInW0);
    190 			m_words[word1Ndx] = (m_words[word1Ndx] & ~(((Word)1 << (highNdxInW1+1)) - 1))	| (((Word)bits & ~bitsLowMask) >> numBitsToSetInW0);
    191 		}
    192 	}
    193 
    194 	void assignToMemory (deUint8* dst) const
    195 	{
    196 		for (int wordNdx = 0; wordNdx < NUM_WORDS; wordNdx++)
    197 		{
    198 			for (int byteNdx = 0; byteNdx < WORD_BYTES; byteNdx++)
    199 				dst[wordNdx*WORD_BYTES + byteNdx] = (deUint8)((m_words[wordNdx] >> (8*byteNdx)) & 0xff);
    200 		}
    201 	}
    202 
    203 	void pushBytesToVector (vector<deUint8>& dst) const
    204 	{
    205 		const int assignStartIndex = (int)dst.size();
    206 		dst.resize(dst.size() + ASTC_BLOCK_SIZE_BYTES);
    207 		assignToMemory(&dst[assignStartIndex]);
    208 	}
    209 
    210 private:
    211 	Word m_words[NUM_WORDS];
    212 };
    213 
    214 // A helper for sequential access into a AssignBlock128.
    215 class BitAssignAccessStream
    216 {
    217 public:
    218 	BitAssignAccessStream (AssignBlock128& dst, int startNdxInSrc, int length, bool forward)
    219 		: m_dst				(dst)
    220 		, m_startNdxInSrc	(startNdxInSrc)
    221 		, m_length			(length)
    222 		, m_forward			(forward)
    223 		, m_ndx				(0)
    224 	{
    225 	}
    226 
    227 	// Set the next num bits. Bits at positions greater than or equal to m_length are not touched.
    228 	void setNext (int num, deUint32 bits)
    229 	{
    230 		DE_ASSERT((bits & (((deUint64)1 << num) - 1)) == bits);
    231 
    232 		if (num == 0 || m_ndx >= m_length)
    233 			return;
    234 
    235 		const int		end				= m_ndx + num;
    236 		const int		numBitsToDst	= de::max(0, de::min(m_length, end) - m_ndx);
    237 		const int		low				= m_ndx;
    238 		const int		high			= m_ndx + numBitsToDst - 1;
    239 		const deUint32	actualBits		= getBits(bits, 0, numBitsToDst-1);
    240 
    241 		m_ndx += num;
    242 
    243 		return m_forward ? m_dst.setBits(m_startNdxInSrc + low,  m_startNdxInSrc + high, actualBits)
    244 						 : m_dst.setBits(m_startNdxInSrc - high, m_startNdxInSrc - low, reverseBits(actualBits, numBitsToDst));
    245 	}
    246 
    247 private:
    248 	AssignBlock128&		m_dst;
    249 	const int			m_startNdxInSrc;
    250 	const int			m_length;
    251 	const bool			m_forward;
    252 
    253 	int					m_ndx;
    254 };
    255 
    256 struct VoidExtentParams
    257 {
    258 	DE_STATIC_ASSERT((isSameType<deFloat16, deUint16>::V));
    259 	bool		isHDR;
    260 	deUint16	r;
    261 	deUint16	g;
    262 	deUint16	b;
    263 	deUint16	a;
    264 	// \note Currently extent coordinates are all set to all-ones.
    265 
    266 	VoidExtentParams (bool isHDR_, deUint16 r_, deUint16 g_, deUint16 b_, deUint16 a_) : isHDR(isHDR_), r(r_), g(g_), b(b_), a(a_) {}
    267 };
    268 
    269 static AssignBlock128 generateVoidExtentBlock (const VoidExtentParams& params)
    270 {
    271 	AssignBlock128 block;
    272 
    273 	block.setBits(0, 8, 0x1fc); // \note Marks void-extent block.
    274 	block.setBit(9, params.isHDR);
    275 	block.setBits(10, 11, 3); // \note Spec shows that these bits are both set, although they serve no purpose.
    276 
    277 	// Extent coordinates - currently all-ones.
    278 	block.setBits(12, 24, 0x1fff);
    279 	block.setBits(25, 37, 0x1fff);
    280 	block.setBits(38, 50, 0x1fff);
    281 	block.setBits(51, 63, 0x1fff);
    282 
    283 	DE_ASSERT(!params.isHDR || (!isFloat16InfOrNan(params.r) &&
    284 								!isFloat16InfOrNan(params.g) &&
    285 								!isFloat16InfOrNan(params.b) &&
    286 								!isFloat16InfOrNan(params.a)));
    287 
    288 	block.setBits(64,  79,  params.r);
    289 	block.setBits(80,  95,  params.g);
    290 	block.setBits(96,  111, params.b);
    291 	block.setBits(112, 127, params.a);
    292 
    293 	return block;
    294 }
    295 
    296 enum ISEMode
    297 {
    298 	ISEMODE_TRIT = 0,
    299 	ISEMODE_QUINT,
    300 	ISEMODE_PLAIN_BIT,
    301 
    302 	ISEMODE_LAST
    303 };
    304 
    305 struct ISEParams
    306 {
    307 	ISEMode		mode;
    308 	int			numBits;
    309 
    310 	ISEParams (ISEMode mode_, int numBits_) : mode(mode_), numBits(numBits_) {}
    311 };
    312 
    313 // An input array of ISE inputs for an entire ASTC block. Can be given as either single values in the
    314 // range [0, maximumValueOfISERange] or as explicit block value specifications. The latter is needed
    315 // so we can test all possible values of T and Q in a block, since multiple T or Q values may map
    316 // to the same set of decoded values.
    317 struct ISEInput
    318 {
    319 	struct Block
    320 	{
    321 		deUint32 tOrQValue; //!< The 8-bit T or 7-bit Q in a trit or quint ISE block.
    322 		deUint32 bitValues[5];
    323 	};
    324 
    325 	bool isGivenInBlockForm;
    326 	union
    327 	{
    328 		//!< \note 64 comes from the maximum number of weight values in an ASTC block.
    329 		deUint32	plain[64];
    330 		Block		block[64];
    331 	} value;
    332 
    333 	ISEInput (void)
    334 		: isGivenInBlockForm (false)
    335 	{
    336 	}
    337 };
    338 
    339 static inline int computeNumRequiredBits (const ISEParams& iseParams, int numValues)
    340 {
    341 	switch (iseParams.mode)
    342 	{
    343 		case ISEMODE_TRIT:			return divRoundUp(numValues*8, 5) + numValues*iseParams.numBits;
    344 		case ISEMODE_QUINT:			return divRoundUp(numValues*7, 3) + numValues*iseParams.numBits;
    345 		case ISEMODE_PLAIN_BIT:		return numValues*iseParams.numBits;
    346 		default:
    347 			DE_ASSERT(false);
    348 			return -1;
    349 	}
    350 }
    351 
    352 static inline deUint32 computeISERangeMax (const ISEParams& iseParams)
    353 {
    354 	switch (iseParams.mode)
    355 	{
    356 		case ISEMODE_TRIT:			return (1u << iseParams.numBits) * 3 - 1;
    357 		case ISEMODE_QUINT:			return (1u << iseParams.numBits) * 5 - 1;
    358 		case ISEMODE_PLAIN_BIT:		return (1u << iseParams.numBits)     - 1;
    359 		default:
    360 			DE_ASSERT(false);
    361 			return -1;
    362 	}
    363 }
    364 
    365 struct NormalBlockParams
    366 {
    367 	int					weightGridWidth;
    368 	int					weightGridHeight;
    369 	ISEParams			weightISEParams;
    370 	bool				isDualPlane;
    371 	deUint32			ccs; //! \note Irrelevant if !isDualPlane.
    372 	int					numPartitions;
    373 	deUint32			colorEndpointModes[4];
    374 	// \note Below members are irrelevant if numPartitions == 1.
    375 	bool				isMultiPartSingleCemMode; //! \note If true, the single CEM is at colorEndpointModes[0].
    376 	deUint32			partitionSeed;
    377 
    378 	NormalBlockParams (void)
    379 		: weightGridWidth			(-1)
    380 		, weightGridHeight			(-1)
    381 		, weightISEParams			(ISEMODE_LAST, -1)
    382 		, isDualPlane				(true)
    383 		, ccs						((deUint32)-1)
    384 		, numPartitions				(-1)
    385 		, isMultiPartSingleCemMode	(false)
    386 		, partitionSeed				((deUint32)-1)
    387 	{
    388 		colorEndpointModes[0] = 0;
    389 		colorEndpointModes[1] = 0;
    390 		colorEndpointModes[2] = 0;
    391 		colorEndpointModes[3] = 0;
    392 	}
    393 };
    394 
    395 struct NormalBlockISEInputs
    396 {
    397 	ISEInput weight;
    398 	ISEInput endpoint;
    399 
    400 	NormalBlockISEInputs (void)
    401 		: weight	()
    402 		, endpoint	()
    403 	{
    404 	}
    405 };
    406 
    407 static inline int computeNumWeights (const NormalBlockParams& params)
    408 {
    409 	return params.weightGridWidth * params.weightGridHeight * (params.isDualPlane ? 2 : 1);
    410 }
    411 
    412 static inline int computeNumBitsForColorEndpoints (const NormalBlockParams& params)
    413 {
    414 	const int numWeightBits			= computeNumRequiredBits(params.weightISEParams, computeNumWeights(params));
    415 	const int numConfigDataBits		= (params.numPartitions == 1 ? 17 : params.isMultiPartSingleCemMode ? 29 : 25 + 3*params.numPartitions) +
    416 									  (params.isDualPlane ? 2 : 0);
    417 
    418 	return 128 - numWeightBits - numConfigDataBits;
    419 }
    420 
    421 static inline int computeNumColorEndpointValues (deUint32 endpointMode)
    422 {
    423 	DE_ASSERT(endpointMode < 16);
    424 	return (endpointMode/4 + 1) * 2;
    425 }
    426 
    427 static inline int computeNumColorEndpointValues (const deUint32* endpointModes, int numPartitions, bool isMultiPartSingleCemMode)
    428 {
    429 	if (isMultiPartSingleCemMode)
    430 		return numPartitions * computeNumColorEndpointValues(endpointModes[0]);
    431 	else
    432 	{
    433 		int result = 0;
    434 		for (int i = 0; i < numPartitions; i++)
    435 			result += computeNumColorEndpointValues(endpointModes[i]);
    436 		return result;
    437 	}
    438 }
    439 
    440 static inline bool isValidBlockParams (const NormalBlockParams& params, int blockWidth, int blockHeight)
    441 {
    442 	const int numWeights				= computeNumWeights(params);
    443 	const int numWeightBits				= computeNumRequiredBits(params.weightISEParams, numWeights);
    444 	const int numColorEndpointValues	= computeNumColorEndpointValues(&params.colorEndpointModes[0], params.numPartitions, params.isMultiPartSingleCemMode);
    445 	const int numBitsForColorEndpoints	= computeNumBitsForColorEndpoints(params);
    446 
    447 	return numWeights <= 64										&&
    448 		   de::inRange(numWeightBits, 24, 96)					&&
    449 		   params.weightGridWidth <= blockWidth					&&
    450 		   params.weightGridHeight <= blockHeight				&&
    451 		   !(params.numPartitions == 4 && params.isDualPlane)	&&
    452 		   numColorEndpointValues <= 18							&&
    453 		   numBitsForColorEndpoints >= divRoundUp(13*numColorEndpointValues, 5);
    454 }
    455 
    456 // Write bits 0 to 10 of an ASTC block.
    457 static void writeBlockMode (AssignBlock128& dst, const NormalBlockParams& blockParams)
    458 {
    459 	const deUint32	d = blockParams.isDualPlane != 0;
    460 	// r and h initialized in switch below.
    461 	deUint32		r;
    462 	deUint32		h;
    463 	// a, b and blockModeLayoutNdx initialized in block mode layout index detecting loop below.
    464 	deUint32		a = (deUint32)-1;
    465 	deUint32		b = (deUint32)-1;
    466 	int				blockModeLayoutNdx;
    467 
    468 	// Find the values of r and h (ISE range).
    469 	switch (computeISERangeMax(blockParams.weightISEParams))
    470 	{
    471 		case 1:		r = 2; h = 0;	break;
    472 		case 2:		r = 3; h = 0;	break;
    473 		case 3:		r = 4; h = 0;	break;
    474 		case 4:		r = 5; h = 0;	break;
    475 		case 5:		r = 6; h = 0;	break;
    476 		case 7:		r = 7; h = 0;	break;
    477 
    478 		case 9:		r = 2; h = 1;	break;
    479 		case 11:	r = 3; h = 1;	break;
    480 		case 15:	r = 4; h = 1;	break;
    481 		case 19:	r = 5; h = 1;	break;
    482 		case 23:	r = 6; h = 1;	break;
    483 		case 31:	r = 7; h = 1;	break;
    484 
    485 		default:
    486 			DE_ASSERT(false);
    487 			r = (deUint32)-1;
    488 			h = (deUint32)-1;
    489 	}
    490 
    491 	// Find block mode layout index, i.e. appropriate row in the "2d block mode layout" table in ASTC spec.
    492 
    493 	{
    494 		enum BlockModeLayoutABVariable { Z=0, A=1, B=2 };
    495 
    496 		static const struct BlockModeLayout
    497 		{
    498 			int							aNumBits;
    499 			int							bNumBits;
    500 			BlockModeLayoutABVariable	gridWidthVariableTerm;
    501 			int							gridWidthConstantTerm;
    502 			BlockModeLayoutABVariable	gridHeightVariableTerm;
    503 			int							gridHeightConstantTerm;
    504 		} blockModeLayouts[] =
    505 		{
    506 			{ 2, 2,   B,  4,   A,  2},
    507 			{ 2, 2,   B,  8,   A,  2},
    508 			{ 2, 2,   A,  2,   B,  8},
    509 			{ 2, 1,   A,  2,   B,  6},
    510 			{ 2, 1,   B,  2,   A,  2},
    511 			{ 2, 0,   Z, 12,   A,  2},
    512 			{ 2, 0,   A,  2,   Z, 12},
    513 			{ 0, 0,   Z,  6,   Z, 10},
    514 			{ 0, 0,   Z, 10,   Z,  6},
    515 			{ 2, 2,   A,  6,   B,  6}
    516 		};
    517 
    518 		for (blockModeLayoutNdx = 0; blockModeLayoutNdx < DE_LENGTH_OF_ARRAY(blockModeLayouts); blockModeLayoutNdx++)
    519 		{
    520 			const BlockModeLayout&	layout					= blockModeLayouts[blockModeLayoutNdx];
    521 			const int				aMax					= (1 << layout.aNumBits) - 1;
    522 			const int				bMax					= (1 << layout.bNumBits) - 1;
    523 			const int				variableOffsetsMax[3]	= { 0, aMax, bMax };
    524 			const int				widthMin				= layout.gridWidthConstantTerm;
    525 			const int				heightMin				= layout.gridHeightConstantTerm;
    526 			const int				widthMax				= widthMin  + variableOffsetsMax[layout.gridWidthVariableTerm];
    527 			const int				heightMax				= heightMin + variableOffsetsMax[layout.gridHeightVariableTerm];
    528 
    529 			DE_ASSERT(layout.gridWidthVariableTerm != layout.gridHeightVariableTerm || layout.gridWidthVariableTerm == Z);
    530 
    531 			if (de::inRange(blockParams.weightGridWidth, widthMin, widthMax) &&
    532 				de::inRange(blockParams.weightGridHeight, heightMin, heightMax))
    533 			{
    534 				deUint32	dummy			= 0;
    535 				deUint32&	widthVariable	= layout.gridWidthVariableTerm == A  ? a : layout.gridWidthVariableTerm == B  ? b : dummy;
    536 				deUint32&	heightVariable	= layout.gridHeightVariableTerm == A ? a : layout.gridHeightVariableTerm == B ? b : dummy;
    537 
    538 				widthVariable	= blockParams.weightGridWidth  - layout.gridWidthConstantTerm;
    539 				heightVariable	= blockParams.weightGridHeight - layout.gridHeightConstantTerm;
    540 
    541 				break;
    542 			}
    543 		}
    544 	}
    545 
    546 	// Set block mode bits.
    547 
    548 	const deUint32 a0 = getBit(a, 0);
    549 	const deUint32 a1 = getBit(a, 1);
    550 	const deUint32 b0 = getBit(b, 0);
    551 	const deUint32 b1 = getBit(b, 1);
    552 	const deUint32 r0 = getBit(r, 0);
    553 	const deUint32 r1 = getBit(r, 1);
    554 	const deUint32 r2 = getBit(r, 2);
    555 
    556 #define SB(NDX, VAL) dst.setBit((NDX), (VAL))
    557 #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)
    558 
    559 	switch (blockModeLayoutNdx)
    560 	{
    561 		case 0: ASSIGN_BITS(d,  h,  b1, b0, a1, a0, r0, 0,  0,  r2, r1);									break;
    562 		case 1: ASSIGN_BITS(d,  h,  b1, b0, a1, a0, r0, 0,  1,  r2, r1);									break;
    563 		case 2: ASSIGN_BITS(d,  h,  b1, b0, a1, a0, r0, 1,  0,  r2, r1);									break;
    564 		case 3: ASSIGN_BITS(d,  h,   0,  b, a1, a0, r0, 1,  1,  r2, r1);									break;
    565 		case 4: ASSIGN_BITS(d,  h,   1,  b, a1, a0, r0, 1,  1,  r2, r1);									break;
    566 		case 5: ASSIGN_BITS(d,  h,   0,  0, a1, a0, r0, r2, r1,  0,  0);									break;
    567 		case 6: ASSIGN_BITS(d,  h,   0,  1, a1, a0, r0, r2, r1,  0,  0);									break;
    568 		case 7: ASSIGN_BITS(d,  h,   1,  1,  0,  0, r0, r2, r1,  0,  0);									break;
    569 		case 8: ASSIGN_BITS(d,  h,   1,  1,  0,  1, r0, r2, r1,  0,  0);									break;
    570 		case 9: ASSIGN_BITS(b1, b0,  1,  0, a1, a0, r0, r2, r1,  0,  0); DE_ASSERT(d == 0 && h == 0);		break;
    571 		default:
    572 			DE_ASSERT(false);
    573 	}
    574 
    575 #undef ASSIGN_BITS
    576 #undef SB
    577 }
    578 
    579 // Write color endpoint mode data of an ASTC block.
    580 static void writeColorEndpointModes (AssignBlock128& dst, const deUint32* colorEndpointModes, bool isMultiPartSingleCemMode, int numPartitions, int extraCemBitsStart)
    581 {
    582 	if (numPartitions == 1)
    583 		dst.setBits(13, 16, colorEndpointModes[0]);
    584 	else
    585 	{
    586 		if (isMultiPartSingleCemMode)
    587 		{
    588 			dst.setBits(23, 24, 0);
    589 			dst.setBits(25, 28, colorEndpointModes[0]);
    590 		}
    591 		else
    592 		{
    593 			DE_ASSERT(numPartitions > 0);
    594 			const deUint32 minCem				= *std::min_element(&colorEndpointModes[0], &colorEndpointModes[numPartitions]);
    595 			const deUint32 maxCem				= *std::max_element(&colorEndpointModes[0], &colorEndpointModes[numPartitions]);
    596 			const deUint32 minCemClass			= minCem/4;
    597 			const deUint32 maxCemClass			= maxCem/4;
    598 			DE_ASSERT(maxCemClass - minCemClass <= 1);
    599 			DE_UNREF(minCemClass); // \note For non-debug builds.
    600 			const deUint32 highLevelSelector	= de::max(1u, maxCemClass);
    601 
    602 			dst.setBits(23, 24, highLevelSelector);
    603 
    604 			for (int partNdx = 0; partNdx < numPartitions; partNdx++)
    605 			{
    606 				const deUint32 c			= colorEndpointModes[partNdx] / 4 == highLevelSelector ? 1 : 0;
    607 				const deUint32 m			= colorEndpointModes[partNdx] % 4;
    608 				const deUint32 lowMBit0Ndx	= numPartitions + 2*partNdx;
    609 				const deUint32 lowMBit1Ndx	= numPartitions + 2*partNdx + 1;
    610 				dst.setBit(25 + partNdx, c);
    611 				dst.setBit(lowMBit0Ndx < 4 ? 25+lowMBit0Ndx : extraCemBitsStart+lowMBit0Ndx-4, getBit(m, 0));
    612 				dst.setBit(lowMBit1Ndx < 4 ? 25+lowMBit1Ndx : extraCemBitsStart+lowMBit1Ndx-4, getBit(m, 1));
    613 			}
    614 		}
    615 	}
    616 }
    617 
    618 static ISEParams computeMaximumRangeISEParams (int numAvailableBits, int numValuesInSequence)
    619 {
    620 	int curBitsForTritMode		= 6;
    621 	int curBitsForQuintMode		= 5;
    622 	int curBitsForPlainBitMode	= 8;
    623 
    624 	while (true)
    625 	{
    626 		DE_ASSERT(curBitsForTritMode > 0 || curBitsForQuintMode > 0 || curBitsForPlainBitMode > 0);
    627 
    628 		const int tritRange			= curBitsForTritMode > 0		? (3 << curBitsForTritMode) - 1			: -1;
    629 		const int quintRange		= curBitsForQuintMode > 0		? (5 << curBitsForQuintMode) - 1		: -1;
    630 		const int plainBitRange		= curBitsForPlainBitMode > 0	? (1 << curBitsForPlainBitMode) - 1		: -1;
    631 		const int maxRange			= de::max(de::max(tritRange, quintRange), plainBitRange);
    632 
    633 		if (maxRange == tritRange)
    634 		{
    635 			const ISEParams params(ISEMODE_TRIT, curBitsForTritMode);
    636 			if (computeNumRequiredBits(params, numValuesInSequence) <= numAvailableBits)
    637 				return ISEParams(ISEMODE_TRIT, curBitsForTritMode);
    638 			curBitsForTritMode--;
    639 		}
    640 		else if (maxRange == quintRange)
    641 		{
    642 			const ISEParams params(ISEMODE_QUINT, curBitsForQuintMode);
    643 			if (computeNumRequiredBits(params, numValuesInSequence) <= numAvailableBits)
    644 				return ISEParams(ISEMODE_QUINT, curBitsForQuintMode);
    645 			curBitsForQuintMode--;
    646 		}
    647 		else
    648 		{
    649 			const ISEParams params(ISEMODE_PLAIN_BIT, curBitsForPlainBitMode);
    650 			DE_ASSERT(maxRange == plainBitRange);
    651 			if (computeNumRequiredBits(params, numValuesInSequence) <= numAvailableBits)
    652 				return ISEParams(ISEMODE_PLAIN_BIT, curBitsForPlainBitMode);
    653 			curBitsForPlainBitMode--;
    654 		}
    655 	}
    656 }
    657 
    658 static void encodeISETritBlock (BitAssignAccessStream& dst, int numBits, bool fromExplicitInputBlock, const ISEInput::Block& blockInput, const deUint32* nonBlockInput, int numValues)
    659 {
    660 	// tritBlockTValue[t0][t1][t2][t3][t4] is a value of T (not necessarily the only one) that will yield the given trits when decoded.
    661 	static const deUint32 tritBlockTValue[3][3][3][3][3] =
    662 	{
    663 		{
    664 			{{{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}}},
    665 			{{{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}}},
    666 			{{{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}}}
    667 		},
    668 		{
    669 			{{{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}}},
    670 			{{{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}}},
    671 			{{{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}}}
    672 		},
    673 		{
    674 			{{{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}}},
    675 			{{{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}}},
    676 			{{{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}}}
    677 		}
    678 	};
    679 
    680 	DE_ASSERT(de::inRange(numValues, 1, 5));
    681 
    682 	deUint32 tritParts[5];
    683 	deUint32 bitParts[5];
    684 
    685 	for (int i = 0; i < 5; i++)
    686 	{
    687 		if (i < numValues)
    688 		{
    689 			if (fromExplicitInputBlock)
    690 			{
    691 				bitParts[i]		= blockInput.bitValues[i];
    692 				tritParts[i]	= -1; // \note Won't be used, but silences warning.
    693 			}
    694 			else
    695 			{
    696 				bitParts[i]		= getBits(nonBlockInput[i], 0, numBits-1);
    697 				tritParts[i]	= nonBlockInput[i] >> numBits;
    698 			}
    699 		}
    700 		else
    701 		{
    702 			bitParts[i]		= 0;
    703 			tritParts[i]	= 0;
    704 		}
    705 	}
    706 
    707 	const deUint32 T = fromExplicitInputBlock ? blockInput.tOrQValue : tritBlockTValue[tritParts[0]]
    708 																					  [tritParts[1]]
    709 																					  [tritParts[2]]
    710 																					  [tritParts[3]]
    711 																					  [tritParts[4]];
    712 
    713 	dst.setNext(numBits,	bitParts[0]);
    714 	dst.setNext(2,			getBits(T, 0, 1));
    715 	dst.setNext(numBits,	bitParts[1]);
    716 	dst.setNext(2,			getBits(T, 2, 3));
    717 	dst.setNext(numBits,	bitParts[2]);
    718 	dst.setNext(1,			getBit(T, 4));
    719 	dst.setNext(numBits,	bitParts[3]);
    720 	dst.setNext(2,			getBits(T, 5, 6));
    721 	dst.setNext(numBits,	bitParts[4]);
    722 	dst.setNext(1,			getBit(T, 7));
    723 }
    724 
    725 static void encodeISEQuintBlock (BitAssignAccessStream& dst, int numBits, bool fromExplicitInputBlock, const ISEInput::Block& blockInput, const deUint32* nonBlockInput, int numValues)
    726 {
    727 	// quintBlockQValue[q0][q1][q2] is a value of Q (not necessarily the only one) that will yield the given quints when decoded.
    728 	static const deUint32 quintBlockQValue[5][5][5] =
    729 	{
    730 		{{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}},
    731 		{{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}},
    732 		{{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}},
    733 		{{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}},
    734 		{{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}}
    735 	};
    736 
    737 	DE_ASSERT(de::inRange(numValues, 1, 3));
    738 
    739 	deUint32 quintParts[3];
    740 	deUint32 bitParts[3];
    741 
    742 	for (int i = 0; i < 3; i++)
    743 	{
    744 		if (i < numValues)
    745 		{
    746 			if (fromExplicitInputBlock)
    747 			{
    748 				bitParts[i]		= blockInput.bitValues[i];
    749 				quintParts[i]	= -1; // \note Won't be used, but silences warning.
    750 			}
    751 			else
    752 			{
    753 				bitParts[i]		= getBits(nonBlockInput[i], 0, numBits-1);
    754 				quintParts[i]	= nonBlockInput[i] >> numBits;
    755 			}
    756 		}
    757 		else
    758 		{
    759 			bitParts[i]		= 0;
    760 			quintParts[i]	= 0;
    761 		}
    762 	}
    763 
    764 	const deUint32 Q = fromExplicitInputBlock ? blockInput.tOrQValue : quintBlockQValue[quintParts[0]]
    765 																					   [quintParts[1]]
    766 																					   [quintParts[2]];
    767 
    768 	dst.setNext(numBits,	bitParts[0]);
    769 	dst.setNext(3,			getBits(Q, 0, 2));
    770 	dst.setNext(numBits,	bitParts[1]);
    771 	dst.setNext(2,			getBits(Q, 3, 4));
    772 	dst.setNext(numBits,	bitParts[2]);
    773 	dst.setNext(2,			getBits(Q, 5, 6));
    774 }
    775 
    776 static void encodeISEBitBlock (BitAssignAccessStream& dst, int numBits, deUint32 value)
    777 {
    778 	DE_ASSERT(de::inRange(value, 0u, (1u<<numBits)-1));
    779 	dst.setNext(numBits, value);
    780 }
    781 
    782 static void encodeISE (BitAssignAccessStream& dst, const ISEParams& params, const ISEInput& input, int numValues)
    783 {
    784 	if (params.mode == ISEMODE_TRIT)
    785 	{
    786 		const int numBlocks = divRoundUp(numValues, 5);
    787 		for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
    788 		{
    789 			const int numValuesInBlock = blockNdx == numBlocks-1 ? numValues - 5*(numBlocks-1) : 5;
    790 			encodeISETritBlock(dst, params.numBits, input.isGivenInBlockForm,
    791 							   input.isGivenInBlockForm ? input.value.block[blockNdx]	: ISEInput::Block(),
    792 							   input.isGivenInBlockForm ? DE_NULL						: &input.value.plain[5*blockNdx],
    793 							   numValuesInBlock);
    794 		}
    795 	}
    796 	else if (params.mode == ISEMODE_QUINT)
    797 	{
    798 		const int numBlocks = divRoundUp(numValues, 3);
    799 		for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
    800 		{
    801 			const int numValuesInBlock = blockNdx == numBlocks-1 ? numValues - 3*(numBlocks-1) : 3;
    802 			encodeISEQuintBlock(dst, params.numBits, input.isGivenInBlockForm,
    803 								input.isGivenInBlockForm ? input.value.block[blockNdx]	: ISEInput::Block(),
    804 								input.isGivenInBlockForm ? DE_NULL						: &input.value.plain[3*blockNdx],
    805 								numValuesInBlock);
    806 		}
    807 	}
    808 	else
    809 	{
    810 		DE_ASSERT(params.mode == ISEMODE_PLAIN_BIT);
    811 		for (int i = 0; i < numValues; i++)
    812 			encodeISEBitBlock(dst, params.numBits, input.isGivenInBlockForm ? input.value.block[i].bitValues[0] : input.value.plain[i]);
    813 	}
    814 }
    815 
    816 static void writeWeightData (AssignBlock128& dst, const ISEParams& iseParams, const ISEInput& input, int numWeights)
    817 {
    818 	const int				numWeightBits	= computeNumRequiredBits(iseParams, numWeights);
    819 	BitAssignAccessStream	access			(dst, 127, numWeightBits, false);
    820 	encodeISE(access, iseParams, input, numWeights);
    821 }
    822 
    823 static void writeColorEndpointData (AssignBlock128& dst, const ISEParams& iseParams, const ISEInput& input, int numEndpoints, int numBitsForColorEndpoints, int colorEndpointDataStartNdx)
    824 {
    825 	BitAssignAccessStream access(dst, colorEndpointDataStartNdx, numBitsForColorEndpoints, true);
    826 	encodeISE(access, iseParams, input, numEndpoints);
    827 }
    828 
    829 static AssignBlock128 generateNormalBlock (const NormalBlockParams& blockParams, int blockWidth, int blockHeight, const NormalBlockISEInputs& iseInputs)
    830 {
    831 	DE_ASSERT(isValidBlockParams(blockParams, blockWidth, blockHeight));
    832 	DE_UNREF(blockWidth);	// \note For non-debug builds.
    833 	DE_UNREF(blockHeight);	// \note For non-debug builds.
    834 
    835 	AssignBlock128	block;
    836 	const int		numWeights		= computeNumWeights(blockParams);
    837 	const int		numWeightBits	= computeNumRequiredBits(blockParams.weightISEParams, numWeights);
    838 
    839 	writeBlockMode(block, blockParams);
    840 
    841 	block.setBits(11, 12, blockParams.numPartitions - 1);
    842 	if (blockParams.numPartitions > 1)
    843 		block.setBits(13, 22, blockParams.partitionSeed);
    844 
    845 	{
    846 		const int extraCemBitsStart = 127 - numWeightBits - (blockParams.numPartitions == 1 || blockParams.isMultiPartSingleCemMode		? -1
    847 															: blockParams.numPartitions == 4											? 7
    848 															: blockParams.numPartitions == 3											? 4
    849 															: blockParams.numPartitions == 2											? 1
    850 															: 0);
    851 
    852 		writeColorEndpointModes(block, &blockParams.colorEndpointModes[0], blockParams.isMultiPartSingleCemMode, blockParams.numPartitions, extraCemBitsStart);
    853 
    854 		if (blockParams.isDualPlane)
    855 			block.setBits(extraCemBitsStart-2, extraCemBitsStart-1, blockParams.ccs);
    856 	}
    857 
    858 	writeWeightData(block, blockParams.weightISEParams, iseInputs.weight, numWeights);
    859 
    860 	{
    861 		const int			numColorEndpointValues		= computeNumColorEndpointValues(&blockParams.colorEndpointModes[0], blockParams.numPartitions, blockParams.isMultiPartSingleCemMode);
    862 		const int			numBitsForColorEndpoints	= computeNumBitsForColorEndpoints(blockParams);
    863 		const int			colorEndpointDataStartNdx	= blockParams.numPartitions == 1 ? 17 : 29;
    864 		const ISEParams&	colorEndpointISEParams		= computeMaximumRangeISEParams(numBitsForColorEndpoints, numColorEndpointValues);
    865 
    866 		writeColorEndpointData(block, colorEndpointISEParams, iseInputs.endpoint, numColorEndpointValues, numBitsForColorEndpoints, colorEndpointDataStartNdx);
    867 	}
    868 
    869 	return block;
    870 }
    871 
    872 // Generate default ISE inputs for weight and endpoint data - gradient-ish values.
    873 static NormalBlockISEInputs generateDefaultISEInputs (const NormalBlockParams& blockParams)
    874 {
    875 	NormalBlockISEInputs result;
    876 
    877 	{
    878 		result.weight.isGivenInBlockForm = false;
    879 
    880 		const int numWeights		= computeNumWeights(blockParams);
    881 		const int weightRangeMax	= computeISERangeMax(blockParams.weightISEParams);
    882 
    883 		if (blockParams.isDualPlane)
    884 		{
    885 			for (int i = 0; i < numWeights; i += 2)
    886 				result.weight.value.plain[i] = (i*weightRangeMax + (numWeights-1)/2) / (numWeights-1);
    887 
    888 			for (int i = 1; i < numWeights; i += 2)
    889 				result.weight.value.plain[i] = weightRangeMax - (i*weightRangeMax + (numWeights-1)/2) / (numWeights-1);
    890 		}
    891 		else
    892 		{
    893 			for (int i = 0; i < numWeights; i++)
    894 				result.weight.value.plain[i] = (i*weightRangeMax + (numWeights-1)/2) / (numWeights-1);
    895 		}
    896 	}
    897 
    898 	{
    899 		result.endpoint.isGivenInBlockForm = false;
    900 
    901 		const int			numColorEndpointValues		= computeNumColorEndpointValues(&blockParams.colorEndpointModes[0], blockParams.numPartitions, blockParams.isMultiPartSingleCemMode);
    902 		const int			numBitsForColorEndpoints	= computeNumBitsForColorEndpoints(blockParams);
    903 		const ISEParams&	colorEndpointISEParams		= computeMaximumRangeISEParams(numBitsForColorEndpoints, numColorEndpointValues);
    904 		const int			colorEndpointRangeMax		= computeISERangeMax(colorEndpointISEParams);
    905 
    906 		for (int i = 0; i < numColorEndpointValues; i++)
    907 			result.endpoint.value.plain[i] = (i*colorEndpointRangeMax + (numColorEndpointValues-1)/2) / (numColorEndpointValues-1);
    908 	}
    909 
    910 	return result;
    911 }
    912 
    913 } // ASTCBlockGeneratorInternal
    914 
    915 static Vec4 getBlockTestTypeColorScale (ASTCBlockTestType testType)
    916 {
    917 	switch (testType)
    918 	{
    919 		case ASTCBLOCKTESTTYPE_VOID_EXTENT_HDR:				return Vec4(0.5f/65504.0f);
    920 		case ASTCBLOCKTESTTYPE_ENDPOINT_VALUE_HDR_NO_15:	return Vec4(1.0f/65504.0f, 1.0f/65504.0f, 1.0f/65504.0f, 1.0f);
    921 		case ASTCBLOCKTESTTYPE_ENDPOINT_VALUE_HDR_15:		return Vec4(1.0f/65504.0f);
    922 		default:											return Vec4(1.0f);
    923 	}
    924 }
    925 
    926 static Vec4 getBlockTestTypeColorBias (ASTCBlockTestType testType)
    927 {
    928 	switch (testType)
    929 	{
    930 		case ASTCBLOCKTESTTYPE_VOID_EXTENT_HDR:		return Vec4(0.5f);
    931 		default:									return Vec4(0.0f);
    932 	}
    933 }
    934 
    935 // Generate block data for a given ASTCBlockTestType and format.
    936 static void generateBlockCaseTestData (vector<deUint8>& dst, CompressedTexture::Format format, ASTCBlockTestType testType)
    937 {
    938 	using namespace ASTCBlockGeneratorInternal;
    939 
    940 	static const ISEParams weightISEParamsCandidates[] =
    941 	{
    942 		ISEParams(ISEMODE_PLAIN_BIT,	1),
    943 		ISEParams(ISEMODE_TRIT,			0),
    944 		ISEParams(ISEMODE_PLAIN_BIT,	2),
    945 		ISEParams(ISEMODE_QUINT,		0),
    946 		ISEParams(ISEMODE_TRIT,			1),
    947 		ISEParams(ISEMODE_PLAIN_BIT,	3),
    948 		ISEParams(ISEMODE_QUINT,		1),
    949 		ISEParams(ISEMODE_TRIT,			2),
    950 		ISEParams(ISEMODE_PLAIN_BIT,	4),
    951 		ISEParams(ISEMODE_QUINT,		2),
    952 		ISEParams(ISEMODE_TRIT,			3),
    953 		ISEParams(ISEMODE_PLAIN_BIT,	5)
    954 	};
    955 
    956 	DE_ASSERT(tcu::isASTCFormat(format));
    957 	DE_ASSERT(!(tcu::isASTCSRGBFormat(format) && isBlockTestTypeHDROnly(testType)));
    958 
    959 	const IVec3 blockSize = getASTCBlockSize(format);
    960 	DE_ASSERT(blockSize.z() == 1);
    961 
    962 	switch (testType)
    963 	{
    964 		case ASTCBLOCKTESTTYPE_VOID_EXTENT_LDR:
    965 		// Generate a gradient-like set of LDR void-extent blocks.
    966 		{
    967 			const int			numBlocks	= 1<<13;
    968 			const deUint32		numValues	= 1<<16;
    969 			dst.reserve(numBlocks*ASTC_BLOCK_SIZE_BYTES);
    970 
    971 			for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
    972 			{
    973 				const deUint32 baseValue	= blockNdx*(numValues-1) / (numBlocks-1);
    974 				const deUint16 r			= (deUint16)((baseValue + numValues*0/4) % numValues);
    975 				const deUint16 g			= (deUint16)((baseValue + numValues*1/4) % numValues);
    976 				const deUint16 b			= (deUint16)((baseValue + numValues*2/4) % numValues);
    977 				const deUint16 a			= (deUint16)((baseValue + numValues*3/4) % numValues);
    978 				AssignBlock128 block;
    979 
    980 				generateVoidExtentBlock(VoidExtentParams(false, r, g, b, a)).pushBytesToVector(dst);
    981 			}
    982 
    983 			break;
    984 		}
    985 
    986 		case ASTCBLOCKTESTTYPE_VOID_EXTENT_HDR:
    987 		// Generate a gradient-like set of HDR void-extent blocks, with values ranging from the largest finite negative to largest finite positive of fp16.
    988 		{
    989 			const float		minValue	= -65504.0f;
    990 			const float		maxValue	= +65504.0f;
    991 			const int		numBlocks	= 1<<13;
    992 			dst.reserve(numBlocks*ASTC_BLOCK_SIZE_BYTES);
    993 
    994 			for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
    995 			{
    996 				const int			rNdx	= (blockNdx + numBlocks*0/4) % numBlocks;
    997 				const int			gNdx	= (blockNdx + numBlocks*1/4) % numBlocks;
    998 				const int			bNdx	= (blockNdx + numBlocks*2/4) % numBlocks;
    999 				const int			aNdx	= (blockNdx + numBlocks*3/4) % numBlocks;
   1000 				const deFloat16		r		= deFloat32To16(minValue + (float)rNdx * (maxValue - minValue) / (float)(numBlocks-1));
   1001 				const deFloat16		g		= deFloat32To16(minValue + (float)gNdx * (maxValue - minValue) / (float)(numBlocks-1));
   1002 				const deFloat16		b		= deFloat32To16(minValue + (float)bNdx * (maxValue - minValue) / (float)(numBlocks-1));
   1003 				const deFloat16		a		= deFloat32To16(minValue + (float)aNdx * (maxValue - minValue) / (float)(numBlocks-1));
   1004 
   1005 				generateVoidExtentBlock(VoidExtentParams(true, r, g, b, a)).pushBytesToVector(dst);
   1006 			}
   1007 
   1008 			break;
   1009 		}
   1010 
   1011 		case ASTCBLOCKTESTTYPE_WEIGHT_GRID:
   1012 		// Generate different combinations of plane count, weight ISE params, and grid size.
   1013 		{
   1014 			for (int isDualPlane = 0;		isDualPlane <= 1;												isDualPlane++)
   1015 			for (int iseParamsNdx = 0;		iseParamsNdx < DE_LENGTH_OF_ARRAY(weightISEParamsCandidates);	iseParamsNdx++)
   1016 			for (int weightGridWidth = 2;	weightGridWidth <= 12;											weightGridWidth++)
   1017 			for (int weightGridHeight = 2;	weightGridHeight <= 12;											weightGridHeight++)
   1018 			{
   1019 				NormalBlockParams		blockParams;
   1020 				NormalBlockISEInputs	iseInputs;
   1021 
   1022 				blockParams.weightGridWidth			= weightGridWidth;
   1023 				blockParams.weightGridHeight		= weightGridHeight;
   1024 				blockParams.isDualPlane				= isDualPlane != 0;
   1025 				blockParams.weightISEParams			= weightISEParamsCandidates[iseParamsNdx];
   1026 				blockParams.ccs						= 0;
   1027 				blockParams.numPartitions			= 1;
   1028 				blockParams.colorEndpointModes[0]	= 0;
   1029 
   1030 				if (isValidBlockParams(blockParams, blockSize.x(), blockSize.y()))
   1031 					generateNormalBlock(blockParams, blockSize.x(), blockSize.y(), generateDefaultISEInputs(blockParams)).pushBytesToVector(dst);
   1032 			}
   1033 
   1034 			break;
   1035 		}
   1036 
   1037 		case ASTCBLOCKTESTTYPE_WEIGHT_ISE:
   1038 		// For each weight ISE param set, generate blocks that cover:
   1039 		// - each single value of the ISE's range, at each position inside an ISE block
   1040 		// - for trit and quint ISEs, each single T or Q value of an ISE block
   1041 		{
   1042 			for (int iseParamsNdx = 0;	iseParamsNdx < DE_LENGTH_OF_ARRAY(weightISEParamsCandidates);	iseParamsNdx++)
   1043 			{
   1044 				const ISEParams&	iseParams = weightISEParamsCandidates[iseParamsNdx];
   1045 				NormalBlockParams	blockParams;
   1046 
   1047 				blockParams.weightGridWidth			= 4;
   1048 				blockParams.weightGridHeight		= 4;
   1049 				blockParams.weightISEParams			= iseParams;
   1050 				blockParams.numPartitions			= 1;
   1051 				blockParams.isDualPlane				= blockParams.weightGridWidth * blockParams.weightGridHeight < 24 ? true : false;
   1052 				blockParams.ccs						= 0;
   1053 				blockParams.colorEndpointModes[0]	= 0;
   1054 
   1055 				while (!isValidBlockParams(blockParams, blockSize.x(), blockSize.y()))
   1056 				{
   1057 					blockParams.weightGridWidth--;
   1058 					blockParams.weightGridHeight--;
   1059 				}
   1060 
   1061 				const int numValuesInISEBlock	= iseParams.mode == ISEMODE_TRIT ? 5 : iseParams.mode == ISEMODE_QUINT ? 3 : 1;
   1062 				const int numWeights			= computeNumWeights(blockParams);
   1063 
   1064 				{
   1065 					const int				numWeightValues		= (int)computeISERangeMax(iseParams) + 1;
   1066 					const int				numBlocks			= divRoundUp(numWeightValues, numWeights);
   1067 					NormalBlockISEInputs	iseInputs			= generateDefaultISEInputs(blockParams);
   1068 					iseInputs.weight.isGivenInBlockForm = false;
   1069 
   1070 					for (int offset = 0;	offset < numValuesInISEBlock;	offset++)
   1071 					for (int blockNdx = 0;	blockNdx < numBlocks;			blockNdx++)
   1072 					{
   1073 						for (int weightNdx = 0; weightNdx < numWeights; weightNdx++)
   1074 							iseInputs.weight.value.plain[weightNdx] = (blockNdx*numWeights + weightNdx + offset) % numWeightValues;
   1075 
   1076 						generateNormalBlock(blockParams, blockSize.x(), blockSize.y(), iseInputs).pushBytesToVector(dst);
   1077 					}
   1078 				}
   1079 
   1080 				if (iseParams.mode == ISEMODE_TRIT || iseParams.mode == ISEMODE_QUINT)
   1081 				{
   1082 					NormalBlockISEInputs iseInputs = generateDefaultISEInputs(blockParams);
   1083 					iseInputs.weight.isGivenInBlockForm = true;
   1084 
   1085 					const int numTQValues			= 1 << (iseParams.mode == ISEMODE_TRIT ? 8 : 7);
   1086 					const int numISEBlocksPerBlock	= divRoundUp(numWeights, numValuesInISEBlock);
   1087 					const int numBlocks				= divRoundUp(numTQValues, numISEBlocksPerBlock);
   1088 
   1089 					for (int offset = 0;	offset < numValuesInISEBlock;	offset++)
   1090 					for (int blockNdx = 0;	blockNdx < numBlocks;			blockNdx++)
   1091 					{
   1092 						for (int iseBlockNdx = 0; iseBlockNdx < numISEBlocksPerBlock; iseBlockNdx++)
   1093 						{
   1094 							for (int i = 0; i < numValuesInISEBlock; i++)
   1095 								iseInputs.weight.value.block[iseBlockNdx].bitValues[i] = 0;
   1096 							iseInputs.weight.value.block[iseBlockNdx].tOrQValue = (blockNdx*numISEBlocksPerBlock + iseBlockNdx + offset) % numTQValues;
   1097 						}
   1098 
   1099 						generateNormalBlock(blockParams, blockSize.x(), blockSize.y(), iseInputs).pushBytesToVector(dst);
   1100 					}
   1101 				}
   1102 			}
   1103 
   1104 			break;
   1105 		}
   1106 
   1107 		case ASTCBLOCKTESTTYPE_CEMS:
   1108 		// For each plane count & partition count combination, generate all color endpoint mode combinations.
   1109 		{
   1110 			for (int isDualPlane = 0;		isDualPlane <= 1;								isDualPlane++)
   1111 			for (int numPartitions = 1;		numPartitions <= (isDualPlane != 0 ? 3 : 4);	numPartitions++)
   1112 			{
   1113 				// Multi-partition, single-CEM mode.
   1114 				if (numPartitions > 1)
   1115 				{
   1116 					for (deUint32 singleCem = 0; singleCem < 16; singleCem++)
   1117 					{
   1118 						NormalBlockParams blockParams;
   1119 						blockParams.weightGridWidth				= 4;
   1120 						blockParams.weightGridHeight			= 4;
   1121 						blockParams.isDualPlane					= isDualPlane != 0;
   1122 						blockParams.ccs							= 0;
   1123 						blockParams.numPartitions				= numPartitions;
   1124 						blockParams.isMultiPartSingleCemMode	= true;
   1125 						blockParams.colorEndpointModes[0]		= singleCem;
   1126 						blockParams.partitionSeed				= 634;
   1127 
   1128 						for (int iseParamsNdx = 0; iseParamsNdx < DE_LENGTH_OF_ARRAY(weightISEParamsCandidates); iseParamsNdx++)
   1129 						{
   1130 							blockParams.weightISEParams = weightISEParamsCandidates[iseParamsNdx];
   1131 							if (isValidBlockParams(blockParams, blockSize.x(), blockSize.y()))
   1132 							{
   1133 								generateNormalBlock(blockParams, blockSize.x(), blockSize.y(), generateDefaultISEInputs(blockParams)).pushBytesToVector(dst);
   1134 								break;
   1135 							}
   1136 						}
   1137 					}
   1138 				}
   1139 
   1140 				// Separate-CEM mode.
   1141 				for (deUint32 cem0 = 0; cem0 < 16; cem0++)
   1142 				for (deUint32 cem1 = 0; cem1 < (numPartitions >= 2 ? 16u : 1u); cem1++)
   1143 				for (deUint32 cem2 = 0; cem2 < (numPartitions >= 3 ? 16u : 1u); cem2++)
   1144 				for (deUint32 cem3 = 0; cem3 < (numPartitions >= 4 ? 16u : 1u); cem3++)
   1145 				{
   1146 					NormalBlockParams blockParams;
   1147 					blockParams.weightGridWidth				= 4;
   1148 					blockParams.weightGridHeight			= 4;
   1149 					blockParams.isDualPlane					= isDualPlane != 0;
   1150 					blockParams.ccs							= 0;
   1151 					blockParams.numPartitions				= numPartitions;
   1152 					blockParams.isMultiPartSingleCemMode	= false;
   1153 					blockParams.colorEndpointModes[0]		= cem0;
   1154 					blockParams.colorEndpointModes[1]		= cem1;
   1155 					blockParams.colorEndpointModes[2]		= cem2;
   1156 					blockParams.colorEndpointModes[3]		= cem3;
   1157 					blockParams.partitionSeed				= 634;
   1158 
   1159 					{
   1160 						const deUint32 minCem		= *std::min_element(&blockParams.colorEndpointModes[0], &blockParams.colorEndpointModes[numPartitions]);
   1161 						const deUint32 maxCem		= *std::max_element(&blockParams.colorEndpointModes[0], &blockParams.colorEndpointModes[numPartitions]);
   1162 						const deUint32 minCemClass	= minCem/4;
   1163 						const deUint32 maxCemClass	= maxCem/4;
   1164 
   1165 						if (maxCemClass - minCemClass > 1)
   1166 							continue;
   1167 					}
   1168 
   1169 					for (int iseParamsNdx = 0; iseParamsNdx < DE_LENGTH_OF_ARRAY(weightISEParamsCandidates); iseParamsNdx++)
   1170 					{
   1171 						blockParams.weightISEParams = weightISEParamsCandidates[iseParamsNdx];
   1172 						if (isValidBlockParams(blockParams, blockSize.x(), blockSize.y()))
   1173 						{
   1174 							generateNormalBlock(blockParams, blockSize.x(), blockSize.y(), generateDefaultISEInputs(blockParams)).pushBytesToVector(dst);
   1175 							break;
   1176 						}
   1177 					}
   1178 				}
   1179 			}
   1180 
   1181 			break;
   1182 		}
   1183 
   1184 		case ASTCBLOCKTESTTYPE_PARTITION_SEED:
   1185 		// Test all partition seeds ("partition pattern indices").
   1186 		{
   1187 			for (int		numPartitions = 2;	numPartitions <= 4;		numPartitions++)
   1188 			for (deUint32	partitionSeed = 0;	partitionSeed < 1<<10;	partitionSeed++)
   1189 			{
   1190 				NormalBlockParams blockParams;
   1191 				blockParams.weightGridWidth				= 4;
   1192 				blockParams.weightGridHeight			= 4;
   1193 				blockParams.weightISEParams				= ISEParams(ISEMODE_PLAIN_BIT, 2);
   1194 				blockParams.isDualPlane					= false;
   1195 				blockParams.numPartitions				= numPartitions;
   1196 				blockParams.isMultiPartSingleCemMode	= true;
   1197 				blockParams.colorEndpointModes[0]		= 0;
   1198 				blockParams.partitionSeed				= partitionSeed;
   1199 
   1200 				generateNormalBlock(blockParams, blockSize.x(), blockSize.y(), generateDefaultISEInputs(blockParams)).pushBytesToVector(dst);
   1201 			}
   1202 
   1203 			break;
   1204 		}
   1205 
   1206 		// \note Fall-through.
   1207 		case ASTCBLOCKTESTTYPE_ENDPOINT_VALUE_LDR:
   1208 		case ASTCBLOCKTESTTYPE_ENDPOINT_VALUE_HDR_NO_15:
   1209 		case ASTCBLOCKTESTTYPE_ENDPOINT_VALUE_HDR_15:
   1210 		// For each endpoint mode, for each pair of components in the endpoint value, test 10x10 combinations of values for that pair.
   1211 		// \note Separate modes for HDR and mode 15 due to different color scales and biases.
   1212 		{
   1213 			for (deUint32 cem = 0; cem < 16; cem++)
   1214 			{
   1215 				const bool isHDRCem = cem == 2		||
   1216 									  cem == 3		||
   1217 									  cem == 7		||
   1218 									  cem == 11		||
   1219 									  cem == 14		||
   1220 									  cem == 15;
   1221 
   1222 				if ((testType == ASTCBLOCKTESTTYPE_ENDPOINT_VALUE_LDR			&& isHDRCem)					||
   1223 					(testType == ASTCBLOCKTESTTYPE_ENDPOINT_VALUE_HDR_NO_15		&& (!isHDRCem || cem == 15))	||
   1224 					(testType == ASTCBLOCKTESTTYPE_ENDPOINT_VALUE_HDR_15		&& cem != 15))
   1225 					continue;
   1226 
   1227 				NormalBlockParams blockParams;
   1228 				blockParams.weightGridWidth			= 3;
   1229 				blockParams.weightGridHeight		= 4;
   1230 				blockParams.weightISEParams			= ISEParams(ISEMODE_PLAIN_BIT, 2);
   1231 				blockParams.isDualPlane				= false;
   1232 				blockParams.numPartitions			= 1;
   1233 				blockParams.colorEndpointModes[0]	= cem;
   1234 
   1235 				{
   1236 					const int			numBitsForEndpoints		= computeNumBitsForColorEndpoints(blockParams);
   1237 					const int			numEndpointParts		= computeNumColorEndpointValues(cem);
   1238 					const ISEParams		endpointISE				= computeMaximumRangeISEParams(numBitsForEndpoints, numEndpointParts);
   1239 					const int			endpointISERangeMax		= computeISERangeMax(endpointISE);
   1240 
   1241 					for (int endpointPartNdx0 = 0;						endpointPartNdx0 < numEndpointParts; endpointPartNdx0++)
   1242 					for (int endpointPartNdx1 = endpointPartNdx0+1;		endpointPartNdx1 < numEndpointParts; endpointPartNdx1++)
   1243 					{
   1244 						NormalBlockISEInputs	iseInputs			= generateDefaultISEInputs(blockParams);
   1245 						const int				numEndpointValues	= de::min(10, endpointISERangeMax+1);
   1246 
   1247 						for (int endpointValueNdx0 = 0; endpointValueNdx0 < numEndpointValues; endpointValueNdx0++)
   1248 						for (int endpointValueNdx1 = 0; endpointValueNdx1 < numEndpointValues; endpointValueNdx1++)
   1249 						{
   1250 							const int endpointValue0 = endpointValueNdx0 * endpointISERangeMax / (numEndpointValues-1);
   1251 							const int endpointValue1 = endpointValueNdx1 * endpointISERangeMax / (numEndpointValues-1);
   1252 
   1253 							iseInputs.endpoint.value.plain[endpointPartNdx0] = endpointValue0;
   1254 							iseInputs.endpoint.value.plain[endpointPartNdx1] = endpointValue1;
   1255 
   1256 							generateNormalBlock(blockParams, blockSize.x(), blockSize.y(), iseInputs).pushBytesToVector(dst);
   1257 						}
   1258 					}
   1259 				}
   1260 			}
   1261 
   1262 			break;
   1263 		}
   1264 
   1265 		case ASTCBLOCKTESTTYPE_ENDPOINT_ISE:
   1266 		// Similar to ASTCBLOCKTESTTYPE_WEIGHT_ISE, see above.
   1267 		{
   1268 			static const deUint32 endpointRangeMaximums[] = { 5, 9, 11, 19, 23, 39, 47, 79, 95, 159, 191 };
   1269 
   1270 			for (int endpointRangeNdx = 0; endpointRangeNdx < DE_LENGTH_OF_ARRAY(endpointRangeMaximums); endpointRangeNdx++)
   1271 			{
   1272 				bool validCaseGenerated = false;
   1273 
   1274 				for (int numPartitions = 1;			!validCaseGenerated && numPartitions <= 4;													numPartitions++)
   1275 				for (int isDual = 0;				!validCaseGenerated && isDual <= 1;															isDual++)
   1276 				for (int weightISEParamsNdx = 0;	!validCaseGenerated && weightISEParamsNdx < DE_LENGTH_OF_ARRAY(weightISEParamsCandidates);	weightISEParamsNdx++)
   1277 				for (int weightGridWidth = 2;		!validCaseGenerated && weightGridWidth <= 12;												weightGridWidth++)
   1278 				for (int weightGridHeight = 2;		!validCaseGenerated && weightGridHeight <= 12;												weightGridHeight++)
   1279 				{
   1280 					NormalBlockParams blockParams;
   1281 					blockParams.weightGridWidth				= weightGridWidth;
   1282 					blockParams.weightGridHeight			= weightGridHeight;
   1283 					blockParams.weightISEParams				= weightISEParamsCandidates[weightISEParamsNdx];
   1284 					blockParams.isDualPlane					= isDual != 0;
   1285 					blockParams.ccs							= 0;
   1286 					blockParams.numPartitions				= numPartitions;
   1287 					blockParams.isMultiPartSingleCemMode	= true;
   1288 					blockParams.colorEndpointModes[0]		= 12;
   1289 					blockParams.partitionSeed				= 634;
   1290 
   1291 					if (isValidBlockParams(blockParams, blockSize.x(), blockSize.y()))
   1292 					{
   1293 						const ISEParams endpointISEParams = computeMaximumRangeISEParams(computeNumBitsForColorEndpoints(blockParams),
   1294 																						 computeNumColorEndpointValues(&blockParams.colorEndpointModes[0], numPartitions, true));
   1295 
   1296 						if (computeISERangeMax(endpointISEParams) == endpointRangeMaximums[endpointRangeNdx])
   1297 						{
   1298 							validCaseGenerated = true;
   1299 
   1300 							const int numColorEndpoints		= computeNumColorEndpointValues(&blockParams.colorEndpointModes[0], numPartitions, blockParams.isMultiPartSingleCemMode);
   1301 							const int numValuesInISEBlock	= endpointISEParams.mode == ISEMODE_TRIT ? 5 : endpointISEParams.mode == ISEMODE_QUINT ? 3 : 1;
   1302 
   1303 							{
   1304 								const int				numColorEndpointValues	= (int)computeISERangeMax(endpointISEParams) + 1;
   1305 								const int				numBlocks				= divRoundUp(numColorEndpointValues, numColorEndpoints);
   1306 								NormalBlockISEInputs	iseInputs				= generateDefaultISEInputs(blockParams);
   1307 								iseInputs.endpoint.isGivenInBlockForm = false;
   1308 
   1309 								for (int offset = 0;	offset < numValuesInISEBlock;	offset++)
   1310 								for (int blockNdx = 0;	blockNdx < numBlocks;			blockNdx++)
   1311 								{
   1312 									for (int endpointNdx = 0; endpointNdx < numColorEndpoints; endpointNdx++)
   1313 										iseInputs.endpoint.value.plain[endpointNdx] = (blockNdx*numColorEndpoints + endpointNdx + offset) % numColorEndpointValues;
   1314 
   1315 									generateNormalBlock(blockParams, blockSize.x(), blockSize.y(), iseInputs).pushBytesToVector(dst);
   1316 								}
   1317 							}
   1318 
   1319 							if (endpointISEParams.mode == ISEMODE_TRIT || endpointISEParams.mode == ISEMODE_QUINT)
   1320 							{
   1321 								NormalBlockISEInputs iseInputs = generateDefaultISEInputs(blockParams);
   1322 								iseInputs.endpoint.isGivenInBlockForm = true;
   1323 
   1324 								const int numTQValues			= 1 << (endpointISEParams.mode == ISEMODE_TRIT ? 8 : 7);
   1325 								const int numISEBlocksPerBlock	= divRoundUp(numColorEndpoints, numValuesInISEBlock);
   1326 								const int numBlocks				= divRoundUp(numTQValues, numISEBlocksPerBlock);
   1327 
   1328 								for (int offset = 0;	offset < numValuesInISEBlock;	offset++)
   1329 								for (int blockNdx = 0;	blockNdx < numBlocks;			blockNdx++)
   1330 								{
   1331 									for (int iseBlockNdx = 0; iseBlockNdx < numISEBlocksPerBlock; iseBlockNdx++)
   1332 									{
   1333 										for (int i = 0; i < numValuesInISEBlock; i++)
   1334 											iseInputs.endpoint.value.block[iseBlockNdx].bitValues[i] = 0;
   1335 										iseInputs.endpoint.value.block[iseBlockNdx].tOrQValue = (blockNdx*numISEBlocksPerBlock + iseBlockNdx + offset) % numTQValues;
   1336 									}
   1337 
   1338 									generateNormalBlock(blockParams, blockSize.x(), blockSize.y(), iseInputs).pushBytesToVector(dst);
   1339 								}
   1340 							}
   1341 						}
   1342 					}
   1343 				}
   1344 
   1345 				DE_ASSERT(validCaseGenerated);
   1346 			}
   1347 
   1348 			break;
   1349 		}
   1350 
   1351 		case ASTCBLOCKTESTTYPE_CCS:
   1352 		// For all partition counts, test all values of the CCS (color component selector).
   1353 		{
   1354 			for (int		numPartitions = 1;		numPartitions <= 3;		numPartitions++)
   1355 			for (deUint32	ccs = 0;				ccs < 4;				ccs++)
   1356 			{
   1357 				NormalBlockParams blockParams;
   1358 				blockParams.weightGridWidth				= 3;
   1359 				blockParams.weightGridHeight			= 3;
   1360 				blockParams.weightISEParams				= ISEParams(ISEMODE_PLAIN_BIT, 2);
   1361 				blockParams.isDualPlane					= true;
   1362 				blockParams.ccs							= ccs;
   1363 				blockParams.numPartitions				= numPartitions;
   1364 				blockParams.isMultiPartSingleCemMode	= true;
   1365 				blockParams.colorEndpointModes[0]		= 8;
   1366 				blockParams.partitionSeed				= 634;
   1367 
   1368 				generateNormalBlock(blockParams, blockSize.x(), blockSize.y(), generateDefaultISEInputs(blockParams)).pushBytesToVector(dst);
   1369 			}
   1370 
   1371 			break;
   1372 		}
   1373 
   1374 		case ASTCBLOCKTESTTYPE_RANDOM:
   1375 		// Generate a number of random (but valid) blocks.
   1376 		{
   1377 			const int		numBlocks			= 16384;
   1378 			de::Random		rnd					(1);
   1379 			int				numBlocksGenerated	= 0;
   1380 
   1381 			dst.reserve(numBlocks*ASTC_BLOCK_SIZE_BYTES);
   1382 
   1383 			for (numBlocksGenerated = 0; numBlocksGenerated < numBlocks; numBlocksGenerated++)
   1384 			{
   1385 				if (rnd.getFloat() < 0.1f)
   1386 				{
   1387 					// Void extent block.
   1388 					const bool		isVoidExtentHDR		= rnd.getBool();
   1389 					const deUint16	r					= isVoidExtentHDR ? deFloat32To16(rnd.getFloat(0.0f, 1.0f)) : rnd.getInt(0, 0xffff);
   1390 					const deUint16	g					= isVoidExtentHDR ? deFloat32To16(rnd.getFloat(0.0f, 1.0f)) : rnd.getInt(0, 0xffff);
   1391 					const deUint16	b					= isVoidExtentHDR ? deFloat32To16(rnd.getFloat(0.0f, 1.0f)) : rnd.getInt(0, 0xffff);
   1392 					const deUint16	a					= isVoidExtentHDR ? deFloat32To16(rnd.getFloat(0.0f, 1.0f)) : rnd.getInt(0, 0xffff);
   1393 					generateVoidExtentBlock(VoidExtentParams(isVoidExtentHDR, r, g, b, a)).pushBytesToVector(dst);
   1394 				}
   1395 				else
   1396 				{
   1397 					// Not void extent block.
   1398 
   1399 					// Generate block params.
   1400 
   1401 					NormalBlockParams blockParams;
   1402 
   1403 					do
   1404 					{
   1405 						blockParams.weightGridWidth				= rnd.getInt(2, blockSize.x());
   1406 						blockParams.weightGridHeight			= rnd.getInt(2, blockSize.y());
   1407 						blockParams.weightISEParams				= weightISEParamsCandidates[rnd.getInt(0, DE_LENGTH_OF_ARRAY(weightISEParamsCandidates)-1)];
   1408 						blockParams.numPartitions				= rnd.getInt(1, 4);
   1409 						blockParams.isMultiPartSingleCemMode	= rnd.getFloat() < 0.25f;
   1410 						blockParams.isDualPlane					= blockParams.numPartitions != 4 && rnd.getBool();
   1411 						blockParams.ccs							= rnd.getInt(0, 3);
   1412 						blockParams.partitionSeed				= rnd.getInt(0, 1023);
   1413 
   1414 						blockParams.colorEndpointModes[0] = rnd.getInt(0, 15);
   1415 
   1416 						{
   1417 							const int cemDiff = blockParams.isMultiPartSingleCemMode		? 0
   1418 												: blockParams.colorEndpointModes[0] == 0	? 1
   1419 												: blockParams.colorEndpointModes[0] == 15	? -1
   1420 												: rnd.getBool()								? 1 : -1;
   1421 
   1422 							for (int i = 1; i < blockParams.numPartitions; i++)
   1423 								blockParams.colorEndpointModes[i] = blockParams.colorEndpointModes[0] + (cemDiff == -1 ? rnd.getInt(-1, 0) : cemDiff == 1 ? rnd.getInt(0, 1) : 0);
   1424 						}
   1425 					} while (!isValidBlockParams(blockParams, blockSize.x(), blockSize.y()));
   1426 
   1427 					// Generate ISE inputs for both weight and endpoint data.
   1428 
   1429 					NormalBlockISEInputs iseInputs;
   1430 
   1431 					for (int weightOrEndpoints = 0; weightOrEndpoints <= 1; weightOrEndpoints++)
   1432 					{
   1433 						const bool			setWeights	= weightOrEndpoints == 0;
   1434 						const int			numValues	= setWeights ? computeNumWeights(blockParams) :
   1435 														  computeNumColorEndpointValues(&blockParams.colorEndpointModes[0], blockParams.numPartitions, blockParams.isMultiPartSingleCemMode);
   1436 						const ISEParams		iseParams	= setWeights ? blockParams.weightISEParams : computeMaximumRangeISEParams(computeNumBitsForColorEndpoints(blockParams), numValues);
   1437 						ISEInput&			iseInput	= setWeights ? iseInputs.weight : iseInputs.endpoint;
   1438 
   1439 						iseInput.isGivenInBlockForm = rnd.getBool();
   1440 
   1441 						if (iseInput.isGivenInBlockForm)
   1442 						{
   1443 							const int numValuesPerISEBlock	= iseParams.mode == ISEMODE_TRIT	? 5
   1444 															: iseParams.mode == ISEMODE_QUINT	? 3
   1445 															:									  1;
   1446 							const int iseBitMax				= (1 << iseParams.numBits) - 1;
   1447 							const int numISEBlocks			= divRoundUp(numValues, numValuesPerISEBlock);
   1448 
   1449 							for (int iseBlockNdx = 0; iseBlockNdx < numISEBlocks; iseBlockNdx++)
   1450 							{
   1451 								iseInput.value.block[iseBlockNdx].tOrQValue = rnd.getInt(0, 255);
   1452 								for (int i = 0; i < numValuesPerISEBlock; i++)
   1453 									iseInput.value.block[iseBlockNdx].bitValues[i] = rnd.getInt(0, iseBitMax);
   1454 							}
   1455 						}
   1456 						else
   1457 						{
   1458 							const int rangeMax = computeISERangeMax(iseParams);
   1459 
   1460 							for (int valueNdx = 0; valueNdx < numValues; valueNdx++)
   1461 								iseInput.value.plain[valueNdx] = rnd.getInt(0, rangeMax);
   1462 						}
   1463 					}
   1464 
   1465 					generateNormalBlock(blockParams, blockSize.x(), blockSize.y(), iseInputs).pushBytesToVector(dst);
   1466 				}
   1467 			}
   1468 
   1469 			break;
   1470 		}
   1471 
   1472 		default:
   1473 			DE_ASSERT(false);
   1474 	}
   1475 }
   1476 
   1477 // Get a string describing the data of an ASTC block. Currently contains just hex and bin dumps of the block.
   1478 static string astcBlockDataStr (const deUint8* data)
   1479 {
   1480 	string result;
   1481 	result += "  Hexadecimal (big endian: upper left hex digit is block bits 127 to 124):";
   1482 
   1483 	{
   1484 		static const char* const hexDigits = "0123456789ABCDEF";
   1485 
   1486 		for (int i = ASTC_BLOCK_SIZE_BYTES-1; i >= 0; i--)
   1487 		{
   1488 			if ((i+1) % 2 == 0)
   1489 				result += "\n    ";
   1490 			else
   1491 				result += "  ";
   1492 
   1493 			result += hexDigits[(data[i] & 0xf0) >> 4];
   1494 			result += " ";
   1495 			result += hexDigits[(data[i] & 0x0f) >> 0];
   1496 		}
   1497 	}
   1498 
   1499 	result += "\n\n  Binary (big endian: upper left bit is block bit 127):";
   1500 
   1501 	for (int i = ASTC_BLOCK_SIZE_BYTES-1; i >= 0; i--)
   1502 	{
   1503 		if ((i+1) % 2 == 0)
   1504 			result += "\n    ";
   1505 		else
   1506 			result += "  ";
   1507 
   1508 		for (int j = 8-1; j >= 0; j--)
   1509 		{
   1510 			if (j == 3)
   1511 				result += " ";
   1512 
   1513 			result += (data[i] >> j) & 1 ? "1" : "0";
   1514 		}
   1515 	}
   1516 
   1517 	result += "\n";
   1518 
   1519 	return result;
   1520 }
   1521 
   1522 // Compare reference and result block images, reporting also the position of the first non-matching block.
   1523 static bool compareBlockImages (const Surface&		reference,
   1524 								const Surface&		result,
   1525 								const tcu::RGBA&	thresholdRGBA,
   1526 								const IVec2&		blockSize,
   1527 								int					numNonDummyBlocks,
   1528 								IVec2&				firstFailedBlockCoordDst,
   1529 								Surface&			errorMaskDst,
   1530 								IVec4&				maxDiffDst)
   1531 {
   1532 	TCU_CHECK_INTERNAL(reference.getWidth() == result.getWidth() && reference.getHeight() == result.getHeight());
   1533 
   1534 	const int		width		= result.getWidth();
   1535 	const int		height		= result.getHeight();
   1536 	const IVec4		threshold	= thresholdRGBA.toIVec();
   1537 	const int		numXBlocks	= width / blockSize.x();
   1538 
   1539 	DE_ASSERT(width % blockSize.x() == 0 && height % blockSize.y() == 0);
   1540 
   1541 	errorMaskDst.setSize(width, height);
   1542 
   1543 	firstFailedBlockCoordDst	= IVec2(-1, -1);
   1544 	maxDiffDst					= IVec4(0);
   1545 
   1546 	for (int y = 0; y < height; y++)
   1547 	for (int x = 0; x < width; x++)
   1548 	{
   1549 		const IVec2 blockCoord = IVec2(x, y) / blockSize;
   1550 
   1551 		if (blockCoord.y()*numXBlocks + blockCoord.x() < numNonDummyBlocks)
   1552 		{
   1553 			const IVec4 refPix = reference.getPixel(x, y).toIVec();
   1554 
   1555 			if (refPix == IVec4(255, 0, 255, 255))
   1556 			{
   1557 				// ASTC error color - allow anything in result.
   1558 				errorMaskDst.setPixel(x, y, tcu::RGBA(255, 0, 255, 255));
   1559 				continue;
   1560 			}
   1561 
   1562 			const IVec4		resPix		= result.getPixel(x, y).toIVec();
   1563 			const IVec4		diff		= tcu::abs(refPix - resPix);
   1564 			const bool		isOk		= tcu::boolAll(tcu::lessThanEqual(diff, threshold));
   1565 
   1566 			maxDiffDst = tcu::max(maxDiffDst, diff);
   1567 
   1568 			errorMaskDst.setPixel(x, y, isOk ? tcu::RGBA::green : tcu::RGBA::red);
   1569 
   1570 			if (!isOk && firstFailedBlockCoordDst.x() == -1)
   1571 				firstFailedBlockCoordDst = blockCoord;
   1572 		}
   1573 	}
   1574 
   1575 	return boolAll(lessThanEqual(maxDiffDst, threshold));
   1576 }
   1577 
   1578 enum ASTCSupportLevel
   1579 {
   1580 	// \note Ordered from smallest subset to full, for convenient comparison.
   1581 	ASTCSUPPORTLEVEL_NONE = 0,
   1582 	ASTCSUPPORTLEVEL_LDR,
   1583 	ASTCSUPPORTLEVEL_HDR,
   1584 	ASTCSUPPORTLEVEL_FULL
   1585 };
   1586 
   1587 static inline ASTCSupportLevel getASTCSupportLevel (const glu::ContextInfo& contextInfo)
   1588 {
   1589 	const vector<string>& extensions = contextInfo.getExtensions();
   1590 
   1591 	ASTCSupportLevel maxLevel = ASTCSUPPORTLEVEL_NONE;
   1592 
   1593 	for (int extNdx = 0; extNdx < (int)extensions.size(); extNdx++)
   1594 	{
   1595 		const string& ext = extensions[extNdx];
   1596 
   1597 		maxLevel = de::max(maxLevel, ext == "GL_KHR_texture_compression_astc_ldr"	? ASTCSUPPORTLEVEL_LDR
   1598 								   : ext == "GL_KHR_texture_compression_astc_hdr"	? ASTCSUPPORTLEVEL_HDR
   1599 								   : ext == "GL_OES_texture_compression_astc"		? ASTCSUPPORTLEVEL_FULL
   1600 								   : ASTCSUPPORTLEVEL_NONE);
   1601 	}
   1602 
   1603 	return maxLevel;
   1604 }
   1605 
   1606 // Class handling the common rendering stuff of ASTC cases.
   1607 class ASTCRenderer2D
   1608 {
   1609 public:
   1610 										ASTCRenderer2D		(Context&					context,
   1611 															 CompressedTexture::Format	format,
   1612 															 deUint32					randomSeed);
   1613 
   1614 										~ASTCRenderer2D		(void);
   1615 
   1616 	void								initialize			(int minRenderWidth, int minRenderHeight, const Vec4& colorScale, const Vec4& colorBias);
   1617 	void								clear				(void);
   1618 
   1619 	void								render				(Surface&					referenceDst,
   1620 															 Surface&					resultDst,
   1621 															 const glu::Texture2D&		texture,
   1622 															 const tcu::TextureFormat&	uncompressedFormat);
   1623 
   1624 	CompressedTexture::Format			getFormat			(void) const { return m_format; }
   1625 	IVec2								getBlockSize		(void) const { return m_blockSize; }
   1626 	ASTCSupportLevel					getASTCSupport		(void) const { DE_ASSERT(m_initialized); return m_astcSupport;	}
   1627 
   1628 private:
   1629 	Context&							m_context;
   1630 	TextureRenderer						m_renderer;
   1631 
   1632 	const CompressedTexture::Format		m_format;
   1633 	const IVec2							m_blockSize;
   1634 	ASTCSupportLevel					m_astcSupport;
   1635 	Vec4								m_colorScale;
   1636 	Vec4								m_colorBias;
   1637 
   1638 	de::Random							m_rnd;
   1639 
   1640 	bool								m_initialized;
   1641 };
   1642 
   1643 } // ASTCDecompressionCaseInternal
   1644 
   1645 using namespace ASTCDecompressionCaseInternal;
   1646 
   1647 ASTCRenderer2D::ASTCRenderer2D (Context&					context,
   1648 								CompressedTexture::Format	format,
   1649 								deUint32					randomSeed)
   1650 	: m_context			(context)
   1651 	, m_renderer		(context.getRenderContext(), context.getTestContext(), glu::GLSL_VERSION_300_ES, glu::PRECISION_HIGHP)
   1652 	, m_format			(format)
   1653 	, m_blockSize		(tcu::getASTCBlockSize(format).xy())
   1654 	, m_astcSupport		(ASTCSUPPORTLEVEL_NONE)
   1655 	, m_colorScale		(-1.0f)
   1656 	, m_colorBias		(-1.0f)
   1657 	, m_rnd				(randomSeed)
   1658 	, m_initialized		(false)
   1659 {
   1660 	DE_ASSERT(tcu::getASTCBlockSize(format).z() == 1);
   1661 }
   1662 
   1663 ASTCRenderer2D::~ASTCRenderer2D (void)
   1664 {
   1665 	clear();
   1666 }
   1667 
   1668 void ASTCRenderer2D::initialize (int minRenderWidth, int minRenderHeight, const Vec4& colorScale, const Vec4& colorBias)
   1669 {
   1670 	DE_ASSERT(!m_initialized);
   1671 
   1672 	const tcu::RenderTarget&	renderTarget	= m_context.getRenderTarget();
   1673 	TestLog&					log				= m_context.getTestContext().getLog();
   1674 
   1675 	m_astcSupport	= getASTCSupportLevel(m_context.getContextInfo());
   1676 	m_colorScale	= colorScale;
   1677 	m_colorBias		= colorBias;
   1678 
   1679 	switch (m_astcSupport)
   1680 	{
   1681 		case ASTCSUPPORTLEVEL_NONE:		log << TestLog::Message << "No ASTC support detected" << TestLog::EndMessage;		throw tcu::NotSupportedError("ASTC not supported");
   1682 		case ASTCSUPPORTLEVEL_LDR:		log << TestLog::Message << "LDR ASTC support detected" << TestLog::EndMessage;		break;
   1683 		case ASTCSUPPORTLEVEL_HDR:		log << TestLog::Message << "HDR ASTC support detected" << TestLog::EndMessage;		break;
   1684 		case ASTCSUPPORTLEVEL_FULL:		log << TestLog::Message << "Full ASTC support detected" << TestLog::EndMessage;		break;
   1685 		default:
   1686 			DE_ASSERT(false);
   1687 	}
   1688 
   1689 	if (renderTarget.getWidth() < minRenderWidth || renderTarget.getHeight() < minRenderHeight)
   1690 		throw tcu::NotSupportedError("Render target must be at least " + de::toString(minRenderWidth) + "x" + de::toString(minRenderHeight));
   1691 
   1692 	log << TestLog::Message << "Using color scale and bias: result = raw * " << colorScale << " + " << colorBias << TestLog::EndMessage;
   1693 
   1694 	m_initialized = true;
   1695 }
   1696 
   1697 void ASTCRenderer2D::clear (void)
   1698 {
   1699 	m_renderer.clear();
   1700 }
   1701 
   1702 void ASTCRenderer2D::render (Surface& referenceDst, Surface& resultDst, const glu::Texture2D& texture, const tcu::TextureFormat& uncompressedFormat)
   1703 {
   1704 	DE_ASSERT(m_initialized);
   1705 
   1706 	const glw::Functions&			gl						= m_context.getRenderContext().getFunctions();
   1707 	const glu::RenderContext&		renderCtx				= m_context.getRenderContext();
   1708 	const int						textureWidth			= texture.getRefTexture().getWidth();
   1709 	const int						textureHeight			= texture.getRefTexture().getHeight();
   1710 	const RandomViewport			viewport				(renderCtx.getRenderTarget(), textureWidth, textureHeight, m_rnd.getUint32());
   1711 	ReferenceParams					renderParams			(gls::TextureTestUtil::TEXTURETYPE_2D);
   1712 	vector<float>					texCoord;
   1713 	gls::TextureTestUtil::computeQuadTexCoord2D(texCoord, Vec2(0.0f, 0.0f), Vec2(1.0f, 1.0f));
   1714 
   1715 	renderParams.samplerType	= gls::TextureTestUtil::getSamplerType(uncompressedFormat);
   1716 	renderParams.sampler		= Sampler(Sampler::CLAMP_TO_EDGE, Sampler::CLAMP_TO_EDGE, Sampler::CLAMP_TO_EDGE, Sampler::NEAREST, Sampler::NEAREST);
   1717 	renderParams.colorScale		= m_colorScale;
   1718 	renderParams.colorBias		= m_colorBias;
   1719 
   1720 	// Setup base viewport.
   1721 	gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
   1722 
   1723 	// Bind to unit 0.
   1724 	gl.activeTexture(GL_TEXTURE0);
   1725 	gl.bindTexture(GL_TEXTURE_2D, texture.getGLTexture());
   1726 
   1727 	// Setup nearest neighbor filtering and clamp-to-edge.
   1728 	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,		GL_CLAMP_TO_EDGE);
   1729 	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,		GL_CLAMP_TO_EDGE);
   1730 	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,	GL_NEAREST);
   1731 	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,	GL_NEAREST);
   1732 
   1733 	GLU_EXPECT_NO_ERROR(gl.getError(), "Set texturing state");
   1734 
   1735 	// Issue GL draws.
   1736 	m_renderer.renderQuad(0, &texCoord[0], renderParams);
   1737 	gl.flush();
   1738 
   1739 	// Compute reference.
   1740 	sampleTexture(gls::TextureTestUtil::SurfaceAccess(referenceDst, renderCtx.getRenderTarget().getPixelFormat()), texture.getRefTexture(), &texCoord[0], renderParams);
   1741 
   1742 	// Read GL-rendered image.
   1743 	glu::readPixels(renderCtx, viewport.x, viewport.y, resultDst.getAccess());
   1744 }
   1745 
   1746 ASTCBlockCase2D::ASTCBlockCase2D (Context&						context,
   1747 								  const char*					name,
   1748 								  const char*					description,
   1749 								  ASTCBlockTestType				testType,
   1750 								  CompressedTexture::Format		format)
   1751 	: TestCase				(context, name, description)
   1752 	, m_testType			(testType)
   1753 	, m_format				(format)
   1754 	, m_numBlocksTested		(0)
   1755 	, m_currentIteration	(0)
   1756 	, m_renderer			(new ASTCRenderer2D(context, format, deStringHash(getName())))
   1757 {
   1758 	DE_ASSERT(!(tcu::isASTCSRGBFormat(m_format) && isBlockTestTypeHDROnly(m_testType))); // \note There is no HDR sRGB mode, so these would be redundant.
   1759 }
   1760 
   1761 ASTCBlockCase2D::~ASTCBlockCase2D (void)
   1762 {
   1763 	ASTCBlockCase2D::deinit();
   1764 }
   1765 
   1766 void ASTCBlockCase2D::init (void)
   1767 {
   1768 	m_renderer->initialize(64, 64, getBlockTestTypeColorScale(m_testType), getBlockTestTypeColorBias(m_testType));
   1769 
   1770 	generateBlockCaseTestData(m_blockData, m_format, m_testType);
   1771 	DE_ASSERT(!m_blockData.empty());
   1772 	DE_ASSERT(m_blockData.size() % ASTC_BLOCK_SIZE_BYTES == 0);
   1773 
   1774 	m_testCtx.getLog() << TestLog::Message << "Total " << m_blockData.size() / ASTC_BLOCK_SIZE_BYTES << " blocks to test" << TestLog::EndMessage
   1775 					   << TestLog::Message << "Note: Legitimate ASTC error pixels will be ignored when comparing to reference" << TestLog::EndMessage;
   1776 }
   1777 
   1778 void ASTCBlockCase2D::deinit (void)
   1779 {
   1780 	m_renderer->clear();
   1781 	m_blockData.clear();
   1782 }
   1783 
   1784 ASTCBlockCase2D::IterateResult ASTCBlockCase2D::iterate (void)
   1785 {
   1786 	TestLog&						log						= m_testCtx.getLog();
   1787 
   1788 	if (m_renderer->getASTCSupport() == ASTCSUPPORTLEVEL_LDR && isBlockTestTypeHDROnly(m_testType))
   1789 	{
   1790 		log << TestLog::Message << "Passing the case immediately, since only LDR support was detected and test only contains HDR blocks" << TestLog::EndMessage;
   1791 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
   1792 		return STOP;
   1793 	}
   1794 
   1795 	const IVec2						blockSize				= m_renderer->getBlockSize();
   1796 	const int						totalNumBlocks			= (int)m_blockData.size() / ASTC_BLOCK_SIZE_BYTES;
   1797 	const int						numXBlocksPerImage		= de::min(m_context.getRenderTarget().getWidth(),  512) / blockSize.x();
   1798 	const int						numYBlocksPerImage		= de::min(m_context.getRenderTarget().getHeight(), 512) / blockSize.y();
   1799 	const int						numBlocksPerImage		= numXBlocksPerImage * numYBlocksPerImage;
   1800 	const int						imageWidth				= numXBlocksPerImage * blockSize.x();
   1801 	const int						imageHeight				= numYBlocksPerImage * blockSize.y();
   1802 	const int						numBlocksRemaining		= totalNumBlocks - m_numBlocksTested;
   1803 	const int						curNumNonDummyBlocks	= de::min(numBlocksPerImage, numBlocksRemaining);
   1804 	const int						curNumDummyBlocks		= numBlocksPerImage - curNumNonDummyBlocks;
   1805 	const glu::RenderContext&		renderCtx				= m_context.getRenderContext();
   1806 	const tcu::RGBA					threshold				= renderCtx.getRenderTarget().getPixelFormat().getColorThreshold() + (tcu::isASTCSRGBFormat(m_format) ? tcu::RGBA(2,2,2,2) : tcu::RGBA(1,1,1,1));
   1807 	tcu::CompressedTexture			compressed				(m_format, imageWidth, imageHeight);
   1808 
   1809 	if (m_currentIteration == 0)
   1810 	{
   1811 		log << TestLog::Message << "Using texture of size "
   1812 								<< imageWidth << "x" << imageHeight
   1813 								<< ", with " << numXBlocksPerImage << " block columns and " << numYBlocksPerImage << " block rows "
   1814 								<< ", with block size " << blockSize.x() << "x" << blockSize.y()
   1815 			<< TestLog::EndMessage;
   1816 	}
   1817 
   1818 	DE_ASSERT(compressed.getDataSize() == numBlocksPerImage*ASTC_BLOCK_SIZE_BYTES);
   1819 	deMemcpy(compressed.getData(), &m_blockData[m_numBlocksTested*ASTC_BLOCK_SIZE_BYTES], curNumNonDummyBlocks*ASTC_BLOCK_SIZE_BYTES);
   1820 	if (curNumDummyBlocks > 1)
   1821 		generateDummyBlocks((deUint8*)compressed.getData() + curNumNonDummyBlocks*ASTC_BLOCK_SIZE_BYTES, curNumDummyBlocks);
   1822 
   1823 	// Create texture and render.
   1824 
   1825 	glu::Texture2D	texture			(renderCtx, m_context.getContextInfo(), 1, &compressed, tcu::CompressedTexture::DecompressionParams(m_renderer->getASTCSupport() == ASTCSUPPORTLEVEL_LDR));
   1826 	Surface			renderedFrame	(imageWidth, imageHeight);
   1827 	Surface			referenceFrame	(imageWidth, imageHeight);
   1828 
   1829 	m_renderer->render(referenceFrame, renderedFrame, texture, compressed.getUncompressedFormat());
   1830 
   1831 	// Compare and log.
   1832 	// \note Since a case can draw quite many images, only log the first iteration and failures.
   1833 
   1834 	{
   1835 		Surface		errorMask;
   1836 		IVec2		firstFailedBlockCoord;
   1837 		IVec4		maxDiff;
   1838 		const bool	compareOk = compareBlockImages(referenceFrame, renderedFrame, threshold, blockSize, curNumNonDummyBlocks, firstFailedBlockCoord, errorMask, maxDiff);
   1839 
   1840 		if (m_currentIteration == 0 || !compareOk)
   1841 		{
   1842 			const char* const		imageSetName	= "ComparisonResult";
   1843 			const char* const		imageSetDesc	= "Comparison Result";
   1844 
   1845 			{
   1846 				tcu::ScopedLogSection section(log, "Iteration " + de::toString(m_currentIteration),
   1847 													"Blocks " + de::toString(m_numBlocksTested) + " to " + de::toString(m_numBlocksTested + curNumNonDummyBlocks - 1));
   1848 
   1849 				if (curNumDummyBlocks > 0)
   1850 					log << TestLog::Message << "Note: Only the first " << curNumNonDummyBlocks << " blocks in the image are relevant; rest " << curNumDummyBlocks << " are dummies and not checked" << TestLog::EndMessage;
   1851 
   1852 				if (!compareOk)
   1853 				{
   1854 					log << TestLog::Message << "Image comparison failed: max difference = " << maxDiff << ", threshold = " << threshold << TestLog::EndMessage
   1855 						<< TestLog::ImageSet(imageSetName, imageSetDesc)
   1856 						<< TestLog::Image("Result",		"Result",		renderedFrame)
   1857 						<< TestLog::Image("Reference",	"Reference",	referenceFrame)
   1858 						<< TestLog::Image("ErrorMask",	"Error mask",	errorMask)
   1859 						<< TestLog::EndImageSet;
   1860 
   1861 					const int blockNdx = m_numBlocksTested + firstFailedBlockCoord.y()*numXBlocksPerImage + firstFailedBlockCoord.x();
   1862 					DE_ASSERT(blockNdx < totalNumBlocks);
   1863 
   1864 					log << TestLog::Message << "First failed block at column " << firstFailedBlockCoord.x() << " and row " << firstFailedBlockCoord.y() << TestLog::EndMessage
   1865 						<< TestLog::Message << "Data of first failed block:\n" << astcBlockDataStr(&m_blockData[blockNdx*ASTC_BLOCK_SIZE_BYTES]) << TestLog::EndMessage;
   1866 
   1867 					m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
   1868 					return STOP;
   1869 				}
   1870 				else
   1871 				{
   1872 					log << TestLog::ImageSet(imageSetName, imageSetDesc)
   1873 						<< TestLog::Image("Result", "Result", renderedFrame)
   1874 						<< TestLog::EndImageSet;
   1875 				}
   1876 			}
   1877 
   1878 			if (m_numBlocksTested + curNumNonDummyBlocks < totalNumBlocks)
   1879 				log << TestLog::Message << "Note: not logging further images unless reference comparison fails" << TestLog::EndMessage;
   1880 		}
   1881 	}
   1882 
   1883 	m_currentIteration++;
   1884 	m_numBlocksTested += curNumNonDummyBlocks;
   1885 
   1886 	if (m_numBlocksTested >= totalNumBlocks)
   1887 	{
   1888 		DE_ASSERT(m_numBlocksTested == totalNumBlocks);
   1889 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
   1890 		return STOP;
   1891 	}
   1892 
   1893 	return CONTINUE;
   1894 }
   1895 
   1896 // Generate a number of trivial dummy blocks to fill unneeded space in a texture.
   1897 void ASTCBlockCase2D::generateDummyBlocks (deUint8* dst, int num)
   1898 {
   1899 	using namespace ASTCBlockGeneratorInternal;
   1900 
   1901 	AssignBlock128 block = generateVoidExtentBlock(VoidExtentParams(false, 0, 0, 0, 0));
   1902 	for (int i = 0; i < num; i++)
   1903 		block.assignToMemory(&dst[i * ASTC_BLOCK_SIZE_BYTES]);
   1904 }
   1905 
   1906 ASTCBlockSizeRemainderCase2D::ASTCBlockSizeRemainderCase2D (Context&					context,
   1907 															const char*					name,
   1908 															const char*					description,
   1909 															CompressedTexture::Format	format)
   1910 	: TestCase				(context, name, description)
   1911 	, m_format				(format)
   1912 	, m_currentIteration	(0)
   1913 	, m_renderer			(new ASTCRenderer2D(context, format, deStringHash(getName())))
   1914 {
   1915 }
   1916 
   1917 ASTCBlockSizeRemainderCase2D::~ASTCBlockSizeRemainderCase2D (void)
   1918 {
   1919 	ASTCBlockSizeRemainderCase2D::deinit();
   1920 }
   1921 
   1922 void ASTCBlockSizeRemainderCase2D::init (void)
   1923 {
   1924 	const IVec2 blockSize = m_renderer->getBlockSize();
   1925 	m_renderer->initialize(MAX_NUM_BLOCKS_X*blockSize.x(), MAX_NUM_BLOCKS_Y*blockSize.y(), Vec4(1.0f), Vec4(0.0f));
   1926 }
   1927 
   1928 void ASTCBlockSizeRemainderCase2D::deinit (void)
   1929 {
   1930 	m_renderer->clear();
   1931 }
   1932 
   1933 ASTCBlockSizeRemainderCase2D::IterateResult ASTCBlockSizeRemainderCase2D::iterate (void)
   1934 {
   1935 	TestLog&						log						= m_testCtx.getLog();
   1936 	const IVec2						blockSize				= m_renderer->getBlockSize();
   1937 	const int						curRemainderX			= m_currentIteration % blockSize.x();
   1938 	const int						curRemainderY			= m_currentIteration / blockSize.x();
   1939 	const int						imageWidth				= (MAX_NUM_BLOCKS_X-1)*blockSize.x() + curRemainderX;
   1940 	const int						imageHeight				= (MAX_NUM_BLOCKS_Y-1)*blockSize.y() + curRemainderY;
   1941 	const int						numBlocksX				= divRoundUp(imageWidth, blockSize.x());
   1942 	const int						numBlocksY				= divRoundUp(imageHeight, blockSize.y());
   1943 	const int						totalNumBlocks			= numBlocksX * numBlocksY;
   1944 	const glu::RenderContext&		renderCtx				= m_context.getRenderContext();
   1945 	const tcu::RGBA					threshold				= renderCtx.getRenderTarget().getPixelFormat().getColorThreshold() + (tcu::isASTCSRGBFormat(m_format) ? tcu::RGBA(2,2,2,2) : tcu::RGBA(1,1,1,1));
   1946 	tcu::CompressedTexture			compressed				(m_format, imageWidth, imageHeight);
   1947 
   1948 	DE_ASSERT(compressed.getDataSize() == totalNumBlocks*ASTC_BLOCK_SIZE_BYTES);
   1949 	generateDefaultBlockData((deUint8*)compressed.getData(), totalNumBlocks, blockSize.x(), blockSize.y());
   1950 
   1951 	// Create texture and render.
   1952 
   1953 	Surface			renderedFrame	(imageWidth, imageHeight);
   1954 	Surface			referenceFrame	(imageWidth, imageHeight);
   1955 	glu::Texture2D	texture			(renderCtx, m_context.getContextInfo(), 1, &compressed, tcu::CompressedTexture::DecompressionParams(m_renderer->getASTCSupport() == ASTCSUPPORTLEVEL_LDR));
   1956 
   1957 	m_renderer->render(referenceFrame, renderedFrame, texture, compressed.getUncompressedFormat());
   1958 
   1959 	{
   1960 		// Compare and log.
   1961 
   1962 		tcu::ScopedLogSection section(log, "Iteration " + de::toString(m_currentIteration),
   1963 										   "Remainder " + de::toString(curRemainderX) + "x" + de::toString(curRemainderY));
   1964 
   1965 		log << TestLog::Message << "Using texture of size "
   1966 								<< imageWidth << "x" << imageHeight
   1967 								<< " and block size "
   1968 								<< blockSize.x() << "x" << blockSize.y()
   1969 								<< "; the x and y remainders are "
   1970 								<< curRemainderX << " and " << curRemainderY << " respectively"
   1971 			<< TestLog::EndMessage;
   1972 
   1973 		const bool compareOk = tcu::pixelThresholdCompare(m_testCtx.getLog(), "ComparisonResult", "Comparison Result", referenceFrame, renderedFrame, threshold,
   1974 														  m_currentIteration == 0 ? tcu::COMPARE_LOG_RESULT : tcu::COMPARE_LOG_ON_ERROR);
   1975 
   1976 		if (!compareOk)
   1977 		{
   1978 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
   1979 			return STOP;
   1980 		}
   1981 	}
   1982 
   1983 	if (m_currentIteration == 0 && m_currentIteration+1 < blockSize.x()*blockSize.y())
   1984 		log << TestLog::Message << "Note: not logging further images unless reference comparison fails" << TestLog::EndMessage;
   1985 
   1986 	m_currentIteration++;
   1987 
   1988 	if (m_currentIteration >= blockSize.x()*blockSize.y())
   1989 	{
   1990 		DE_ASSERT(m_currentIteration == blockSize.x()*blockSize.y());
   1991 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
   1992 		return STOP;
   1993 	}
   1994 	return CONTINUE;
   1995 }
   1996 
   1997 void ASTCBlockSizeRemainderCase2D::generateDefaultBlockData (deUint8* dst, int numBlocks, int blockWidth, int blockHeight)
   1998 {
   1999 	using namespace ASTCBlockGeneratorInternal;
   2000 
   2001 	NormalBlockParams blockParams;
   2002 
   2003 	blockParams.weightGridWidth			= 3;
   2004 	blockParams.weightGridHeight		= 3;
   2005 	blockParams.weightISEParams			= ISEParams(ISEMODE_PLAIN_BIT, 5);
   2006 	blockParams.isDualPlane				= false;
   2007 	blockParams.numPartitions			= 1;
   2008 	blockParams.colorEndpointModes[0]	= 8;
   2009 
   2010 	NormalBlockISEInputs iseInputs = generateDefaultISEInputs(blockParams);
   2011 	iseInputs.weight.isGivenInBlockForm = false;
   2012 
   2013 	const int numWeights		= computeNumWeights(blockParams);
   2014 	const int weightRangeMax	= computeISERangeMax(blockParams.weightISEParams);
   2015 
   2016 	for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
   2017 	{
   2018 		for (int weightNdx = 0; weightNdx < numWeights; weightNdx++)
   2019 			iseInputs.weight.value.plain[weightNdx] = (blockNdx*numWeights + weightNdx) * weightRangeMax / (numBlocks*numWeights-1);
   2020 
   2021 		generateNormalBlock(blockParams, blockWidth, blockHeight, iseInputs).assignToMemory(dst + blockNdx*ASTC_BLOCK_SIZE_BYTES);
   2022 	}
   2023 }
   2024 
   2025 const char* getBlockTestTypeName (ASTCBlockTestType testType)
   2026 {
   2027 	switch (testType)
   2028 	{
   2029 		case ASTCBLOCKTESTTYPE_VOID_EXTENT_LDR:				return "void_extent_ldr";
   2030 		case ASTCBLOCKTESTTYPE_VOID_EXTENT_HDR:				return "void_extent_hdr";
   2031 		case ASTCBLOCKTESTTYPE_WEIGHT_GRID:					return "weight_grid";
   2032 		case ASTCBLOCKTESTTYPE_WEIGHT_ISE:					return "weight_ise";
   2033 		case ASTCBLOCKTESTTYPE_CEMS:						return "color_endpoint_modes";
   2034 		case ASTCBLOCKTESTTYPE_PARTITION_SEED:				return "partition_pattern_index";
   2035 		case ASTCBLOCKTESTTYPE_ENDPOINT_VALUE_LDR:			return "endpoint_value_ldr";
   2036 		case ASTCBLOCKTESTTYPE_ENDPOINT_VALUE_HDR_NO_15:	return "endpoint_value_hdr_cem_not_15";
   2037 		case ASTCBLOCKTESTTYPE_ENDPOINT_VALUE_HDR_15:		return "endpoint_value_hdr_cem_15";
   2038 		case ASTCBLOCKTESTTYPE_ENDPOINT_ISE:				return "endpoint_ise";
   2039 		case ASTCBLOCKTESTTYPE_CCS:							return "color_component_selector";
   2040 		case ASTCBLOCKTESTTYPE_RANDOM:						return "random";
   2041 		default:
   2042 			DE_ASSERT(false);
   2043 			return DE_NULL;
   2044 	}
   2045 }
   2046 
   2047 const char* getBlockTestTypeDescription (ASTCBlockTestType testType)
   2048 {
   2049 	switch (testType)
   2050 	{
   2051 		case ASTCBLOCKTESTTYPE_VOID_EXTENT_LDR:				return "Test void extent block, LDR mode";
   2052 		case ASTCBLOCKTESTTYPE_VOID_EXTENT_HDR:				return "Test void extent block, HDR mode";
   2053 		case ASTCBLOCKTESTTYPE_WEIGHT_GRID:					return "Test combinations of plane count, weight integer sequence encoding parameters, and weight grid size";
   2054 		case ASTCBLOCKTESTTYPE_WEIGHT_ISE:					return "Test different integer sequence encoding block values for weight grid";
   2055 		case ASTCBLOCKTESTTYPE_CEMS:						return "Test different color endpoint mode combinations, combined with different plane and partition counts";
   2056 		case ASTCBLOCKTESTTYPE_PARTITION_SEED:				return "Test different partition pattern indices";
   2057 		case ASTCBLOCKTESTTYPE_ENDPOINT_VALUE_LDR:			return "Test various combinations of each pair of color endpoint values, for each LDR color endpoint mode";
   2058 		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";
   2059 		case ASTCBLOCKTESTTYPE_ENDPOINT_VALUE_HDR_15:		return "Test various combinations of each pair of color endpoint values, HDR color endpoint mode 15";
   2060 		case ASTCBLOCKTESTTYPE_ENDPOINT_ISE:				return "Test different integer sequence encoding block values for color endpoints";
   2061 		case ASTCBLOCKTESTTYPE_CCS:							return "Test color component selector, for different partition counts";
   2062 		case ASTCBLOCKTESTTYPE_RANDOM:						return "Random block test";
   2063 		default:
   2064 			DE_ASSERT(false);
   2065 			return DE_NULL;
   2066 	}
   2067 }
   2068 
   2069 bool isBlockTestTypeHDROnly (ASTCBlockTestType testType)
   2070 {
   2071 	return testType == ASTCBLOCKTESTTYPE_VOID_EXTENT_HDR			||
   2072 		   testType == ASTCBLOCKTESTTYPE_ENDPOINT_VALUE_HDR_NO_15	||
   2073 		   testType == ASTCBLOCKTESTTYPE_ENDPOINT_VALUE_HDR_15;
   2074 }
   2075 
   2076 } // Functional
   2077 } // gles3
   2078 } // deqp
   2079