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