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(¶ms.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