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 gls::TextureTestUtil::ReferenceParams;
     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			(gls::TextureTestUtil::TEXTURETYPE_2D);
    335 	vector<float>					texCoord;
    336 	gls::TextureTestUtil::computeQuadTexCoord2D(texCoord, Vec2(0.0f, 0.0f), Vec2(1.0f, 1.0f));
    337 
    338 	renderParams.samplerType	= gls::TextureTestUtil::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(gls::TextureTestUtil::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 	glu::Texture2D	texture			(renderCtx, m_context.getContextInfo(), 1, &compressed, tcu::TexDecompressionParams((m_renderer->getASTCSupport() == ASTCSUPPORTLEVEL_LDR ? tcu::TexDecompressionParams::ASTCMODE_LDR : tcu::TexDecompressionParams::ASTCMODE_HDR)));
    449 	Surface			renderedFrame	(imageWidth, imageHeight);
    450 	Surface			referenceFrame	(imageWidth, imageHeight);
    451 
    452 	m_renderer->render(referenceFrame, renderedFrame, texture, getUncompressedFormat(compressed.getFormat()));
    453 
    454 	// Compare and log.
    455 	// \note Since a case can draw quite many images, only log the first iteration and failures.
    456 
    457 	{
    458 		Surface		errorMask;
    459 		IVec2		firstFailedBlockCoord;
    460 		IVec4		maxDiff;
    461 		const bool	compareOk = compareBlockImages(referenceFrame, renderedFrame, threshold, blockSize, curNumNonDummyBlocks, firstFailedBlockCoord, errorMask, maxDiff);
    462 
    463 		if (m_currentIteration == 0 || !compareOk)
    464 		{
    465 			const char* const		imageSetName	= "ComparisonResult";
    466 			const char* const		imageSetDesc	= "Comparison Result";
    467 
    468 			{
    469 				tcu::ScopedLogSection section(log, "Iteration " + de::toString(m_currentIteration),
    470 													"Blocks " + de::toString(m_numBlocksTested) + " to " + de::toString(m_numBlocksTested + curNumNonDummyBlocks - 1));
    471 
    472 				if (curNumDummyBlocks > 0)
    473 					log << TestLog::Message << "Note: Only the first " << curNumNonDummyBlocks << " blocks in the image are relevant; rest " << curNumDummyBlocks << " are dummies and not checked" << TestLog::EndMessage;
    474 
    475 				if (!compareOk)
    476 				{
    477 					log << TestLog::Message << "Image comparison failed: max difference = " << maxDiff << ", threshold = " << threshold << TestLog::EndMessage
    478 						<< TestLog::ImageSet(imageSetName, imageSetDesc)
    479 						<< TestLog::Image("Result",		"Result",		renderedFrame)
    480 						<< TestLog::Image("Reference",	"Reference",	referenceFrame)
    481 						<< TestLog::Image("ErrorMask",	"Error mask",	errorMask)
    482 						<< TestLog::EndImageSet;
    483 
    484 					const int blockNdx = m_numBlocksTested + firstFailedBlockCoord.y()*numXBlocksPerImage + firstFailedBlockCoord.x();
    485 					DE_ASSERT(blockNdx < totalNumBlocks);
    486 
    487 					log << TestLog::Message << "First failed block at column " << firstFailedBlockCoord.x() << " and row " << firstFailedBlockCoord.y() << TestLog::EndMessage
    488 						<< TestLog::Message << "Data of first failed block:\n" << astcBlockDataStr(&m_blockData[blockNdx*tcu::astc::BLOCK_SIZE_BYTES]) << TestLog::EndMessage;
    489 
    490 					m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
    491 					return STOP;
    492 				}
    493 				else
    494 				{
    495 					log << TestLog::ImageSet(imageSetName, imageSetDesc)
    496 						<< TestLog::Image("Result", "Result", renderedFrame)
    497 						<< TestLog::EndImageSet;
    498 				}
    499 			}
    500 
    501 			if (m_numBlocksTested + curNumNonDummyBlocks < totalNumBlocks)
    502 				log << TestLog::Message << "Note: not logging further images unless reference comparison fails" << TestLog::EndMessage;
    503 		}
    504 	}
    505 
    506 	m_currentIteration++;
    507 	m_numBlocksTested += curNumNonDummyBlocks;
    508 
    509 	if (m_numBlocksTested >= totalNumBlocks)
    510 	{
    511 		DE_ASSERT(m_numBlocksTested == totalNumBlocks);
    512 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
    513 		return STOP;
    514 	}
    515 
    516 	return CONTINUE;
    517 }
    518 
    519 
    520 
    521 ASTCBlockSizeRemainderCase2D::ASTCBlockSizeRemainderCase2D (Context&			context,
    522 															const char*			name,
    523 															const char*			description,
    524 															CompressedTexFormat	format)
    525 	: TestCase				(context, name, description)
    526 	, m_format				(format)
    527 	, m_currentIteration	(0)
    528 	, m_renderer			(new ASTCRenderer2D(context, format, deStringHash(getName())))
    529 {
    530 }
    531 
    532 ASTCBlockSizeRemainderCase2D::~ASTCBlockSizeRemainderCase2D (void)
    533 {
    534 	ASTCBlockSizeRemainderCase2D::deinit();
    535 }
    536 
    537 void ASTCBlockSizeRemainderCase2D::init (void)
    538 {
    539 	const IVec2 blockSize = m_renderer->getBlockSize();
    540 	m_renderer->initialize(MAX_NUM_BLOCKS_X*blockSize.x(), MAX_NUM_BLOCKS_Y*blockSize.y(), Vec4(1.0f), Vec4(0.0f));
    541 }
    542 
    543 void ASTCBlockSizeRemainderCase2D::deinit (void)
    544 {
    545 	m_renderer->clear();
    546 }
    547 
    548 ASTCBlockSizeRemainderCase2D::IterateResult ASTCBlockSizeRemainderCase2D::iterate (void)
    549 {
    550 	TestLog&						log						= m_testCtx.getLog();
    551 	const IVec2						blockSize				= m_renderer->getBlockSize();
    552 	const int						curRemainderX			= m_currentIteration % blockSize.x();
    553 	const int						curRemainderY			= m_currentIteration / blockSize.x();
    554 	const int						imageWidth				= (MAX_NUM_BLOCKS_X-1)*blockSize.x() + curRemainderX;
    555 	const int						imageHeight				= (MAX_NUM_BLOCKS_Y-1)*blockSize.y() + curRemainderY;
    556 	const int						numBlocksX				= deDivRoundUp32(imageWidth, blockSize.x());
    557 	const int						numBlocksY				= deDivRoundUp32(imageHeight, blockSize.y());
    558 	const int						totalNumBlocks			= numBlocksX * numBlocksY;
    559 	const glu::RenderContext&		renderCtx				= m_context.getRenderContext();
    560 	const tcu::RGBA					threshold				= renderCtx.getRenderTarget().getPixelFormat().getColorThreshold() + (tcu::isAstcSRGBFormat(m_format) ? tcu::RGBA(2,2,2,2) : tcu::RGBA(1,1,1,1));
    561 	tcu::CompressedTexture			compressed				(m_format, imageWidth, imageHeight);
    562 
    563 	DE_ASSERT(compressed.getDataSize() == totalNumBlocks*tcu::astc::BLOCK_SIZE_BYTES);
    564 	tcu::astc::generateDummyNormalBlocks((deUint8*)compressed.getData(), totalNumBlocks, blockSize.x(), blockSize.y());
    565 
    566 	// Create texture and render.
    567 
    568 	Surface			renderedFrame	(imageWidth, imageHeight);
    569 	Surface			referenceFrame	(imageWidth, imageHeight);
    570 	glu::Texture2D	texture			(renderCtx, m_context.getContextInfo(), 1, &compressed, tcu::TexDecompressionParams(m_renderer->getASTCSupport() == ASTCSUPPORTLEVEL_LDR ? tcu::TexDecompressionParams::ASTCMODE_LDR : tcu::TexDecompressionParams::ASTCMODE_HDR));
    571 
    572 	m_renderer->render(referenceFrame, renderedFrame, texture, getUncompressedFormat(compressed.getFormat()));
    573 
    574 	{
    575 		// Compare and log.
    576 
    577 		tcu::ScopedLogSection section(log, "Iteration " + de::toString(m_currentIteration),
    578 										   "Remainder " + de::toString(curRemainderX) + "x" + de::toString(curRemainderY));
    579 
    580 		log << TestLog::Message << "Using texture of size "
    581 								<< imageWidth << "x" << imageHeight
    582 								<< " and block size "
    583 								<< blockSize.x() << "x" << blockSize.y()
    584 								<< "; the x and y remainders are "
    585 								<< curRemainderX << " and " << curRemainderY << " respectively"
    586 			<< TestLog::EndMessage;
    587 
    588 		const bool compareOk = tcu::pixelThresholdCompare(m_testCtx.getLog(), "ComparisonResult", "Comparison Result", referenceFrame, renderedFrame, threshold,
    589 														  m_currentIteration == 0 ? tcu::COMPARE_LOG_RESULT : tcu::COMPARE_LOG_ON_ERROR);
    590 
    591 		if (!compareOk)
    592 		{
    593 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
    594 			return STOP;
    595 		}
    596 	}
    597 
    598 	if (m_currentIteration == 0 && m_currentIteration+1 < blockSize.x()*blockSize.y())
    599 		log << TestLog::Message << "Note: not logging further images unless reference comparison fails" << TestLog::EndMessage;
    600 
    601 	m_currentIteration++;
    602 
    603 	if (m_currentIteration >= blockSize.x()*blockSize.y())
    604 	{
    605 		DE_ASSERT(m_currentIteration == blockSize.x()*blockSize.y());
    606 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
    607 		return STOP;
    608 	}
    609 	return CONTINUE;
    610 }
    611 
    612 } // Functional
    613 } // gles3
    614 } // deqp
    615