xref: /aosp_15_r20/external/deqp/modules/gles3/functional/es3fASTCDecompressionCases.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
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 std::string;
62 using std::vector;
63 using tcu::CompressedTexFormat;
64 using tcu::CompressedTexture;
65 using tcu::IVec2;
66 using tcu::IVec3;
67 using tcu::IVec4;
68 using tcu::Sampler;
69 using tcu::Surface;
70 using tcu::TestLog;
71 using tcu::Vec2;
72 using tcu::Vec4;
73 using tcu::astc::BlockTestType;
74 
75 namespace deqp
76 {
77 
78 using gls::TextureTestUtil::RandomViewport;
79 using gls::TextureTestUtil::TextureRenderer;
80 using namespace glu::TextureTestUtil;
81 
82 namespace gles3
83 {
84 namespace Functional
85 {
86 
87 namespace ASTCDecompressionCaseInternal
88 {
89 
90 // Get a string describing the data of an ASTC block. Currently contains just hex and bin dumps of the block.
astcBlockDataStr(const uint8_t * data)91 static string astcBlockDataStr(const uint8_t *data)
92 {
93     string result;
94     result += "  Hexadecimal (big endian: upper left hex digit is block bits 127 to 124):";
95 
96     {
97         static const char *const hexDigits = "0123456789ABCDEF";
98 
99         for (int i = tcu::astc::BLOCK_SIZE_BYTES - 1; i >= 0; i--)
100         {
101             if ((i + 1) % 2 == 0)
102                 result += "\n    ";
103             else
104                 result += "  ";
105 
106             result += hexDigits[(data[i] & 0xf0) >> 4];
107             result += " ";
108             result += hexDigits[(data[i] & 0x0f) >> 0];
109         }
110     }
111 
112     result += "\n\n  Binary (big endian: upper left bit is block bit 127):";
113 
114     for (int i = tcu::astc::BLOCK_SIZE_BYTES - 1; i >= 0; i--)
115     {
116         if ((i + 1) % 2 == 0)
117             result += "\n    ";
118         else
119             result += "  ";
120 
121         for (int j = 8 - 1; j >= 0; j--)
122         {
123             if (j == 3)
124                 result += " ";
125 
126             result += (data[i] >> j) & 1 ? "1" : "0";
127         }
128     }
129 
130     result += "\n";
131 
132     return result;
133 }
134 
135 // 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 numUsedBlocks,IVec2 & firstFailedBlockCoordDst,Surface & errorMaskDst,IVec4 & maxDiffDst)136 static bool compareBlockImages(const Surface &reference, const Surface &result, const tcu::RGBA &thresholdRGBA,
137                                const IVec2 &blockSize, int numUsedBlocks, IVec2 &firstFailedBlockCoordDst,
138                                Surface &errorMaskDst, IVec4 &maxDiffDst)
139 {
140     TCU_CHECK_INTERNAL(reference.getWidth() == result.getWidth() && reference.getHeight() == result.getHeight());
141 
142     const int width       = result.getWidth();
143     const int height      = result.getHeight();
144     const IVec4 threshold = thresholdRGBA.toIVec();
145     const int numXBlocks  = width / blockSize.x();
146 
147     DE_ASSERT(width % blockSize.x() == 0 && height % blockSize.y() == 0);
148 
149     errorMaskDst.setSize(width, height);
150 
151     firstFailedBlockCoordDst = IVec2(-1, -1);
152     maxDiffDst               = IVec4(0);
153 
154     for (int y = 0; y < height; y++)
155         for (int x = 0; x < width; x++)
156         {
157             const IVec2 blockCoord = IVec2(x, y) / blockSize;
158 
159             if (blockCoord.y() * numXBlocks + blockCoord.x() < numUsedBlocks)
160             {
161                 const IVec4 refPix = reference.getPixel(x, y).toIVec();
162 
163                 if (refPix == IVec4(255, 0, 255, 255))
164                 {
165                     // ASTC error color - allow anything in result.
166                     errorMaskDst.setPixel(x, y, tcu::RGBA(255, 0, 255, 255));
167                     continue;
168                 }
169 
170                 const IVec4 resPix = result.getPixel(x, y).toIVec();
171                 const IVec4 diff   = tcu::abs(refPix - resPix);
172                 const bool isOk    = tcu::boolAll(tcu::lessThanEqual(diff, threshold));
173 
174                 maxDiffDst = tcu::max(maxDiffDst, diff);
175 
176                 errorMaskDst.setPixel(x, y, isOk ? tcu::RGBA::green() : tcu::RGBA::red());
177 
178                 if (!isOk && firstFailedBlockCoordDst.x() == -1)
179                     firstFailedBlockCoordDst = blockCoord;
180             }
181         }
182 
183     return boolAll(lessThanEqual(maxDiffDst, threshold));
184 }
185 
186 enum ASTCSupportLevel
187 {
188     // \note Ordered from smallest subset to full, for convenient comparison.
189     ASTCSUPPORTLEVEL_NONE = 0,
190     ASTCSUPPORTLEVEL_LDR,
191     ASTCSUPPORTLEVEL_HDR,
192     ASTCSUPPORTLEVEL_FULL
193 };
194 
getASTCSupportLevel(const glu::ContextInfo & contextInfo,const glu::RenderContext & renderCtx)195 static inline ASTCSupportLevel getASTCSupportLevel(const glu::ContextInfo &contextInfo,
196                                                    const glu::RenderContext &renderCtx)
197 {
198     const bool isES32 = glu::contextSupports(renderCtx.getType(), glu::ApiType::es(3, 2));
199 
200     const vector<string> &extensions = contextInfo.getExtensions();
201 
202     ASTCSupportLevel maxLevel = ASTCSUPPORTLEVEL_NONE;
203 
204     for (int extNdx = 0; extNdx < (int)extensions.size(); extNdx++)
205     {
206         const string &ext = extensions[extNdx];
207         if (isES32)
208         {
209             maxLevel = de::max(maxLevel, ext == "GL_KHR_texture_compression_astc_hdr" ? ASTCSUPPORTLEVEL_HDR :
210                                          ext == "GL_OES_texture_compression_astc"     ? ASTCSUPPORTLEVEL_FULL :
211                                                                                         ASTCSUPPORTLEVEL_LDR);
212         }
213         else
214         {
215             maxLevel = de::max(maxLevel, ext == "GL_KHR_texture_compression_astc_ldr" ? ASTCSUPPORTLEVEL_LDR :
216                                          ext == "GL_KHR_texture_compression_astc_hdr" ? ASTCSUPPORTLEVEL_HDR :
217                                          ext == "GL_OES_texture_compression_astc"     ? ASTCSUPPORTLEVEL_FULL :
218                                                                                         ASTCSUPPORTLEVEL_NONE);
219         }
220     }
221 
222     return maxLevel;
223 }
224 
225 // Class handling the common rendering stuff of ASTC cases.
226 class ASTCRenderer2D
227 {
228 public:
229     ASTCRenderer2D(Context &context, CompressedTexFormat format, uint32_t randomSeed);
230 
231     ~ASTCRenderer2D(void);
232 
233     void initialize(int minRenderWidth, int minRenderHeight, const Vec4 &colorScale, const Vec4 &colorBias);
234     void clear(void);
235 
236     void render(Surface &referenceDst, Surface &resultDst, const glu::Texture2D &texture,
237                 const tcu::TextureFormat &uncompressedFormat);
238 
getFormat(void) const239     CompressedTexFormat getFormat(void) const
240     {
241         return m_format;
242     }
getBlockSize(void) const243     IVec2 getBlockSize(void) const
244     {
245         return m_blockSize;
246     }
getASTCSupport(void) const247     ASTCSupportLevel getASTCSupport(void) const
248     {
249         DE_ASSERT(m_initialized);
250         return m_astcSupport;
251     }
252 
253 private:
254     Context &m_context;
255     TextureRenderer m_renderer;
256 
257     const CompressedTexFormat m_format;
258     const IVec2 m_blockSize;
259     ASTCSupportLevel m_astcSupport;
260     Vec4 m_colorScale;
261     Vec4 m_colorBias;
262 
263     de::Random m_rnd;
264 
265     bool m_initialized;
266 };
267 
268 } // namespace ASTCDecompressionCaseInternal
269 
270 using namespace ASTCDecompressionCaseInternal;
271 
ASTCRenderer2D(Context & context,CompressedTexFormat format,uint32_t randomSeed)272 ASTCRenderer2D::ASTCRenderer2D(Context &context, CompressedTexFormat format, uint32_t randomSeed)
273     : m_context(context)
274     , m_renderer(context.getRenderContext(), context.getTestContext().getLog(), glu::GLSL_VERSION_300_ES,
275                  glu::PRECISION_HIGHP)
276     , m_format(format)
277     , m_blockSize(tcu::getBlockPixelSize(format).xy())
278     , m_astcSupport(ASTCSUPPORTLEVEL_NONE)
279     , m_colorScale(-1.0f)
280     , m_colorBias(-1.0f)
281     , m_rnd(randomSeed)
282     , m_initialized(false)
283 {
284     DE_ASSERT(tcu::getBlockPixelSize(format).z() == 1);
285 }
286 
~ASTCRenderer2D(void)287 ASTCRenderer2D::~ASTCRenderer2D(void)
288 {
289     clear();
290 }
291 
initialize(int minRenderWidth,int minRenderHeight,const Vec4 & colorScale,const Vec4 & colorBias)292 void ASTCRenderer2D::initialize(int minRenderWidth, int minRenderHeight, const Vec4 &colorScale, const Vec4 &colorBias)
293 {
294     DE_ASSERT(!m_initialized);
295 
296     const tcu::RenderTarget &renderTarget = m_context.getRenderTarget();
297     TestLog &log                          = m_context.getTestContext().getLog();
298 
299     m_astcSupport = getASTCSupportLevel(m_context.getContextInfo(), m_context.getRenderContext());
300     m_colorScale  = colorScale;
301     m_colorBias   = colorBias;
302 
303     switch (m_astcSupport)
304     {
305     case ASTCSUPPORTLEVEL_NONE:
306         log << TestLog::Message << "No ASTC support detected" << TestLog::EndMessage;
307         throw tcu::NotSupportedError("ASTC not supported");
308     case ASTCSUPPORTLEVEL_LDR:
309         log << TestLog::Message << "LDR ASTC support detected" << TestLog::EndMessage;
310         break;
311     case ASTCSUPPORTLEVEL_HDR:
312         log << TestLog::Message << "HDR ASTC support detected" << TestLog::EndMessage;
313         break;
314     case ASTCSUPPORTLEVEL_FULL:
315         log << TestLog::Message << "Full ASTC support detected" << TestLog::EndMessage;
316         break;
317     default:
318         DE_ASSERT(false);
319     }
320 
321     if (renderTarget.getWidth() < minRenderWidth || renderTarget.getHeight() < minRenderHeight)
322         throw tcu::NotSupportedError("Render target must be at least " + de::toString(minRenderWidth) + "x" +
323                                      de::toString(minRenderHeight));
324 
325     log << TestLog::Message << "Using color scale and bias: result = raw * " << colorScale << " + " << colorBias
326         << TestLog::EndMessage;
327 
328     m_initialized = true;
329 }
330 
clear(void)331 void ASTCRenderer2D::clear(void)
332 {
333     m_renderer.clear();
334 }
335 
render(Surface & referenceDst,Surface & resultDst,const glu::Texture2D & texture,const tcu::TextureFormat & uncompressedFormat)336 void ASTCRenderer2D::render(Surface &referenceDst, Surface &resultDst, const glu::Texture2D &texture,
337                             const tcu::TextureFormat &uncompressedFormat)
338 {
339     DE_ASSERT(m_initialized);
340 
341     const glw::Functions &gl            = m_context.getRenderContext().getFunctions();
342     const glu::RenderContext &renderCtx = m_context.getRenderContext();
343     const int textureWidth              = texture.getRefTexture().getWidth();
344     const int textureHeight             = texture.getRefTexture().getHeight();
345     const RandomViewport viewport(renderCtx.getRenderTarget(), textureWidth, textureHeight, m_rnd.getUint32());
346     ReferenceParams renderParams(TEXTURETYPE_2D);
347     vector<float> texCoord;
348     computeQuadTexCoord2D(texCoord, Vec2(0.0f, 0.0f), Vec2(1.0f, 1.0f));
349 
350     renderParams.samplerType = getSamplerType(uncompressedFormat);
351     renderParams.sampler     = Sampler(Sampler::CLAMP_TO_EDGE, Sampler::CLAMP_TO_EDGE, Sampler::CLAMP_TO_EDGE,
352                                        Sampler::NEAREST, Sampler::NEAREST);
353     renderParams.colorScale  = m_colorScale;
354     renderParams.colorBias   = m_colorBias;
355 
356     // Setup base viewport.
357     gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
358 
359     // Bind to unit 0.
360     gl.activeTexture(GL_TEXTURE0);
361     gl.bindTexture(GL_TEXTURE_2D, texture.getGLTexture());
362 
363     // Setup nearest neighbor filtering and clamp-to-edge.
364     gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
365     gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
366     gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
367     gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
368 
369     GLU_EXPECT_NO_ERROR(gl.getError(), "Set texturing state");
370 
371     // Issue GL draws.
372     m_renderer.renderQuad(0, &texCoord[0], renderParams);
373     gl.flush();
374 
375     // Compute reference.
376     sampleTexture(tcu::SurfaceAccess(referenceDst, renderCtx.getRenderTarget().getPixelFormat()),
377                   texture.getRefTexture(), &texCoord[0], renderParams);
378 
379     // Read GL-rendered image.
380     glu::readPixels(renderCtx, viewport.x, viewport.y, resultDst.getAccess());
381 }
382 
ASTCBlockCase2D(Context & context,const char * name,const char * description,BlockTestType testType,CompressedTexFormat format)383 ASTCBlockCase2D::ASTCBlockCase2D(Context &context, const char *name, const char *description, BlockTestType testType,
384                                  CompressedTexFormat format)
385     : TestCase(context, name, description)
386     , m_testType(testType)
387     , m_format(format)
388     , m_numBlocksTested(0)
389     , m_currentIteration(0)
390     , m_renderer(new ASTCRenderer2D(context, format, deStringHash(getName())))
391 {
392     DE_ASSERT(!(tcu::isAstcSRGBFormat(m_format) &&
393                 tcu::astc::isBlockTestTypeHDROnly(
394                     m_testType))); // \note There is no HDR sRGB mode, so these would be redundant.
395 }
396 
~ASTCBlockCase2D(void)397 ASTCBlockCase2D::~ASTCBlockCase2D(void)
398 {
399     ASTCBlockCase2D::deinit();
400 }
401 
init(void)402 void ASTCBlockCase2D::init(void)
403 {
404     m_renderer->initialize(64, 64, tcu::astc::getBlockTestTypeColorScale(m_testType),
405                            tcu::astc::getBlockTestTypeColorBias(m_testType));
406 
407     generateBlockCaseTestData(m_blockData, m_format, m_testType);
408     DE_ASSERT(!m_blockData.empty());
409     DE_ASSERT(m_blockData.size() % tcu::astc::BLOCK_SIZE_BYTES == 0);
410 
411     m_testCtx.getLog() << TestLog::Message << "Total " << m_blockData.size() / tcu::astc::BLOCK_SIZE_BYTES
412                        << " blocks to test" << TestLog::EndMessage << TestLog::Message
413                        << "Note: Legitimate ASTC error pixels will be ignored when comparing to reference"
414                        << TestLog::EndMessage;
415 }
416 
deinit(void)417 void ASTCBlockCase2D::deinit(void)
418 {
419     m_renderer->clear();
420     m_blockData.clear();
421 }
422 
iterate(void)423 ASTCBlockCase2D::IterateResult ASTCBlockCase2D::iterate(void)
424 {
425     TestLog &log = m_testCtx.getLog();
426 
427     if (m_renderer->getASTCSupport() == ASTCSUPPORTLEVEL_LDR && tcu::astc::isBlockTestTypeHDROnly(m_testType))
428     {
429         log << TestLog::Message
430             << "Passing the case immediately, since only LDR support was detected and test only contains HDR blocks"
431             << TestLog::EndMessage;
432         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
433         return STOP;
434     }
435 
436     const IVec2 blockSize               = m_renderer->getBlockSize();
437     const int totalNumBlocks            = (int)m_blockData.size() / tcu::astc::BLOCK_SIZE_BYTES;
438     const int numXBlocksPerImage        = de::min(m_context.getRenderTarget().getWidth(), 512) / blockSize.x();
439     const int numYBlocksPerImage        = de::min(m_context.getRenderTarget().getHeight(), 512) / blockSize.y();
440     const int numBlocksPerImage         = numXBlocksPerImage * numYBlocksPerImage;
441     const int imageWidth                = numXBlocksPerImage * blockSize.x();
442     const int imageHeight               = numYBlocksPerImage * blockSize.y();
443     const int numBlocksRemaining        = totalNumBlocks - m_numBlocksTested;
444     const int curNumUsedBlocks          = de::min(numBlocksPerImage, numBlocksRemaining);
445     const int curNumUnusedBlocks        = numBlocksPerImage - curNumUsedBlocks;
446     const glu::RenderContext &renderCtx = m_context.getRenderContext();
447     const tcu::RGBA threshold           = renderCtx.getRenderTarget().getPixelFormat().getColorThreshold() +
448                                 (tcu::isAstcSRGBFormat(m_format) ? tcu::RGBA(2, 2, 2, 2) : tcu::RGBA(1, 1, 1, 1));
449     tcu::CompressedTexture compressed(m_format, imageWidth, imageHeight);
450 
451     if (m_currentIteration == 0)
452     {
453         log << TestLog::Message << "Using texture of size " << imageWidth << "x" << imageHeight << ", with "
454             << numXBlocksPerImage << " block columns and " << numYBlocksPerImage << " block rows "
455             << ", with block size " << blockSize.x() << "x" << blockSize.y() << TestLog::EndMessage;
456     }
457 
458     DE_ASSERT(compressed.getDataSize() == numBlocksPerImage * tcu::astc::BLOCK_SIZE_BYTES);
459     deMemcpy(compressed.getData(), &m_blockData[m_numBlocksTested * tcu::astc::BLOCK_SIZE_BYTES],
460              curNumUsedBlocks * tcu::astc::BLOCK_SIZE_BYTES);
461     if (curNumUsedBlocks > 1)
462         tcu::astc::generateDefaultVoidExtentBlocks(
463             (uint8_t *)compressed.getData() + curNumUsedBlocks * tcu::astc::BLOCK_SIZE_BYTES, curNumUnusedBlocks);
464 
465     // Create texture and render.
466 
467     const tcu::TexDecompressionParams::AstcMode decompressionMode =
468         (m_renderer->getASTCSupport() == ASTCSUPPORTLEVEL_LDR || tcu::isAstcSRGBFormat(m_format)) ?
469             tcu::TexDecompressionParams::ASTCMODE_LDR :
470             tcu::TexDecompressionParams::ASTCMODE_HDR;
471     glu::Texture2D texture(renderCtx, m_context.getContextInfo(), 1, &compressed,
472                            tcu::TexDecompressionParams(decompressionMode));
473     Surface renderedFrame(imageWidth, imageHeight);
474     Surface referenceFrame(imageWidth, imageHeight);
475 
476     m_renderer->render(referenceFrame, renderedFrame, texture, getUncompressedFormat(compressed.getFormat()));
477 
478     // Compare and log.
479     // \note Since a case can draw quite many images, only log the first iteration and failures.
480 
481     {
482         Surface errorMask;
483         IVec2 firstFailedBlockCoord;
484         IVec4 maxDiff;
485         const bool compareOk = compareBlockImages(referenceFrame, renderedFrame, threshold, blockSize, curNumUsedBlocks,
486                                                   firstFailedBlockCoord, errorMask, maxDiff);
487 
488         if (m_currentIteration == 0 || !compareOk)
489         {
490             const char *const imageSetName = "ComparisonResult";
491             const char *const imageSetDesc = "Comparison Result";
492 
493             {
494                 tcu::ScopedLogSection section(log, "Iteration " + de::toString(m_currentIteration),
495                                               "Blocks " + de::toString(m_numBlocksTested) + " to " +
496                                                   de::toString(m_numBlocksTested + curNumUsedBlocks - 1));
497 
498                 if (curNumUsedBlocks > 0)
499                     log << TestLog::Message << "Note: Only the first " << curNumUsedBlocks
500                         << " blocks in the image are relevant; rest " << curNumUnusedBlocks
501                         << " are dummies and not checked" << TestLog::EndMessage;
502 
503                 if (!compareOk)
504                 {
505                     log << TestLog::Message << "Image comparison failed: max difference = " << maxDiff
506                         << ", threshold = " << threshold << TestLog::EndMessage
507                         << TestLog::ImageSet(imageSetName, imageSetDesc)
508                         << TestLog::Image("Result", "Result", renderedFrame)
509                         << TestLog::Image("Reference", "Reference", referenceFrame)
510                         << TestLog::Image("ErrorMask", "Error mask", errorMask) << TestLog::EndImageSet;
511 
512                     const int blockNdx =
513                         m_numBlocksTested + firstFailedBlockCoord.y() * numXBlocksPerImage + firstFailedBlockCoord.x();
514                     DE_ASSERT(blockNdx < totalNumBlocks);
515 
516                     log << TestLog::Message << "First failed block at column " << firstFailedBlockCoord.x()
517                         << " and row " << firstFailedBlockCoord.y() << TestLog::EndMessage << TestLog::Message
518                         << "Data of first failed block:\n"
519                         << astcBlockDataStr(&m_blockData[blockNdx * tcu::astc::BLOCK_SIZE_BYTES])
520                         << TestLog::EndMessage;
521 
522                     m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
523                     return STOP;
524                 }
525                 else
526                 {
527                     log << TestLog::ImageSet(imageSetName, imageSetDesc)
528                         << TestLog::Image("Result", "Result", renderedFrame) << TestLog::EndImageSet;
529                 }
530             }
531 
532             if (m_numBlocksTested + curNumUsedBlocks < totalNumBlocks)
533                 log << TestLog::Message << "Note: not logging further images unless reference comparison fails"
534                     << TestLog::EndMessage;
535         }
536     }
537 
538     m_currentIteration++;
539     m_numBlocksTested += curNumUsedBlocks;
540 
541     if (m_numBlocksTested >= totalNumBlocks)
542     {
543         DE_ASSERT(m_numBlocksTested == totalNumBlocks);
544         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
545         return STOP;
546     }
547 
548     return CONTINUE;
549 }
550 
ASTCBlockSizeRemainderCase2D(Context & context,const char * name,const char * description,CompressedTexFormat format)551 ASTCBlockSizeRemainderCase2D::ASTCBlockSizeRemainderCase2D(Context &context, const char *name, const char *description,
552                                                            CompressedTexFormat format)
553     : TestCase(context, name, description)
554     , m_format(format)
555     , m_currentIteration(0)
556     , m_renderer(new ASTCRenderer2D(context, format, deStringHash(getName())))
557 {
558 }
559 
~ASTCBlockSizeRemainderCase2D(void)560 ASTCBlockSizeRemainderCase2D::~ASTCBlockSizeRemainderCase2D(void)
561 {
562     ASTCBlockSizeRemainderCase2D::deinit();
563 }
564 
init(void)565 void ASTCBlockSizeRemainderCase2D::init(void)
566 {
567     const IVec2 blockSize = m_renderer->getBlockSize();
568     m_renderer->initialize(MAX_NUM_BLOCKS_X * blockSize.x(), MAX_NUM_BLOCKS_Y * blockSize.y(), Vec4(1.0f), Vec4(0.0f));
569 }
570 
deinit(void)571 void ASTCBlockSizeRemainderCase2D::deinit(void)
572 {
573     m_renderer->clear();
574 }
575 
iterate(void)576 ASTCBlockSizeRemainderCase2D::IterateResult ASTCBlockSizeRemainderCase2D::iterate(void)
577 {
578     TestLog &log                        = m_testCtx.getLog();
579     const IVec2 blockSize               = m_renderer->getBlockSize();
580     const int curRemainderX             = m_currentIteration % blockSize.x();
581     const int curRemainderY             = m_currentIteration / blockSize.x();
582     const int imageWidth                = (MAX_NUM_BLOCKS_X - 1) * blockSize.x() + curRemainderX;
583     const int imageHeight               = (MAX_NUM_BLOCKS_Y - 1) * blockSize.y() + curRemainderY;
584     const int numBlocksX                = deDivRoundUp32(imageWidth, blockSize.x());
585     const int numBlocksY                = deDivRoundUp32(imageHeight, blockSize.y());
586     const int totalNumBlocks            = numBlocksX * numBlocksY;
587     const glu::RenderContext &renderCtx = m_context.getRenderContext();
588     const tcu::RGBA threshold           = renderCtx.getRenderTarget().getPixelFormat().getColorThreshold() +
589                                 (tcu::isAstcSRGBFormat(m_format) ? tcu::RGBA(2, 2, 2, 2) : tcu::RGBA(1, 1, 1, 1));
590     tcu::CompressedTexture compressed(m_format, imageWidth, imageHeight);
591 
592     DE_ASSERT(compressed.getDataSize() == totalNumBlocks * tcu::astc::BLOCK_SIZE_BYTES);
593     tcu::astc::generateDefaultNormalBlocks((uint8_t *)compressed.getData(), totalNumBlocks, blockSize.x(),
594                                            blockSize.y());
595 
596     // Create texture and render.
597 
598     const tcu::TexDecompressionParams::AstcMode decompressionMode =
599         (m_renderer->getASTCSupport() == ASTCSUPPORTLEVEL_LDR || tcu::isAstcSRGBFormat(m_format)) ?
600             tcu::TexDecompressionParams::ASTCMODE_LDR :
601             tcu::TexDecompressionParams::ASTCMODE_HDR;
602     Surface renderedFrame(imageWidth, imageHeight);
603     Surface referenceFrame(imageWidth, imageHeight);
604     glu::Texture2D texture(renderCtx, m_context.getContextInfo(), 1, &compressed,
605                            tcu::TexDecompressionParams(decompressionMode));
606 
607     m_renderer->render(referenceFrame, renderedFrame, texture, getUncompressedFormat(compressed.getFormat()));
608 
609     {
610         // Compare and log.
611 
612         tcu::ScopedLogSection section(log, "Iteration " + de::toString(m_currentIteration),
613                                       "Remainder " + de::toString(curRemainderX) + "x" + de::toString(curRemainderY));
614 
615         log << TestLog::Message << "Using texture of size " << imageWidth << "x" << imageHeight << " and block size "
616             << blockSize.x() << "x" << blockSize.y() << "; the x and y remainders are " << curRemainderX << " and "
617             << curRemainderY << " respectively" << TestLog::EndMessage;
618 
619         const bool compareOk = tcu::pixelThresholdCompare(
620             m_testCtx.getLog(), "ComparisonResult", "Comparison Result", referenceFrame, renderedFrame, threshold,
621             m_currentIteration == 0 ? tcu::COMPARE_LOG_RESULT : tcu::COMPARE_LOG_ON_ERROR);
622 
623         if (!compareOk)
624         {
625             m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
626             return STOP;
627         }
628     }
629 
630     if (m_currentIteration == 0 && m_currentIteration + 1 < blockSize.x() * blockSize.y())
631         log << TestLog::Message << "Note: not logging further images unless reference comparison fails"
632             << TestLog::EndMessage;
633 
634     m_currentIteration++;
635 
636     if (m_currentIteration >= blockSize.x() * blockSize.y())
637     {
638         DE_ASSERT(m_currentIteration == blockSize.x() * blockSize.y());
639         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
640         return STOP;
641     }
642     return CONTINUE;
643 }
644 
645 } // namespace Functional
646 } // namespace gles3
647 } // namespace deqp
648