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