Home | History | Annotate | Download | only in common
      1 /*-------------------------------------------------------------------------
      2  * drawElements Quality Program Tester Core
      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 Image comparison utilities.
     22  *//*--------------------------------------------------------------------*/
     23 
     24 #include "tcuImageCompare.hpp"
     25 #include "tcuSurface.hpp"
     26 #include "tcuFuzzyImageCompare.hpp"
     27 #include "tcuBilinearImageCompare.hpp"
     28 #include "tcuTestLog.hpp"
     29 #include "tcuVector.hpp"
     30 #include "tcuVectorUtil.hpp"
     31 #include "tcuRGBA.hpp"
     32 #include "tcuTexture.hpp"
     33 #include "tcuTextureUtil.hpp"
     34 #include "tcuFloat.hpp"
     35 
     36 #include <string.h>
     37 
     38 namespace tcu
     39 {
     40 
     41 namespace
     42 {
     43 
     44 void computeScaleAndBias (const ConstPixelBufferAccess& reference, const ConstPixelBufferAccess& result, tcu::Vec4& scale, tcu::Vec4& bias)
     45 {
     46 	Vec4 minVal;
     47 	Vec4 maxVal;
     48 	const float eps = 0.0001f;
     49 
     50 	{
     51 		Vec4 refMin;
     52 		Vec4 refMax;
     53 		estimatePixelValueRange(reference, refMin, refMax);
     54 
     55 		minVal	= refMin;
     56 		maxVal	= refMax;
     57 	}
     58 
     59 	{
     60 		Vec4 resMin;
     61 		Vec4 resMax;
     62 
     63 		estimatePixelValueRange(result, resMin, resMax);
     64 
     65 		minVal[0] = de::min(minVal[0], resMin[0]);
     66 		minVal[1] = de::min(minVal[1], resMin[1]);
     67 		minVal[2] = de::min(minVal[2], resMin[2]);
     68 		minVal[3] = de::min(minVal[3], resMin[3]);
     69 
     70 		maxVal[0] = de::max(maxVal[0], resMax[0]);
     71 		maxVal[1] = de::max(maxVal[1], resMax[1]);
     72 		maxVal[2] = de::max(maxVal[2], resMax[2]);
     73 		maxVal[3] = de::max(maxVal[3], resMax[3]);
     74 	}
     75 
     76 	for (int c = 0; c < 4; c++)
     77 	{
     78 		if (maxVal[c] - minVal[c] < eps)
     79 		{
     80 			scale[c]	= (maxVal[c] < eps) ? 1.0f : (1.0f / maxVal[c]);
     81 			bias[c]		= (c == 3) ? (1.0f - maxVal[c]*scale[c]) : (0.0f - minVal[c]*scale[c]);
     82 		}
     83 		else
     84 		{
     85 			scale[c]	= 1.0f / (maxVal[c] - minVal[c]);
     86 			bias[c]		= 0.0f - minVal[c]*scale[c];
     87 		}
     88 	}
     89 }
     90 
     91 static int findNumPositionDeviationFailingPixels (const PixelBufferAccess& errorMask, const ConstPixelBufferAccess& reference, const ConstPixelBufferAccess& result, const UVec4& threshold, const tcu::IVec3& maxPositionDeviation, bool acceptOutOfBoundsAsAnyValue)
     92 {
     93 	const tcu::IVec4	okColor				(0, 255, 0, 255);
     94 	const tcu::IVec4	errorColor			(255, 0, 0, 255);
     95 	const int			width				= reference.getWidth();
     96 	const int			height				= reference.getHeight();
     97 	const int			depth				= reference.getDepth();
     98 	int					numFailingPixels	= 0;
     99 
    100 	// Accept pixels "sampling" over the image bounds pixels since "taps" could be anything
    101 	const int			beginX				= (acceptOutOfBoundsAsAnyValue) ? (maxPositionDeviation.x()) : (0);
    102 	const int			beginY				= (acceptOutOfBoundsAsAnyValue) ? (maxPositionDeviation.y()) : (0);
    103 	const int			beginZ				= (acceptOutOfBoundsAsAnyValue) ? (maxPositionDeviation.z()) : (0);
    104 	const int			endX				= (acceptOutOfBoundsAsAnyValue) ? (width  - maxPositionDeviation.x()) : (width);
    105 	const int			endY				= (acceptOutOfBoundsAsAnyValue) ? (height - maxPositionDeviation.y()) : (height);
    106 	const int			endZ				= (acceptOutOfBoundsAsAnyValue) ? (depth  - maxPositionDeviation.z()) : (depth);
    107 
    108 	TCU_CHECK_INTERNAL(result.getWidth() == width && result.getHeight() == height && result.getDepth() == depth);
    109 	DE_ASSERT(endX > 0 && endY > 0 && endZ > 0);	// most likely a bug
    110 
    111 	tcu::clear(errorMask, okColor);
    112 
    113 	for (int z = beginZ; z < endZ; z++)
    114 	{
    115 		for (int y = beginY; y < endY; y++)
    116 		{
    117 			for (int x = beginX; x < endX; x++)
    118 			{
    119 				const IVec4	refPix = reference.getPixelInt(x, y, z);
    120 				const IVec4	cmpPix = result.getPixelInt(x, y, z);
    121 
    122 				// Exact match
    123 				{
    124 					const UVec4	diff = abs(refPix - cmpPix).cast<deUint32>();
    125 					const bool	isOk = boolAll(lessThanEqual(diff, threshold));
    126 
    127 					if (isOk)
    128 						continue;
    129 				}
    130 
    131 				// Find matching pixels for both result and reference pixel
    132 
    133 				{
    134 					bool pixelFoundForReference = false;
    135 
    136 					// Find deviated result pixel for reference
    137 
    138 					for (int sz = de::max(0, z - maxPositionDeviation.z()); sz <= de::min(depth  - 1, z + maxPositionDeviation.z()) && !pixelFoundForReference; ++sz)
    139 					for (int sy = de::max(0, y - maxPositionDeviation.y()); sy <= de::min(height - 1, y + maxPositionDeviation.y()) && !pixelFoundForReference; ++sy)
    140 					for (int sx = de::max(0, x - maxPositionDeviation.x()); sx <= de::min(width  - 1, x + maxPositionDeviation.x()) && !pixelFoundForReference; ++sx)
    141 					{
    142 						const IVec4	deviatedCmpPix	= result.getPixelInt(sx, sy, sz);
    143 						const UVec4	diff			= abs(refPix - deviatedCmpPix).cast<deUint32>();
    144 						const bool	isOk			= boolAll(lessThanEqual(diff, threshold));
    145 
    146 						pixelFoundForReference		= isOk;
    147 					}
    148 
    149 					if (!pixelFoundForReference)
    150 					{
    151 						errorMask.setPixel(errorColor, x, y, z);
    152 						++numFailingPixels;
    153 						continue;
    154 					}
    155 				}
    156 				{
    157 					bool pixelFoundForResult = false;
    158 
    159 					// Find deviated reference pixel for result
    160 
    161 					for (int sz = de::max(0, z - maxPositionDeviation.z()); sz <= de::min(depth  - 1, z + maxPositionDeviation.z()) && !pixelFoundForResult; ++sz)
    162 					for (int sy = de::max(0, y - maxPositionDeviation.y()); sy <= de::min(height - 1, y + maxPositionDeviation.y()) && !pixelFoundForResult; ++sy)
    163 					for (int sx = de::max(0, x - maxPositionDeviation.x()); sx <= de::min(width  - 1, x + maxPositionDeviation.x()) && !pixelFoundForResult; ++sx)
    164 					{
    165 						const IVec4	deviatedRefPix	= reference.getPixelInt(sx, sy, sz);
    166 						const UVec4	diff			= abs(cmpPix - deviatedRefPix).cast<deUint32>();
    167 						const bool	isOk			= boolAll(lessThanEqual(diff, threshold));
    168 
    169 						pixelFoundForResult			= isOk;
    170 					}
    171 
    172 					if (!pixelFoundForResult)
    173 					{
    174 						errorMask.setPixel(errorColor, x, y, z);
    175 						++numFailingPixels;
    176 						continue;
    177 					}
    178 				}
    179 			}
    180 		}
    181 	}
    182 
    183 	return numFailingPixels;
    184 }
    185 
    186 } // anonymous
    187 
    188 /*--------------------------------------------------------------------*//*!
    189  * \brief Fuzzy image comparison
    190  *
    191  * This image comparison is designed for comparing images rendered by 3D
    192  * graphics APIs such as OpenGL. The comparison allows small local differences
    193  * and compensates for aliasing.
    194  *
    195  * The algorithm first performs light blurring on both images and then
    196  * does per-pixel analysis. Pixels are compared to 3x3 bilinear surface
    197  * defined by adjecent pixels. This compensates for both 1-pixel deviations
    198  * in geometry and aliasing in texture data.
    199  *
    200  * Error metric is computed based on the differences. On valid images the
    201  * metric is usually <0.01. Thus good threshold values are in range 0.02 to
    202  * 0.05.
    203  *
    204  * On failure error image is generated that shows where the failing pixels
    205  * are.
    206  *
    207  * \note				Currently supports only UNORM_INT8 formats
    208  * \param log			Test log for results
    209  * \param imageSetName	Name for image set when logging results
    210  * \param imageSetDesc	Description for image set
    211  * \param reference		Reference image
    212  * \param result		Result image
    213  * \param threshold		Error metric threshold (good values are 0.02-0.05)
    214  * \param logMode		Logging mode
    215  * \return true if comparison passes, false otherwise
    216  *//*--------------------------------------------------------------------*/
    217 bool fuzzyCompare (TestLog& log, const char* imageSetName, const char* imageSetDesc, const ConstPixelBufferAccess& reference, const ConstPixelBufferAccess& result, float threshold, CompareLogMode logMode)
    218 {
    219 	FuzzyCompareParams	params;		// Use defaults.
    220 	TextureLevel		errorMask		(TextureFormat(TextureFormat::RGB, TextureFormat::UNORM_INT8), reference.getWidth(), reference.getHeight());
    221 	float				difference		= fuzzyCompare(params, reference, result, errorMask.getAccess());
    222 	bool				isOk			= difference <= threshold;
    223 	Vec4				pixelBias		(0.0f, 0.0f, 0.0f, 0.0f);
    224 	Vec4				pixelScale		(1.0f, 1.0f, 1.0f, 1.0f);
    225 
    226 	if (!isOk || logMode == COMPARE_LOG_EVERYTHING)
    227 	{
    228 		// Generate more accurate error mask.
    229 		params.maxSampleSkip = 0;
    230 		fuzzyCompare(params, reference, result, errorMask.getAccess());
    231 
    232 		if (result.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8) && reference.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8))
    233 			computeScaleAndBias(reference, result, pixelScale, pixelBias);
    234 
    235 		if (!isOk)
    236 			log << TestLog::Message << "Image comparison failed: difference = " << difference << ", threshold = " << threshold << TestLog::EndMessage;
    237 
    238 		log << TestLog::ImageSet(imageSetName, imageSetDesc)
    239 			<< TestLog::Image("Result",		"Result",		result,		pixelScale, pixelBias)
    240 			<< TestLog::Image("Reference",	"Reference",	reference,	pixelScale, pixelBias)
    241 			<< TestLog::Image("ErrorMask",	"Error mask",	errorMask)
    242 			<< TestLog::EndImageSet;
    243 	}
    244 	else if (logMode == COMPARE_LOG_RESULT)
    245 	{
    246 		if (result.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8))
    247 			computePixelScaleBias(result, pixelScale, pixelBias);
    248 
    249 		log << TestLog::ImageSet(imageSetName, imageSetDesc)
    250 			<< TestLog::Image("Result",		"Result",		result, pixelScale, pixelBias)
    251 			<< TestLog::EndImageSet;
    252 	}
    253 
    254 	return isOk;
    255 }
    256 
    257 /*--------------------------------------------------------------------*//*!
    258  * \brief Fuzzy image comparison
    259  *
    260  * This image comparison is designed for comparing images rendered by 3D
    261  * graphics APIs such as OpenGL. The comparison allows small local differences
    262  * and compensates for aliasing.
    263  *
    264  * The algorithm first performs light blurring on both images and then
    265  * does per-pixel analysis. Pixels are compared to 3x3 bilinear surface
    266  * defined by adjecent pixels. This compensates for both 1-pixel deviations
    267  * in geometry and aliasing in texture data.
    268  *
    269  * Error metric is computed based on the differences. On valid images the
    270  * metric is usually <0.01. Thus good threshold values are in range 0.02 to
    271  * 0.05.
    272  *
    273  * On failure error image is generated that shows where the failing pixels
    274  * are.
    275  *
    276  * \note				Currently supports only UNORM_INT8 formats
    277  * \param log			Test log for results
    278  * \param imageSetName	Name for image set when logging results
    279  * \param imageSetDesc	Description for image set
    280  * \param reference		Reference image
    281  * \param result		Result image
    282  * \param threshold		Error metric threshold (good values are 0.02-0.05)
    283  * \param logMode		Logging mode
    284  * \return true if comparison passes, false otherwise
    285  *//*--------------------------------------------------------------------*/
    286 bool fuzzyCompare (TestLog& log, const char* imageSetName, const char* imageSetDesc, const Surface& reference, const Surface& result, float threshold, CompareLogMode logMode)
    287 {
    288 	return fuzzyCompare(log, imageSetName, imageSetDesc, reference.getAccess(), result.getAccess(), threshold, logMode);
    289 }
    290 
    291 static deInt64 computeSquaredDiffSum (const ConstPixelBufferAccess& ref, const ConstPixelBufferAccess& cmp, const PixelBufferAccess& diffMask, int diffFactor)
    292 {
    293 	TCU_CHECK_INTERNAL(ref.getFormat().type == TextureFormat::UNORM_INT8 && cmp.getFormat().type == TextureFormat::UNORM_INT8);
    294 	DE_ASSERT(ref.getWidth() == cmp.getWidth() && ref.getWidth() == diffMask.getWidth());
    295 	DE_ASSERT(ref.getHeight() == cmp.getHeight() && ref.getHeight() == diffMask.getHeight());
    296 
    297 	deInt64 diffSum = 0;
    298 
    299 	for (int y = 0; y < cmp.getHeight(); y++)
    300 	{
    301 		for (int x = 0; x < cmp.getWidth(); x++)
    302 		{
    303 			IVec4	a		= ref.getPixelInt(x, y);
    304 			IVec4	b		= cmp.getPixelInt(x, y);
    305 			IVec4	diff	= abs(a - b);
    306 			int		sum		= diff.x() + diff.y() + diff.z() + diff.w();
    307 			int		sqSum	= diff.x()*diff.x() + diff.y()*diff.y() + diff.z()*diff.z() + diff.w()*diff.w();
    308 
    309 			diffMask.setPixel(tcu::RGBA(deClamp32(sum*diffFactor, 0, 255), deClamp32(255-sum*diffFactor, 0, 255), 0, 255).toVec(), x, y);
    310 
    311 			diffSum += (deInt64)sqSum;
    312 		}
    313 	}
    314 
    315 	return diffSum;
    316 }
    317 
    318 /*--------------------------------------------------------------------*//*!
    319  * \brief Per-pixel difference accuracy metric
    320  *
    321  * Computes accuracy metric using per-pixel differences between reference
    322  * and result images.
    323  *
    324  * \note					Supports only integer- and fixed-point formats
    325  * \param log				Test log for results
    326  * \param imageSetName		Name for image set when logging results
    327  * \param imageSetDesc		Description for image set
    328  * \param reference			Reference image
    329  * \param result			Result image
    330  * \param bestScoreDiff		Scaling factor
    331  * \param worstScoreDiff	Scaling factor
    332  * \param logMode			Logging mode
    333  * \return true if comparison passes, false otherwise
    334  *//*--------------------------------------------------------------------*/
    335 int measurePixelDiffAccuracy (TestLog& log, const char* imageSetName, const char* imageSetDesc, const ConstPixelBufferAccess& reference, const ConstPixelBufferAccess& result, int bestScoreDiff, int worstScoreDiff, CompareLogMode logMode)
    336 {
    337 	TextureLevel	diffMask		(TextureFormat(TextureFormat::RGB, TextureFormat::UNORM_INT8), reference.getWidth(), reference.getHeight());
    338 	int				diffFactor		= 8;
    339 	deInt64			squaredSum		= computeSquaredDiffSum(reference, result, diffMask.getAccess(), diffFactor);
    340 	float			sum				= deFloatSqrt((float)squaredSum);
    341 	int				score			= deClamp32(deFloorFloatToInt32(100.0f - (de::max(sum-(float)bestScoreDiff, 0.0f) / (float)(worstScoreDiff-bestScoreDiff))*100.0f), 0, 100);
    342 	const int		failThreshold	= 10;
    343 	Vec4			pixelBias		(0.0f, 0.0f, 0.0f, 0.0f);
    344 	Vec4			pixelScale		(1.0f, 1.0f, 1.0f, 1.0f);
    345 
    346 	if (logMode == COMPARE_LOG_EVERYTHING || score <= failThreshold)
    347 	{
    348 		if (result.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8) && reference.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8))
    349 			computeScaleAndBias(reference, result, pixelScale, pixelBias);
    350 
    351 		log << TestLog::ImageSet(imageSetName, imageSetDesc)
    352 			<< TestLog::Image("Result",		"Result",			result,		pixelScale, pixelBias)
    353 			<< TestLog::Image("Reference",	"Reference",		reference,	pixelScale, pixelBias)
    354 			<< TestLog::Image("DiffMask",	"Difference",		diffMask)
    355 			<< TestLog::EndImageSet;
    356 	}
    357 	else if (logMode == COMPARE_LOG_RESULT)
    358 	{
    359 		if (result.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8))
    360 			computePixelScaleBias(result, pixelScale, pixelBias);
    361 
    362 		log << TestLog::ImageSet(imageSetName, imageSetDesc)
    363 			<< TestLog::Image("Result",		"Result",			result,		pixelScale, pixelBias)
    364 			<< TestLog::EndImageSet;
    365 	}
    366 
    367 	if (logMode != COMPARE_LOG_ON_ERROR || score <= failThreshold)
    368 		log << TestLog::Integer("DiffSum", "Squared difference sum", "", QP_KEY_TAG_NONE, squaredSum)
    369 			<< TestLog::Integer("Score", "Score", "", QP_KEY_TAG_QUALITY, score);
    370 
    371 	return score;
    372 }
    373 
    374 /*--------------------------------------------------------------------*//*!
    375  * \brief Per-pixel difference accuracy metric
    376  *
    377  * Computes accuracy metric using per-pixel differences between reference
    378  * and result images.
    379  *
    380  * \note					Supports only integer- and fixed-point formats
    381  * \param log				Test log for results
    382  * \param imageSetName		Name for image set when logging results
    383  * \param imageSetDesc		Description for image set
    384  * \param reference			Reference image
    385  * \param result			Result image
    386  * \param bestScoreDiff		Scaling factor
    387  * \param worstScoreDiff	Scaling factor
    388  * \param logMode			Logging mode
    389  * \return true if comparison passes, false otherwise
    390  *//*--------------------------------------------------------------------*/
    391 int measurePixelDiffAccuracy (TestLog& log, const char* imageSetName, const char* imageSetDesc, const Surface& reference, const Surface& result, int bestScoreDiff, int worstScoreDiff, CompareLogMode logMode)
    392 {
    393 	return measurePixelDiffAccuracy(log, imageSetName, imageSetDesc, reference.getAccess(), result.getAccess(), bestScoreDiff, worstScoreDiff, logMode);
    394 }
    395 
    396 /*--------------------------------------------------------------------*//*!
    397  * Returns the index of float in a float space without denormals
    398  * so that:
    399  * 1) f(0.0) = 0
    400  * 2) f(-0.0) = 0
    401  * 3) f(b) = f(a) + 1  <==>  b = nextAfter(a)
    402  *
    403  * See computeFloatFlushRelaxedULPDiff for details
    404  *//*--------------------------------------------------------------------*/
    405 static deInt32 getPositionOfIEEEFloatWithoutDenormals (float x)
    406 {
    407 	DE_ASSERT(!deIsNaN(x)); // not sane
    408 
    409 	if (x == 0.0f)
    410 		return 0;
    411 	else if (x < 0.0f)
    412 		return -getPositionOfIEEEFloatWithoutDenormals(-x);
    413 	else
    414 	{
    415 		DE_ASSERT(x > 0.0f);
    416 
    417 		const tcu::Float32 f(x);
    418 
    419 		if (f.isDenorm())
    420 		{
    421 			// Denorms are flushed to zero
    422 			return 0;
    423 		}
    424 		else
    425 		{
    426 			// sign is 0, and it's a normal number. Natural position is its bit
    427 			// pattern but since we've collapsed the denorms, we must remove
    428 			// the gap here too to keep the float enumeration continuous.
    429 			//
    430 			// Denormals occupy one exponent pattern. Removing one from
    431 			// exponent should to the trick. Add one since the removed range
    432 			// contained one representable value, 0.
    433 			return (deInt32)(f.bits() - (1u << 23u) + 1u);
    434 		}
    435 	}
    436 }
    437 
    438 static deUint32 computeFloatFlushRelaxedULPDiff (float a, float b)
    439 {
    440 	if (deIsNaN(a) && deIsNaN(b))
    441 		return 0;
    442 	else if (deIsNaN(a) || deIsNaN(b))
    443 	{
    444 		return 0xFFFFFFFFu;
    445 	}
    446 	else
    447 	{
    448 		// Using the "definition 5" in Muller, Jean-Michel. "On the definition of ulp (x)" (2005)
    449 		// assuming a floating point space is IEEE single precision floating point space without
    450 		// denormals (and signed zeros).
    451 		const deInt32 aIndex = getPositionOfIEEEFloatWithoutDenormals(a);
    452 		const deInt32 bIndex = getPositionOfIEEEFloatWithoutDenormals(b);
    453 		return (deUint32)de::abs(aIndex - bIndex);
    454 	}
    455 }
    456 
    457 static tcu::UVec4 computeFlushRelaxedULPDiff (const tcu::Vec4& a, const tcu::Vec4& b)
    458 {
    459 	return tcu::UVec4(computeFloatFlushRelaxedULPDiff(a.x(), b.x()),
    460 					  computeFloatFlushRelaxedULPDiff(a.y(), b.y()),
    461 					  computeFloatFlushRelaxedULPDiff(a.z(), b.z()),
    462 					  computeFloatFlushRelaxedULPDiff(a.w(), b.w()));
    463 }
    464 
    465 /*--------------------------------------------------------------------*//*!
    466  * \brief Per-pixel threshold-based comparison
    467  *
    468  * This compare computes per-pixel differences between result and reference
    469  * image. Comparison fails if any pixels exceed the given threshold value.
    470  *
    471  * This comparison uses ULP (units in last place) metric for computing the
    472  * difference between floating-point values and thus this function can
    473  * be used only for comparing floating-point texture data. In ULP calculation
    474  * the denormal numbers are allowed to be flushed to zero.
    475  *
    476  * On failure error image is generated that shows where the failing pixels
    477  * are.
    478  *
    479  * \param log			Test log for results
    480  * \param imageSetName	Name for image set when logging results
    481  * \param imageSetDesc	Description for image set
    482  * \param reference		Reference image
    483  * \param result		Result image
    484  * \param threshold		Maximum allowed difference
    485  * \param logMode		Logging mode
    486  * \return true if comparison passes, false otherwise
    487  *//*--------------------------------------------------------------------*/
    488 bool floatUlpThresholdCompare (TestLog& log, const char* imageSetName, const char* imageSetDesc, const ConstPixelBufferAccess& reference, const ConstPixelBufferAccess& result, const UVec4& threshold, CompareLogMode logMode)
    489 {
    490 	int					width				= reference.getWidth();
    491 	int					height				= reference.getHeight();
    492 	int					depth				= reference.getDepth();
    493 	TextureLevel		errorMaskStorage	(TextureFormat(TextureFormat::RGB, TextureFormat::UNORM_INT8), width, height, depth);
    494 	PixelBufferAccess	errorMask			= errorMaskStorage.getAccess();
    495 	UVec4				maxDiff				(0, 0, 0, 0);
    496 	Vec4				pixelBias			(0.0f, 0.0f, 0.0f, 0.0f);
    497 	Vec4				pixelScale			(1.0f, 1.0f, 1.0f, 1.0f);
    498 
    499 	TCU_CHECK(result.getWidth() == width && result.getHeight() == height && result.getDepth() == depth);
    500 
    501 	for (int z = 0; z < depth; z++)
    502 	{
    503 		for (int y = 0; y < height; y++)
    504 		{
    505 			for (int x = 0; x < width; x++)
    506 			{
    507 				const Vec4	refPix	= reference.getPixel(x, y, z);
    508 				const Vec4	cmpPix	= result.getPixel(x, y, z);
    509 				const UVec4	diff	= computeFlushRelaxedULPDiff(refPix, cmpPix);
    510 				const bool	isOk	= boolAll(lessThanEqual(diff, threshold));
    511 
    512 				maxDiff = max(maxDiff, diff);
    513 
    514 				errorMask.setPixel(isOk ? Vec4(0.0f, 1.0f, 0.0f, 1.0f) : Vec4(1.0f, 0.0f, 0.0f, 1.0f), x, y, z);
    515 			}
    516 		}
    517 	}
    518 
    519 	bool compareOk = boolAll(lessThanEqual(maxDiff, threshold));
    520 
    521 	if (!compareOk || logMode == COMPARE_LOG_EVERYTHING)
    522 	{
    523 		// All formats except normalized unsigned fixed point ones need remapping in order to fit into unorm channels in logged images.
    524 		if (tcu::getTextureChannelClass(reference.getFormat().type)	!= tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT ||
    525 			tcu::getTextureChannelClass(result.getFormat().type)	!= tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT)
    526 		{
    527 			computeScaleAndBias(reference, result, pixelScale, pixelBias);
    528 			log << TestLog::Message << "Result and reference images are normalized with formula p * " << pixelScale << " + " << pixelBias << TestLog::EndMessage;
    529 		}
    530 
    531 		if (!compareOk)
    532 			log << TestLog::Message << "Image comparison failed: max difference = " << maxDiff << ", threshold = " << threshold << TestLog::EndMessage;
    533 
    534 		log << TestLog::ImageSet(imageSetName, imageSetDesc)
    535 			<< TestLog::Image("Result",		"Result",		result,		pixelScale, pixelBias)
    536 			<< TestLog::Image("Reference",	"Reference",	reference,	pixelScale, pixelBias)
    537 			<< TestLog::Image("ErrorMask",	"Error mask",	errorMask)
    538 			<< TestLog::EndImageSet;
    539 	}
    540 	else if (logMode == COMPARE_LOG_RESULT)
    541 	{
    542 		if (result.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8))
    543 			computePixelScaleBias(result, pixelScale, pixelBias);
    544 
    545 		log << TestLog::ImageSet(imageSetName, imageSetDesc)
    546 			<< TestLog::Image("Result",		"Result",		result,		pixelScale, pixelBias)
    547 			<< TestLog::EndImageSet;
    548 	}
    549 
    550 	return compareOk;
    551 }
    552 
    553 /*--------------------------------------------------------------------*//*!
    554  * \brief Per-pixel threshold-based comparison
    555  *
    556  * This compare computes per-pixel differences between result and reference
    557  * image. Comparison fails if any pixels exceed the given threshold value.
    558  *
    559  * This comparison can be used for floating-point and fixed-point formats.
    560  * Difference is computed in floating-point space.
    561  *
    562  * On failure an error image is generated that shows where the failing
    563  * pixels are.
    564  *
    565  * \param log			Test log for results
    566  * \param imageSetName	Name for image set when logging results
    567  * \param imageSetDesc	Description for image set
    568  * \param reference		Reference image
    569  * \param result		Result image
    570  * \param threshold		Maximum allowed difference
    571  * \param logMode		Logging mode
    572  * \return true if comparison passes, false otherwise
    573  *//*--------------------------------------------------------------------*/
    574 bool floatThresholdCompare (TestLog& log, const char* imageSetName, const char* imageSetDesc, const ConstPixelBufferAccess& reference, const ConstPixelBufferAccess& result, const Vec4& threshold, CompareLogMode logMode)
    575 {
    576 	int					width				= reference.getWidth();
    577 	int					height				= reference.getHeight();
    578 	int					depth				= reference.getDepth();
    579 	TextureLevel		errorMaskStorage	(TextureFormat(TextureFormat::RGB, TextureFormat::UNORM_INT8), width, height, depth);
    580 	PixelBufferAccess	errorMask			= errorMaskStorage.getAccess();
    581 	Vec4				maxDiff				(0.0f, 0.0f, 0.0f, 0.0f);
    582 	Vec4				pixelBias			(0.0f, 0.0f, 0.0f, 0.0f);
    583 	Vec4				pixelScale			(1.0f, 1.0f, 1.0f, 1.0f);
    584 
    585 	TCU_CHECK_INTERNAL(result.getWidth() == width && result.getHeight() == height && result.getDepth() == depth);
    586 
    587 	for (int z = 0; z < depth; z++)
    588 	{
    589 		for (int y = 0; y < height; y++)
    590 		{
    591 			for (int x = 0; x < width; x++)
    592 			{
    593 				Vec4	refPix		= reference.getPixel(x, y, z);
    594 				Vec4	cmpPix		= result.getPixel(x, y, z);
    595 
    596 				Vec4	diff		= abs(refPix - cmpPix);
    597 				bool	isOk		= boolAll(lessThanEqual(diff, threshold));
    598 
    599 				maxDiff = max(maxDiff, diff);
    600 
    601 				errorMask.setPixel(isOk ? Vec4(0.0f, 1.0f, 0.0f, 1.0f) : Vec4(1.0f, 0.0f, 0.0f, 1.0f), x, y, z);
    602 			}
    603 		}
    604 	}
    605 
    606 	bool compareOk = boolAll(lessThanEqual(maxDiff, threshold));
    607 
    608 	if (!compareOk || logMode == COMPARE_LOG_EVERYTHING)
    609 	{
    610 		// All formats except normalized unsigned fixed point ones need remapping in order to fit into unorm channels in logged images.
    611 		if (tcu::getTextureChannelClass(reference.getFormat().type)	!= tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT ||
    612 			tcu::getTextureChannelClass(result.getFormat().type)	!= tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT)
    613 		{
    614 			computeScaleAndBias(reference, result, pixelScale, pixelBias);
    615 			log << TestLog::Message << "Result and reference images are normalized with formula p * " << pixelScale << " + " << pixelBias << TestLog::EndMessage;
    616 		}
    617 
    618 		if (!compareOk)
    619 			log << TestLog::Message << "Image comparison failed: max difference = " << maxDiff << ", threshold = " << threshold << TestLog::EndMessage;
    620 
    621 		log << TestLog::ImageSet(imageSetName, imageSetDesc)
    622 			<< TestLog::Image("Result",		"Result",		result,		pixelScale, pixelBias)
    623 			<< TestLog::Image("Reference",	"Reference",	reference,	pixelScale, pixelBias)
    624 			<< TestLog::Image("ErrorMask",	"Error mask",	errorMask)
    625 			<< TestLog::EndImageSet;
    626 	}
    627 	else if (logMode == COMPARE_LOG_RESULT)
    628 	{
    629 		if (result.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8))
    630 			computePixelScaleBias(result, pixelScale, pixelBias);
    631 
    632 		log << TestLog::ImageSet(imageSetName, imageSetDesc)
    633 			<< TestLog::Image("Result",		"Result",		result,		pixelScale, pixelBias)
    634 			<< TestLog::EndImageSet;
    635 	}
    636 
    637 	return compareOk;
    638 }
    639 
    640 /*--------------------------------------------------------------------*//*!
    641  * \brief Per-pixel threshold-based comparison
    642  *
    643  * This compare computes per-pixel differences between result and reference
    644  * color. Comparison fails if any pixels exceed the given threshold value.
    645  *
    646  * This comparison can be used for floating-point and fixed-point formats.
    647  * Difference is computed in floating-point space.
    648  *
    649  * On failure an error image is generated that shows where the failing
    650  * pixels are.
    651  *
    652  * \param log			Test log for results
    653  * \param imageSetName	Name for image set when logging results
    654  * \param imageSetDesc	Description for image set
    655  * \param reference		Reference color
    656  * \param result		Result image
    657  * \param threshold		Maximum allowed difference
    658  * \param logMode		Logging mode
    659  * \return true if comparison passes, false otherwise
    660  *//*--------------------------------------------------------------------*/
    661 bool floatThresholdCompare (TestLog& log, const char* imageSetName, const char* imageSetDesc, const Vec4& reference, const ConstPixelBufferAccess& result, const Vec4& threshold, CompareLogMode logMode)
    662 {
    663 	const int			width				= result.getWidth();
    664 	const int			height				= result.getHeight();
    665 	const int			depth				= result.getDepth();
    666 
    667 	TextureLevel		errorMaskStorage	(TextureFormat(TextureFormat::RGB, TextureFormat::UNORM_INT8), width, height, depth);
    668 	PixelBufferAccess	errorMask			= errorMaskStorage.getAccess();
    669 	Vec4				maxDiff				(0.0f, 0.0f, 0.0f, 0.0f);
    670 	Vec4				pixelBias			(0.0f, 0.0f, 0.0f, 0.0f);
    671 	Vec4				pixelScale			(1.0f, 1.0f, 1.0f, 1.0f);
    672 
    673 	for (int z = 0; z < depth; z++)
    674 	{
    675 		for (int y = 0; y < height; y++)
    676 		{
    677 			for (int x = 0; x < width; x++)
    678 			{
    679 				const Vec4	cmpPix		= result.getPixel(x, y, z);
    680 				const Vec4	diff		= abs(reference - cmpPix);
    681 				const bool	isOk		= boolAll(lessThanEqual(diff, threshold));
    682 
    683 				maxDiff = max(maxDiff, diff);
    684 
    685 				errorMask.setPixel(isOk ? Vec4(0.0f, 1.0f, 0.0f, 1.0f) : Vec4(1.0f, 0.0f, 0.0f, 1.0f), x, y, z);
    686 			}
    687 		}
    688 	}
    689 
    690 	bool compareOk = boolAll(lessThanEqual(maxDiff, threshold));
    691 
    692 	if (!compareOk || logMode == COMPARE_LOG_EVERYTHING)
    693 	{
    694 		// All formats except normalized unsigned fixed point ones need remapping in order to fit into unorm channels in logged images.
    695 		if (tcu::getTextureChannelClass(result.getFormat().type) != tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT)
    696 		{
    697 			computeScaleAndBias(result, result, pixelScale, pixelBias);
    698 			log << TestLog::Message << "Result image is normalized with formula p * " << pixelScale << " + " << pixelBias << TestLog::EndMessage;
    699 		}
    700 
    701 		if (!compareOk)
    702 			log << TestLog::Message << "Image comparison failed: max difference = " << maxDiff << ", threshold = " << threshold << ", reference = " << reference << TestLog::EndMessage;
    703 
    704 		log << TestLog::ImageSet(imageSetName, imageSetDesc)
    705 			<< TestLog::Image("Result",		"Result",		result,		pixelScale, pixelBias)
    706 			<< TestLog::Image("ErrorMask",	"Error mask",	errorMask)
    707 			<< TestLog::EndImageSet;
    708 	}
    709 	else if (logMode == COMPARE_LOG_RESULT)
    710 	{
    711 		if (result.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8))
    712 			computePixelScaleBias(result, pixelScale, pixelBias);
    713 
    714 		log << TestLog::ImageSet(imageSetName, imageSetDesc)
    715 			<< TestLog::Image("Result",		"Result",		result,		pixelScale, pixelBias)
    716 			<< TestLog::EndImageSet;
    717 	}
    718 
    719 	return compareOk;
    720 }
    721 
    722 /*--------------------------------------------------------------------*//*!
    723  * \brief Per-pixel threshold-based comparison
    724  *
    725  * This compare computes per-pixel differences between result and reference
    726  * image. Comparison fails if any pixels exceed the given threshold value.
    727  *
    728  * This comparison can be used for integer- and fixed-point texture formats.
    729  * Difference is computed in integer space.
    730  *
    731  * On failure error image is generated that shows where the failing pixels
    732  * are.
    733  *
    734  * \param log			Test log for results
    735  * \param imageSetName	Name for image set when logging results
    736  * \param imageSetDesc	Description for image set
    737  * \param reference		Reference image
    738  * \param result		Result image
    739  * \param threshold		Maximum allowed difference
    740  * \param logMode		Logging mode
    741  * \return true if comparison passes, false otherwise
    742  *//*--------------------------------------------------------------------*/
    743 bool intThresholdCompare (TestLog& log, const char* imageSetName, const char* imageSetDesc, const ConstPixelBufferAccess& reference, const ConstPixelBufferAccess& result, const UVec4& threshold, CompareLogMode logMode)
    744 {
    745 	int					width				= reference.getWidth();
    746 	int					height				= reference.getHeight();
    747 	int					depth				= reference.getDepth();
    748 	TextureLevel		errorMaskStorage	(TextureFormat(TextureFormat::RGB, TextureFormat::UNORM_INT8), width, height, depth);
    749 	PixelBufferAccess	errorMask			= errorMaskStorage.getAccess();
    750 	UVec4				maxDiff				(0, 0, 0, 0);
    751 	Vec4				pixelBias			(0.0f, 0.0f, 0.0f, 0.0f);
    752 	Vec4				pixelScale			(1.0f, 1.0f, 1.0f, 1.0f);
    753 
    754 	TCU_CHECK_INTERNAL(result.getWidth() == width && result.getHeight() == height && result.getDepth() == depth);
    755 
    756 	for (int z = 0; z < depth; z++)
    757 	{
    758 		for (int y = 0; y < height; y++)
    759 		{
    760 			for (int x = 0; x < width; x++)
    761 			{
    762 				IVec4	refPix		= reference.getPixelInt(x, y, z);
    763 				IVec4	cmpPix		= result.getPixelInt(x, y, z);
    764 
    765 				UVec4	diff		= abs(refPix - cmpPix).cast<deUint32>();
    766 				bool	isOk		= boolAll(lessThanEqual(diff, threshold));
    767 
    768 				maxDiff = max(maxDiff, diff);
    769 
    770 				errorMask.setPixel(isOk ? IVec4(0, 0xff, 0, 0xff) : IVec4(0xff, 0, 0, 0xff), x, y, z);
    771 			}
    772 		}
    773 	}
    774 
    775 	bool compareOk = boolAll(lessThanEqual(maxDiff, threshold));
    776 
    777 	if (!compareOk || logMode == COMPARE_LOG_EVERYTHING)
    778 	{
    779 		// All formats except normalized unsigned fixed point ones need remapping in order to fit into unorm channels in logged images.
    780 		if (tcu::getTextureChannelClass(reference.getFormat().type)	!= tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT ||
    781 			tcu::getTextureChannelClass(result.getFormat().type)	!= tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT)
    782 		{
    783 			computeScaleAndBias(reference, result, pixelScale, pixelBias);
    784 			log << TestLog::Message << "Result and reference images are normalized with formula p * " << pixelScale << " + " << pixelBias << TestLog::EndMessage;
    785 		}
    786 
    787 		if (!compareOk)
    788 			log << TestLog::Message << "Image comparison failed: max difference = " << maxDiff << ", threshold = " << threshold << TestLog::EndMessage;
    789 
    790 		log << TestLog::ImageSet(imageSetName, imageSetDesc)
    791 			<< TestLog::Image("Result",		"Result",		result,		pixelScale, pixelBias)
    792 			<< TestLog::Image("Reference",	"Reference",	reference,	pixelScale, pixelBias)
    793 			<< TestLog::Image("ErrorMask",	"Error mask",	errorMask)
    794 			<< TestLog::EndImageSet;
    795 	}
    796 	else if (logMode == COMPARE_LOG_RESULT)
    797 	{
    798 		if (result.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8))
    799 			computePixelScaleBias(result, pixelScale, pixelBias);
    800 
    801 		log << TestLog::ImageSet(imageSetName, imageSetDesc)
    802 			<< TestLog::Image("Result",		"Result",		result,		pixelScale, pixelBias)
    803 			<< TestLog::EndImageSet;
    804 	}
    805 
    806 	return compareOk;
    807 }
    808 
    809 /*--------------------------------------------------------------------*//*!
    810  * \brief Per-pixel threshold-based deviation-ignoring comparison
    811  *
    812  * This compare computes per-pixel differences between result and reference
    813  * image. Comparison fails if there is no pixel matching the given threshold
    814  * value in the search volume.
    815  *
    816  * If the search volume contains out-of-bounds pixels, comparison can be set
    817  * to either ignore these pixels in search or to accept any pixel that has
    818  * out-of-bounds pixels in its search volume.
    819  *
    820  * This comparison can be used for integer- and fixed-point texture formats.
    821  * Difference is computed in integer space.
    822  *
    823  * On failure error image is generated that shows where the failing pixels
    824  * are.
    825  *
    826  * \param log							Test log for results
    827  * \param imageSetName					Name for image set when logging results
    828  * \param imageSetDesc					Description for image set
    829  * \param reference						Reference image
    830  * \param result						Result image
    831  * \param threshold						Maximum allowed difference
    832  * \param maxPositionDeviation			Maximum allowed distance in the search
    833  *										volume.
    834  * \param acceptOutOfBoundsAsAnyValue	Accept any pixel in the boundary region
    835  * \param logMode						Logging mode
    836  * \return true if comparison passes, false otherwise
    837  *//*--------------------------------------------------------------------*/
    838 bool intThresholdPositionDeviationCompare (TestLog& log, const char* imageSetName, const char* imageSetDesc, const ConstPixelBufferAccess& reference, const ConstPixelBufferAccess& result, const UVec4& threshold, const tcu::IVec3& maxPositionDeviation, bool acceptOutOfBoundsAsAnyValue, CompareLogMode logMode)
    839 {
    840 	const int			width				= reference.getWidth();
    841 	const int			height				= reference.getHeight();
    842 	const int			depth				= reference.getDepth();
    843 	TextureLevel		errorMaskStorage	(TextureFormat(TextureFormat::RGB, TextureFormat::UNORM_INT8), width, height, depth);
    844 	PixelBufferAccess	errorMask			= errorMaskStorage.getAccess();
    845 	const int			numFailingPixels	= findNumPositionDeviationFailingPixels(errorMask, reference, result, threshold, maxPositionDeviation, acceptOutOfBoundsAsAnyValue);
    846 	const bool			compareOk			= numFailingPixels == 0;
    847 	Vec4				pixelBias			(0.0f, 0.0f, 0.0f, 0.0f);
    848 	Vec4				pixelScale			(1.0f, 1.0f, 1.0f, 1.0f);
    849 
    850 	if (!compareOk || logMode == COMPARE_LOG_EVERYTHING)
    851 	{
    852 		// All formats except normalized unsigned fixed point ones need remapping in order to fit into unorm channels in logged images.
    853 		if (tcu::getTextureChannelClass(reference.getFormat().type)	!= tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT ||
    854 			tcu::getTextureChannelClass(result.getFormat().type)	!= tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT)
    855 		{
    856 			computeScaleAndBias(reference, result, pixelScale, pixelBias);
    857 			log << TestLog::Message << "Result and reference images are normalized with formula p * " << pixelScale << " + " << pixelBias << TestLog::EndMessage;
    858 		}
    859 
    860 		if (!compareOk)
    861 			log	<< TestLog::Message
    862 				<< "Image comparison failed:\n"
    863 				<< "\tallowed position deviation = " << maxPositionDeviation << "\n"
    864 				<< "\tcolor threshold = " << threshold
    865 				<< TestLog::EndMessage;
    866 
    867 		log << TestLog::ImageSet(imageSetName, imageSetDesc)
    868 			<< TestLog::Image("Result",		"Result",		result,		pixelScale, pixelBias)
    869 			<< TestLog::Image("Reference",	"Reference",	reference,	pixelScale, pixelBias)
    870 			<< TestLog::Image("ErrorMask",	"Error mask",	errorMask)
    871 			<< TestLog::EndImageSet;
    872 	}
    873 	else if (logMode == COMPARE_LOG_RESULT)
    874 	{
    875 		if (result.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8))
    876 			computePixelScaleBias(result, pixelScale, pixelBias);
    877 
    878 		log << TestLog::ImageSet(imageSetName, imageSetDesc)
    879 			<< TestLog::Image("Result",		"Result",		result,		pixelScale, pixelBias)
    880 			<< TestLog::EndImageSet;
    881 	}
    882 
    883 	return compareOk;
    884 }
    885 
    886 /*--------------------------------------------------------------------*//*!
    887  * \brief Per-pixel threshold-based deviation-ignoring comparison
    888  *
    889  * This compare computes per-pixel differences between result and reference
    890  * image. Pixel fails the test if there is no pixel matching the given
    891  * threshold value in the search volume. Comparison fails if the number of
    892  * failing pixels exceeds the given limit.
    893  *
    894  * If the search volume contains out-of-bounds pixels, comparison can be set
    895  * to either ignore these pixels in search or to accept any pixel that has
    896  * out-of-bounds pixels in its search volume.
    897  *
    898  * This comparison can be used for integer- and fixed-point texture formats.
    899  * Difference is computed in integer space.
    900  *
    901  * On failure error image is generated that shows where the failing pixels
    902  * are.
    903  *
    904  * \param log							Test log for results
    905  * \param imageSetName					Name for image set when logging results
    906  * \param imageSetDesc					Description for image set
    907  * \param reference						Reference image
    908  * \param result						Result image
    909  * \param threshold						Maximum allowed difference
    910  * \param maxPositionDeviation			Maximum allowed distance in the search
    911  *										volume.
    912  * \param acceptOutOfBoundsAsAnyValue	Accept any pixel in the boundary region
    913  * \param maxAllowedFailingPixels		Maximum number of failing pixels
    914  * \param logMode						Logging mode
    915  * \return true if comparison passes, false otherwise
    916  *//*--------------------------------------------------------------------*/
    917 bool intThresholdPositionDeviationErrorThresholdCompare (TestLog& log, const char* imageSetName, const char* imageSetDesc, const ConstPixelBufferAccess& reference, const ConstPixelBufferAccess& result, const UVec4& threshold, const tcu::IVec3& maxPositionDeviation, bool acceptOutOfBoundsAsAnyValue, int maxAllowedFailingPixels, CompareLogMode logMode)
    918 {
    919 	const int			width				= reference.getWidth();
    920 	const int			height				= reference.getHeight();
    921 	const int			depth				= reference.getDepth();
    922 	TextureLevel		errorMaskStorage	(TextureFormat(TextureFormat::RGB, TextureFormat::UNORM_INT8), width, height, depth);
    923 	PixelBufferAccess	errorMask			= errorMaskStorage.getAccess();
    924 	const int			numFailingPixels	= findNumPositionDeviationFailingPixels(errorMask, reference, result, threshold, maxPositionDeviation, acceptOutOfBoundsAsAnyValue);
    925 	const bool			compareOk			= numFailingPixels <= maxAllowedFailingPixels;
    926 	Vec4				pixelBias			(0.0f, 0.0f, 0.0f, 0.0f);
    927 	Vec4				pixelScale			(1.0f, 1.0f, 1.0f, 1.0f);
    928 
    929 	if (!compareOk || logMode == COMPARE_LOG_EVERYTHING)
    930 	{
    931 		// All formats except normalized unsigned fixed point ones need remapping in order to fit into unorm channels in logged images.
    932 		if (tcu::getTextureChannelClass(reference.getFormat().type)	!= tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT ||
    933 			tcu::getTextureChannelClass(result.getFormat().type)	!= tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT)
    934 		{
    935 			computeScaleAndBias(reference, result, pixelScale, pixelBias);
    936 			log << TestLog::Message << "Result and reference images are normalized with formula p * " << pixelScale << " + " << pixelBias << TestLog::EndMessage;
    937 		}
    938 
    939 		if (!compareOk)
    940 			log	<< TestLog::Message
    941 				<< "Image comparison failed:\n"
    942 				<< "\tallowed position deviation = " << maxPositionDeviation << "\n"
    943 				<< "\tcolor threshold = " << threshold
    944 				<< TestLog::EndMessage;
    945 		log << TestLog::Message << "Number of failing pixels = " << numFailingPixels << ", max allowed = " << maxAllowedFailingPixels << TestLog::EndMessage;
    946 
    947 		log << TestLog::ImageSet(imageSetName, imageSetDesc)
    948 			<< TestLog::Image("Result",		"Result",		result,		pixelScale, pixelBias)
    949 			<< TestLog::Image("Reference",	"Reference",	reference,	pixelScale, pixelBias)
    950 			<< TestLog::Image("ErrorMask",	"Error mask",	errorMask)
    951 			<< TestLog::EndImageSet;
    952 	}
    953 	else if (logMode == COMPARE_LOG_RESULT)
    954 	{
    955 		if (result.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8))
    956 			computePixelScaleBias(result, pixelScale, pixelBias);
    957 
    958 		log << TestLog::ImageSet(imageSetName, imageSetDesc)
    959 			<< TestLog::Image("Result",		"Result",		result,		pixelScale, pixelBias)
    960 			<< TestLog::EndImageSet;
    961 	}
    962 
    963 	return compareOk;
    964 }
    965 
    966 /*--------------------------------------------------------------------*//*!
    967  * \brief Per-pixel threshold-based comparison
    968  *
    969  * This compare computes per-pixel differences between result and reference
    970  * image. Comparison fails if any pixels exceed the given threshold value.
    971  *
    972  * On failure error image is generated that shows where the failing pixels
    973  * are.
    974  *
    975  * \param log			Test log for results
    976  * \param imageSetName	Name for image set when logging results
    977  * \param imageSetDesc	Description for image set
    978  * \param reference		Reference image
    979  * \param result		Result image
    980  * \param threshold		Maximum allowed difference
    981  * \param logMode		Logging mode
    982  * \return true if comparison passes, false otherwise
    983  *//*--------------------------------------------------------------------*/
    984 bool pixelThresholdCompare (TestLog& log, const char* imageSetName, const char* imageSetDesc, const Surface& reference, const Surface& result, const RGBA& threshold, CompareLogMode logMode)
    985 {
    986 	return intThresholdCompare(log, imageSetName, imageSetDesc, reference.getAccess(), result.getAccess(), threshold.toIVec().cast<deUint32>(), logMode);
    987 }
    988 
    989 /*--------------------------------------------------------------------*//*!
    990  * \brief Bilinear image comparison
    991  *
    992  * \todo [pyry] Describe
    993  *
    994  * On failure error image is generated that shows where the failing pixels
    995  * are.
    996  *
    997  * \note				Currently supports only RGBA, UNORM_INT8 formats
    998  * \param log			Test log for results
    999  * \param imageSetName	Name for image set when logging results
   1000  * \param imageSetDesc	Description for image set
   1001  * \param reference		Reference image
   1002  * \param result		Result image
   1003  * \param threshold		Maximum local difference
   1004  * \param logMode		Logging mode
   1005  * \return true if comparison passes, false otherwise
   1006  *//*--------------------------------------------------------------------*/
   1007 bool bilinearCompare (TestLog& log, const char* imageSetName, const char* imageSetDesc, const ConstPixelBufferAccess& reference, const ConstPixelBufferAccess& result, const RGBA threshold, CompareLogMode logMode)
   1008 {
   1009 	TextureLevel		errorMask		(TextureFormat(TextureFormat::RGB, TextureFormat::UNORM_INT8), reference.getWidth(), reference.getHeight());
   1010 	bool				isOk			= bilinearCompare(reference, result, errorMask, threshold);
   1011 	Vec4				pixelBias		(0.0f, 0.0f, 0.0f, 0.0f);
   1012 	Vec4				pixelScale		(1.0f, 1.0f, 1.0f, 1.0f);
   1013 
   1014 	if (!isOk || logMode == COMPARE_LOG_EVERYTHING)
   1015 	{
   1016 		if (result.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8) && reference.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8))
   1017 			computeScaleAndBias(reference, result, pixelScale, pixelBias);
   1018 
   1019 		if (!isOk)
   1020 			log << TestLog::Message << "Image comparison failed, threshold = " << threshold << TestLog::EndMessage;
   1021 
   1022 		log << TestLog::ImageSet(imageSetName, imageSetDesc)
   1023 			<< TestLog::Image("Result",		"Result",		result,		pixelScale, pixelBias)
   1024 			<< TestLog::Image("Reference",	"Reference",	reference,	pixelScale, pixelBias)
   1025 			<< TestLog::Image("ErrorMask",	"Error mask",	errorMask)
   1026 			<< TestLog::EndImageSet;
   1027 	}
   1028 	else if (logMode == COMPARE_LOG_RESULT)
   1029 	{
   1030 		if (result.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8))
   1031 			computePixelScaleBias(result, pixelScale, pixelBias);
   1032 
   1033 		log << TestLog::ImageSet(imageSetName, imageSetDesc)
   1034 			<< TestLog::Image("Result",		"Result",		result, pixelScale, pixelBias)
   1035 			<< TestLog::EndImageSet;
   1036 	}
   1037 
   1038 	return isOk;
   1039 }
   1040 
   1041 } // tcu
   1042