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