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