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::IVec2;
64using tcu::IVec3;
65using tcu::IVec4;
66using tcu::Vec2;
67using tcu::Vec4;
68using tcu::Sampler;
69using tcu::Surface;
70using std::vector;
71using std::string;
72
73namespace deqp
74{
75
76using gls::TextureTestUtil::TextureRenderer;
77using gls::TextureTestUtil::RandomViewport;
78using gls::TextureTestUtil::ReferenceParams;
79
80namespace gles3
81{
82namespace Functional
83{
84
85namespace ASTCDecompressionCaseInternal
86{
87
88static const int ASTC_BLOCK_SIZE_BYTES = 128/8;
89
90static inline int divRoundUp (int a, int b)
91{
92	return a/b + ((a%b) ? 1 : 0);
93}
94
95namespace ASTCBlockGeneratorInternal
96{
97
98static 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
107static inline deUint32 getBit (deUint32 src, int ndx)
108{
109	DE_ASSERT(de::inBounds(ndx, 0, 32));
110	return (src >> ndx) & 1;
111}
112
113static 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)
123static inline bool isFloat16InfOrNan (deFloat16 v)
124{
125	return getBits(v, 10, 14) == 31;
126}
127#endif
128
129template <typename T, typename Y>
130struct isSameType			{ enum { V = 0 }; };
131template <typename T>
132struct isSameType<T, T>		{ enum { V = 1 }; };
133
134// Helper class for setting bits in a 128-bit block.
135class AssignBlock128
136{
137private:
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
149public:
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
210private:
211	Word m_words[NUM_WORDS];
212};
213
214// A helper for sequential access into a AssignBlock128.
215class BitAssignAccessStream
216{
217public:
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
247private:
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
256struct 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
269static 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
296enum ISEMode
297{
298	ISEMODE_TRIT = 0,
299	ISEMODE_QUINT,
300	ISEMODE_PLAIN_BIT,
301
302	ISEMODE_LAST
303};
304
305struct 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.
317struct 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
339static 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
352static 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
365struct 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
395struct NormalBlockISEInputs
396{
397	ISEInput weight;
398	ISEInput endpoint;
399
400	NormalBlockISEInputs (void)
401		: weight	()
402		, endpoint	()
403	{
404	}
405};
406
407static inline int computeNumWeights (const NormalBlockParams& params)
408{
409	return params.weightGridWidth * params.weightGridHeight * (params.isDualPlane ? 2 : 1);
410}
411
412static 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
421static inline int computeNumColorEndpointValues (deUint32 endpointMode)
422{
423	DE_ASSERT(endpointMode < 16);
424	return (endpointMode/4 + 1) * 2;
425}
426
427static 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
440static 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.
457static 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.
580static 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
618static 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
658static 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
725static 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
776static 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
782static 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
816static 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
823static 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
829static 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.
873static 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
915static 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
926static 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.
936static 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.
1478static 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.
1523static 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
1578enum 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
1587static 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.
1607class ASTCRenderer2D
1608{
1609public:
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
1628private:
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
1645using namespace ASTCDecompressionCaseInternal;
1646
1647ASTCRenderer2D::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
1663ASTCRenderer2D::~ASTCRenderer2D (void)
1664{
1665	clear();
1666}
1667
1668void 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
1697void ASTCRenderer2D::clear (void)
1698{
1699	m_renderer.clear();
1700}
1701
1702void 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
1746ASTCBlockCase2D::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
1761ASTCBlockCase2D::~ASTCBlockCase2D (void)
1762{
1763	ASTCBlockCase2D::deinit();
1764}
1765
1766void 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
1778void ASTCBlockCase2D::deinit (void)
1779{
1780	m_renderer->clear();
1781	m_blockData.clear();
1782}
1783
1784ASTCBlockCase2D::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.
1897void 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
1906ASTCBlockSizeRemainderCase2D::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
1917ASTCBlockSizeRemainderCase2D::~ASTCBlockSizeRemainderCase2D (void)
1918{
1919	ASTCBlockSizeRemainderCase2D::deinit();
1920}
1921
1922void 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
1928void ASTCBlockSizeRemainderCase2D::deinit (void)
1929{
1930	m_renderer->clear();
1931}
1932
1933ASTCBlockSizeRemainderCase2D::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
1997void 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
2025const 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
2047const 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
2069bool 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