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()) : (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
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. Add one since the removed range
431			// contained one representable value, 0.
432			return (deInt32)(f.bits() - (1u << 23u) + 1u);
433		}
434	}
435}
436
437static deUint32 computeFloatFlushRelaxedULPDiff (float a, float b)
438{
439	if (deIsNaN(a) && deIsNaN(b))
440		return 0;
441	else if (deIsNaN(a) || deIsNaN(b))
442	{
443		return 0xFFFFFFFFu;
444	}
445	else
446	{
447		// Using the "definition 5" in Muller, Jean-Michel. "On the definition of ulp (x)" (2005)
448		// assuming a floating point space is IEEE single precision floating point space without
449		// denormals (and signed zeros).
450		const deInt32 aIndex = getPositionOfIEEEFloatWithoutDenormals(a);
451		const deInt32 bIndex = getPositionOfIEEEFloatWithoutDenormals(b);
452		return (deUint32)de::abs(aIndex - bIndex);
453	}
454}
455
456static tcu::UVec4 computeFlushRelaxedULPDiff (const tcu::Vec4& a, const tcu::Vec4& b)
457{
458	return tcu::UVec4(computeFloatFlushRelaxedULPDiff(a.x(), b.x()),
459					  computeFloatFlushRelaxedULPDiff(a.y(), b.y()),
460					  computeFloatFlushRelaxedULPDiff(a.z(), b.z()),
461					  computeFloatFlushRelaxedULPDiff(a.w(), b.w()));
462}
463
464/*--------------------------------------------------------------------*//*!
465 * \brief Per-pixel threshold-based comparison
466 *
467 * This compare computes per-pixel differences between result and reference
468 * image. Comparison fails if any pixels exceed the given threshold value.
469 *
470 * This comparison uses ULP (units in last place) metric for computing the
471 * difference between floating-point values and thus this function can
472 * be used only for comparing floating-point texture data. In ULP calculation
473 * the denormal numbers are allowed to be flushed to zero.
474 *
475 * On failure error image is generated that shows where the failing pixels
476 * are.
477 *
478 * \param log			Test log for results
479 * \param imageSetName	Name for image set when logging results
480 * \param imageSetDesc	Description for image set
481 * \param reference		Reference image
482 * \param result		Result image
483 * \param threshold		Maximum allowed difference
484 * \param logMode		Logging mode
485 * \return true if comparison passes, false otherwise
486 *//*--------------------------------------------------------------------*/
487bool floatUlpThresholdCompare (TestLog& log, const char* imageSetName, const char* imageSetDesc, const ConstPixelBufferAccess& reference, const ConstPixelBufferAccess& result, const UVec4& threshold, CompareLogMode logMode)
488{
489	int					width				= reference.getWidth();
490	int					height				= reference.getHeight();
491	int					depth				= reference.getDepth();
492	TextureLevel		errorMaskStorage	(TextureFormat(TextureFormat::RGB, TextureFormat::UNORM_INT8), width, height, depth);
493	PixelBufferAccess	errorMask			= errorMaskStorage.getAccess();
494	UVec4				maxDiff				(0, 0, 0, 0);
495	Vec4				pixelBias			(0.0f, 0.0f, 0.0f, 0.0f);
496	Vec4				pixelScale			(1.0f, 1.0f, 1.0f, 1.0f);
497
498	TCU_CHECK(result.getWidth() == width && result.getHeight() == height && result.getDepth() == depth);
499
500	for (int z = 0; z < depth; z++)
501	{
502		for (int y = 0; y < height; y++)
503		{
504			for (int x = 0; x < width; x++)
505			{
506				const Vec4	refPix	= reference.getPixel(x, y, z);
507				const Vec4	cmpPix	= result.getPixel(x, y, z);
508				const UVec4	diff	= computeFlushRelaxedULPDiff(refPix, cmpPix);
509				const bool	isOk	= boolAll(lessThanEqual(diff, threshold));
510
511				maxDiff = max(maxDiff, diff);
512
513				errorMask.setPixel(isOk ? Vec4(0.0f, 1.0f, 0.0f, 1.0f) : Vec4(1.0f, 0.0f, 0.0f, 1.0f), x, y, z);
514			}
515		}
516	}
517
518	bool compareOk = boolAll(lessThanEqual(maxDiff, threshold));
519
520	if (!compareOk || logMode == COMPARE_LOG_EVERYTHING)
521	{
522		// All formats except normalized unsigned fixed point ones need remapping in order to fit into unorm channels in logged images.
523		if (tcu::getTextureChannelClass(reference.getFormat().type)	!= tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT ||
524			tcu::getTextureChannelClass(result.getFormat().type)	!= tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT)
525		{
526			computeScaleAndBias(reference, result, pixelScale, pixelBias);
527			log << TestLog::Message << "Result and reference images are normalized with formula p * " << pixelScale << " + " << pixelBias << TestLog::EndMessage;
528		}
529
530		if (!compareOk)
531			log << TestLog::Message << "Image comparison failed: max difference = " << maxDiff << ", threshold = " << threshold << TestLog::EndMessage;
532
533		log << TestLog::ImageSet(imageSetName, imageSetDesc)
534			<< TestLog::Image("Result",		"Result",		result,		pixelScale, pixelBias)
535			<< TestLog::Image("Reference",	"Reference",	reference,	pixelScale, pixelBias)
536			<< TestLog::Image("ErrorMask",	"Error mask",	errorMask)
537			<< TestLog::EndImageSet;
538	}
539	else if (logMode == COMPARE_LOG_RESULT)
540	{
541		if (result.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8))
542			computePixelScaleBias(result, pixelScale, pixelBias);
543
544		log << TestLog::ImageSet(imageSetName, imageSetDesc)
545			<< TestLog::Image("Result",		"Result",		result,		pixelScale, pixelBias)
546			<< TestLog::EndImageSet;
547	}
548
549	return compareOk;
550}
551
552/*--------------------------------------------------------------------*//*!
553 * \brief Per-pixel threshold-based comparison
554 *
555 * This compare computes per-pixel differences between result and reference
556 * image. Comparison fails if any pixels exceed the given threshold value.
557 *
558 * This comparison can be used for floating-point and fixed-point formats.
559 * Difference is computed in floating-point space.
560 *
561 * On failure an error image is generated that shows where the failing
562 * pixels are.
563 *
564 * \param log			Test log for results
565 * \param imageSetName	Name for image set when logging results
566 * \param imageSetDesc	Description for image set
567 * \param reference		Reference image
568 * \param result		Result image
569 * \param threshold		Maximum allowed difference
570 * \param logMode		Logging mode
571 * \return true if comparison passes, false otherwise
572 *//*--------------------------------------------------------------------*/
573bool floatThresholdCompare (TestLog& log, const char* imageSetName, const char* imageSetDesc, const ConstPixelBufferAccess& reference, const ConstPixelBufferAccess& result, const Vec4& threshold, CompareLogMode logMode)
574{
575	int					width				= reference.getWidth();
576	int					height				= reference.getHeight();
577	int					depth				= reference.getDepth();
578	TextureLevel		errorMaskStorage	(TextureFormat(TextureFormat::RGB, TextureFormat::UNORM_INT8), width, height, depth);
579	PixelBufferAccess	errorMask			= errorMaskStorage.getAccess();
580	Vec4				maxDiff				(0.0f, 0.0f, 0.0f, 0.0f);
581	Vec4				pixelBias			(0.0f, 0.0f, 0.0f, 0.0f);
582	Vec4				pixelScale			(1.0f, 1.0f, 1.0f, 1.0f);
583
584	TCU_CHECK_INTERNAL(result.getWidth() == width && result.getHeight() == height && result.getDepth() == depth);
585
586	for (int z = 0; z < depth; z++)
587	{
588		for (int y = 0; y < height; y++)
589		{
590			for (int x = 0; x < width; x++)
591			{
592				Vec4	refPix		= reference.getPixel(x, y, z);
593				Vec4	cmpPix		= result.getPixel(x, y, z);
594
595				Vec4	diff		= abs(refPix - cmpPix);
596				bool	isOk		= boolAll(lessThanEqual(diff, threshold));
597
598				maxDiff = max(maxDiff, diff);
599
600				errorMask.setPixel(isOk ? Vec4(0.0f, 1.0f, 0.0f, 1.0f) : Vec4(1.0f, 0.0f, 0.0f, 1.0f), x, y, z);
601			}
602		}
603	}
604
605	bool compareOk = boolAll(lessThanEqual(maxDiff, threshold));
606
607	if (!compareOk || logMode == COMPARE_LOG_EVERYTHING)
608	{
609		// All formats except normalized unsigned fixed point ones need remapping in order to fit into unorm channels in logged images.
610		if (tcu::getTextureChannelClass(reference.getFormat().type)	!= tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT ||
611			tcu::getTextureChannelClass(result.getFormat().type)	!= tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT)
612		{
613			computeScaleAndBias(reference, result, pixelScale, pixelBias);
614			log << TestLog::Message << "Result and reference images are normalized with formula p * " << pixelScale << " + " << pixelBias << TestLog::EndMessage;
615		}
616
617		if (!compareOk)
618			log << TestLog::Message << "Image comparison failed: max difference = " << maxDiff << ", threshold = " << threshold << TestLog::EndMessage;
619
620		log << TestLog::ImageSet(imageSetName, imageSetDesc)
621			<< TestLog::Image("Result",		"Result",		result,		pixelScale, pixelBias)
622			<< TestLog::Image("Reference",	"Reference",	reference,	pixelScale, pixelBias)
623			<< TestLog::Image("ErrorMask",	"Error mask",	errorMask)
624			<< TestLog::EndImageSet;
625	}
626	else if (logMode == COMPARE_LOG_RESULT)
627	{
628		if (result.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8))
629			computePixelScaleBias(result, pixelScale, pixelBias);
630
631		log << TestLog::ImageSet(imageSetName, imageSetDesc)
632			<< TestLog::Image("Result",		"Result",		result,		pixelScale, pixelBias)
633			<< TestLog::EndImageSet;
634	}
635
636	return compareOk;
637}
638
639/*--------------------------------------------------------------------*//*!
640 * \brief Per-pixel threshold-based comparison
641 *
642 * This compare computes per-pixel differences between result and reference
643 * color. Comparison fails if any pixels exceed the given threshold value.
644 *
645 * This comparison can be used for floating-point and fixed-point formats.
646 * Difference is computed in floating-point space.
647 *
648 * On failure an error image is generated that shows where the failing
649 * pixels are.
650 *
651 * \param log			Test log for results
652 * \param imageSetName	Name for image set when logging results
653 * \param imageSetDesc	Description for image set
654 * \param reference		Reference color
655 * \param result		Result image
656 * \param threshold		Maximum allowed difference
657 * \param logMode		Logging mode
658 * \return true if comparison passes, false otherwise
659 *//*--------------------------------------------------------------------*/
660bool floatThresholdCompare (TestLog& log, const char* imageSetName, const char* imageSetDesc, const Vec4& reference, const ConstPixelBufferAccess& result, const Vec4& threshold, CompareLogMode logMode)
661{
662	const int			width				= result.getWidth();
663	const int			height				= result.getHeight();
664	const int			depth				= result.getDepth();
665
666	TextureLevel		errorMaskStorage	(TextureFormat(TextureFormat::RGB, TextureFormat::UNORM_INT8), width, height, depth);
667	PixelBufferAccess	errorMask			= errorMaskStorage.getAccess();
668	Vec4				maxDiff				(0.0f, 0.0f, 0.0f, 0.0f);
669	Vec4				pixelBias			(0.0f, 0.0f, 0.0f, 0.0f);
670	Vec4				pixelScale			(1.0f, 1.0f, 1.0f, 1.0f);
671
672	for (int z = 0; z < depth; z++)
673	{
674		for (int y = 0; y < height; y++)
675		{
676			for (int x = 0; x < width; x++)
677			{
678				const Vec4	cmpPix		= result.getPixel(x, y, z);
679				const Vec4	diff		= abs(reference - cmpPix);
680				const bool	isOk		= boolAll(lessThanEqual(diff, threshold));
681
682				maxDiff = max(maxDiff, diff);
683
684				errorMask.setPixel(isOk ? Vec4(0.0f, 1.0f, 0.0f, 1.0f) : Vec4(1.0f, 0.0f, 0.0f, 1.0f), x, y, z);
685			}
686		}
687	}
688
689	bool compareOk = boolAll(lessThanEqual(maxDiff, threshold));
690
691	if (!compareOk || logMode == COMPARE_LOG_EVERYTHING)
692	{
693		// All formats except normalized unsigned fixed point ones need remapping in order to fit into unorm channels in logged images.
694		if (tcu::getTextureChannelClass(result.getFormat().type) != tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT)
695		{
696			computeScaleAndBias(result, result, pixelScale, pixelBias);
697			log << TestLog::Message << "Result image is normalized with formula p * " << pixelScale << " + " << pixelBias << TestLog::EndMessage;
698		}
699
700		if (!compareOk)
701			log << TestLog::Message << "Image comparison failed: max difference = " << maxDiff << ", threshold = " << threshold << ", reference = " << reference << TestLog::EndMessage;
702
703		log << TestLog::ImageSet(imageSetName, imageSetDesc)
704			<< TestLog::Image("Result",		"Result",		result,		pixelScale, pixelBias)
705			<< TestLog::Image("ErrorMask",	"Error mask",	errorMask)
706			<< TestLog::EndImageSet;
707	}
708	else if (logMode == COMPARE_LOG_RESULT)
709	{
710		if (result.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8))
711			computePixelScaleBias(result, pixelScale, pixelBias);
712
713		log << TestLog::ImageSet(imageSetName, imageSetDesc)
714			<< TestLog::Image("Result",		"Result",		result,		pixelScale, pixelBias)
715			<< TestLog::EndImageSet;
716	}
717
718	return compareOk;
719}
720
721/*--------------------------------------------------------------------*//*!
722 * \brief Per-pixel threshold-based comparison
723 *
724 * This compare computes per-pixel differences between result and reference
725 * image. Comparison fails if any pixels exceed the given threshold value.
726 *
727 * This comparison can be used for integer- and fixed-point texture formats.
728 * Difference is computed in integer space.
729 *
730 * On failure error image is generated that shows where the failing pixels
731 * are.
732 *
733 * \param log			Test log for results
734 * \param imageSetName	Name for image set when logging results
735 * \param imageSetDesc	Description for image set
736 * \param reference		Reference image
737 * \param result		Result image
738 * \param threshold		Maximum allowed difference
739 * \param logMode		Logging mode
740 * \return true if comparison passes, false otherwise
741 *//*--------------------------------------------------------------------*/
742bool intThresholdCompare (TestLog& log, const char* imageSetName, const char* imageSetDesc, const ConstPixelBufferAccess& reference, const ConstPixelBufferAccess& result, const UVec4& threshold, CompareLogMode logMode)
743{
744	int					width				= reference.getWidth();
745	int					height				= reference.getHeight();
746	int					depth				= reference.getDepth();
747	TextureLevel		errorMaskStorage	(TextureFormat(TextureFormat::RGB, TextureFormat::UNORM_INT8), width, height, depth);
748	PixelBufferAccess	errorMask			= errorMaskStorage.getAccess();
749	UVec4				maxDiff				(0, 0, 0, 0);
750	Vec4				pixelBias			(0.0f, 0.0f, 0.0f, 0.0f);
751	Vec4				pixelScale			(1.0f, 1.0f, 1.0f, 1.0f);
752
753	TCU_CHECK_INTERNAL(result.getWidth() == width && result.getHeight() == height && result.getDepth() == depth);
754
755	for (int z = 0; z < depth; z++)
756	{
757		for (int y = 0; y < height; y++)
758		{
759			for (int x = 0; x < width; x++)
760			{
761				IVec4	refPix		= reference.getPixelInt(x, y, z);
762				IVec4	cmpPix		= result.getPixelInt(x, y, z);
763
764				UVec4	diff		= abs(refPix - cmpPix).cast<deUint32>();
765				bool	isOk		= boolAll(lessThanEqual(diff, threshold));
766
767				maxDiff = max(maxDiff, diff);
768
769				errorMask.setPixel(isOk ? IVec4(0, 0xff, 0, 0xff) : IVec4(0xff, 0, 0, 0xff), x, y, z);
770			}
771		}
772	}
773
774	bool compareOk = boolAll(lessThanEqual(maxDiff, threshold));
775
776	if (!compareOk || logMode == COMPARE_LOG_EVERYTHING)
777	{
778		// All formats except normalized unsigned fixed point ones need remapping in order to fit into unorm channels in logged images.
779		if (tcu::getTextureChannelClass(reference.getFormat().type)	!= tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT ||
780			tcu::getTextureChannelClass(result.getFormat().type)	!= tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT)
781		{
782			computeScaleAndBias(reference, result, pixelScale, pixelBias);
783			log << TestLog::Message << "Result and reference images are normalized with formula p * " << pixelScale << " + " << pixelBias << TestLog::EndMessage;
784		}
785
786		if (!compareOk)
787			log << TestLog::Message << "Image comparison failed: max difference = " << maxDiff << ", threshold = " << threshold << TestLog::EndMessage;
788
789		log << TestLog::ImageSet(imageSetName, imageSetDesc)
790			<< TestLog::Image("Result",		"Result",		result,		pixelScale, pixelBias)
791			<< TestLog::Image("Reference",	"Reference",	reference,	pixelScale, pixelBias)
792			<< TestLog::Image("ErrorMask",	"Error mask",	errorMask)
793			<< TestLog::EndImageSet;
794	}
795	else if (logMode == COMPARE_LOG_RESULT)
796	{
797		if (result.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8))
798			computePixelScaleBias(result, pixelScale, pixelBias);
799
800		log << TestLog::ImageSet(imageSetName, imageSetDesc)
801			<< TestLog::Image("Result",		"Result",		result,		pixelScale, pixelBias)
802			<< TestLog::EndImageSet;
803	}
804
805	return compareOk;
806}
807
808/*--------------------------------------------------------------------*//*!
809 * \brief Per-pixel threshold-based deviation-ignoring comparison
810 *
811 * This compare computes per-pixel differences between result and reference
812 * image. Comparison fails if there is no pixel matching the given threshold
813 * value in the search volume.
814 *
815 * If the search volume contains out-of-bounds pixels, comparison can be set
816 * to either ignore these pixels in search or to accept any pixel that has
817 * out-of-bounds pixels in its search volume.
818 *
819 * This comparison can be used for integer- and fixed-point texture formats.
820 * Difference is computed in integer space.
821 *
822 * On failure error image is generated that shows where the failing pixels
823 * are.
824 *
825 * \param log							Test log for results
826 * \param imageSetName					Name for image set when logging results
827 * \param imageSetDesc					Description for image set
828 * \param reference						Reference image
829 * \param result						Result image
830 * \param threshold						Maximum allowed difference
831 * \param maxPositionDeviation			Maximum allowed distance in the search
832 *										volume.
833 * \param acceptOutOfBoundsAsAnyValue	Accept any pixel in the boundary region
834 * \param logMode						Logging mode
835 * \return true if comparison passes, false otherwise
836 *//*--------------------------------------------------------------------*/
837bool 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)
838{
839	const int			width				= reference.getWidth();
840	const int			height				= reference.getHeight();
841	const int			depth				= reference.getDepth();
842	TextureLevel		errorMaskStorage	(TextureFormat(TextureFormat::RGB, TextureFormat::UNORM_INT8), width, height, depth);
843	PixelBufferAccess	errorMask			= errorMaskStorage.getAccess();
844	const int			numFailingPixels	= findNumPositionDeviationFailingPixels(errorMask, reference, result, threshold, maxPositionDeviation, acceptOutOfBoundsAsAnyValue);
845	const bool			compareOk			= numFailingPixels == 0;
846	Vec4				pixelBias			(0.0f, 0.0f, 0.0f, 0.0f);
847	Vec4				pixelScale			(1.0f, 1.0f, 1.0f, 1.0f);
848
849	if (!compareOk || logMode == COMPARE_LOG_EVERYTHING)
850	{
851		// All formats except normalized unsigned fixed point ones need remapping in order to fit into unorm channels in logged images.
852		if (tcu::getTextureChannelClass(reference.getFormat().type)	!= tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT ||
853			tcu::getTextureChannelClass(result.getFormat().type)	!= tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT)
854		{
855			computeScaleAndBias(reference, result, pixelScale, pixelBias);
856			log << TestLog::Message << "Result and reference images are normalized with formula p * " << pixelScale << " + " << pixelBias << TestLog::EndMessage;
857		}
858
859		if (!compareOk)
860			log	<< TestLog::Message
861				<< "Image comparison failed:\n"
862				<< "\tallowed position deviation = " << maxPositionDeviation << "\n"
863				<< "\tcolor threshold = " << threshold
864				<< TestLog::EndMessage;
865
866		log << TestLog::ImageSet(imageSetName, imageSetDesc)
867			<< TestLog::Image("Result",		"Result",		result,		pixelScale, pixelBias)
868			<< TestLog::Image("Reference",	"Reference",	reference,	pixelScale, pixelBias)
869			<< TestLog::Image("ErrorMask",	"Error mask",	errorMask)
870			<< TestLog::EndImageSet;
871	}
872	else if (logMode == COMPARE_LOG_RESULT)
873	{
874		if (result.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8))
875			computePixelScaleBias(result, pixelScale, pixelBias);
876
877		log << TestLog::ImageSet(imageSetName, imageSetDesc)
878			<< TestLog::Image("Result",		"Result",		result,		pixelScale, pixelBias)
879			<< TestLog::EndImageSet;
880	}
881
882	return compareOk;
883}
884
885/*--------------------------------------------------------------------*//*!
886 * \brief Per-pixel threshold-based deviation-ignoring comparison
887 *
888 * This compare computes per-pixel differences between result and reference
889 * image. Pixel fails the test if there is no pixel matching the given
890 * threshold value in the search volume. Comparison fails if the number of
891 * failing pixels exceeds the given limit.
892 *
893 * If the search volume contains out-of-bounds pixels, comparison can be set
894 * to either ignore these pixels in search or to accept any pixel that has
895 * out-of-bounds pixels in its search volume.
896 *
897 * This comparison can be used for integer- and fixed-point texture formats.
898 * Difference is computed in integer space.
899 *
900 * On failure error image is generated that shows where the failing pixels
901 * are.
902 *
903 * \param log							Test log for results
904 * \param imageSetName					Name for image set when logging results
905 * \param imageSetDesc					Description for image set
906 * \param reference						Reference image
907 * \param result						Result image
908 * \param threshold						Maximum allowed difference
909 * \param maxPositionDeviation			Maximum allowed distance in the search
910 *										volume.
911 * \param acceptOutOfBoundsAsAnyValue	Accept any pixel in the boundary region
912 * \param maxAllowedFailingPixels		Maximum number of failing pixels
913 * \param logMode						Logging mode
914 * \return true if comparison passes, false otherwise
915 *//*--------------------------------------------------------------------*/
916bool 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)
917{
918	const int			width				= reference.getWidth();
919	const int			height				= reference.getHeight();
920	const int			depth				= reference.getDepth();
921	TextureLevel		errorMaskStorage	(TextureFormat(TextureFormat::RGB, TextureFormat::UNORM_INT8), width, height, depth);
922	PixelBufferAccess	errorMask			= errorMaskStorage.getAccess();
923	const int			numFailingPixels	= findNumPositionDeviationFailingPixels(errorMask, reference, result, threshold, maxPositionDeviation, acceptOutOfBoundsAsAnyValue);
924	const bool			compareOk			= numFailingPixels <= maxAllowedFailingPixels;
925	Vec4				pixelBias			(0.0f, 0.0f, 0.0f, 0.0f);
926	Vec4				pixelScale			(1.0f, 1.0f, 1.0f, 1.0f);
927
928	if (!compareOk || logMode == COMPARE_LOG_EVERYTHING)
929	{
930		// All formats except normalized unsigned fixed point ones need remapping in order to fit into unorm channels in logged images.
931		if (tcu::getTextureChannelClass(reference.getFormat().type)	!= tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT ||
932			tcu::getTextureChannelClass(result.getFormat().type)	!= tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT)
933		{
934			computeScaleAndBias(reference, result, pixelScale, pixelBias);
935			log << TestLog::Message << "Result and reference images are normalized with formula p * " << pixelScale << " + " << pixelBias << TestLog::EndMessage;
936		}
937
938		if (!compareOk)
939			log	<< TestLog::Message
940				<< "Image comparison failed:\n"
941				<< "\tallowed position deviation = " << maxPositionDeviation << "\n"
942				<< "\tcolor threshold = " << threshold
943				<< TestLog::EndMessage;
944		log << TestLog::Message << "Number of failing pixels = " << numFailingPixels << ", max allowed = " << maxAllowedFailingPixels << TestLog::EndMessage;
945
946		log << TestLog::ImageSet(imageSetName, imageSetDesc)
947			<< TestLog::Image("Result",		"Result",		result,		pixelScale, pixelBias)
948			<< TestLog::Image("Reference",	"Reference",	reference,	pixelScale, pixelBias)
949			<< TestLog::Image("ErrorMask",	"Error mask",	errorMask)
950			<< TestLog::EndImageSet;
951	}
952	else if (logMode == COMPARE_LOG_RESULT)
953	{
954		if (result.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8))
955			computePixelScaleBias(result, pixelScale, pixelBias);
956
957		log << TestLog::ImageSet(imageSetName, imageSetDesc)
958			<< TestLog::Image("Result",		"Result",		result,		pixelScale, pixelBias)
959			<< TestLog::EndImageSet;
960	}
961
962	return compareOk;
963}
964
965/*--------------------------------------------------------------------*//*!
966 * \brief Per-pixel threshold-based comparison
967 *
968 * This compare computes per-pixel differences between result and reference
969 * image. Comparison fails if any pixels exceed the given threshold value.
970 *
971 * On failure error image is generated that shows where the failing pixels
972 * are.
973 *
974 * \param log			Test log for results
975 * \param imageSetName	Name for image set when logging results
976 * \param imageSetDesc	Description for image set
977 * \param reference		Reference image
978 * \param result		Result image
979 * \param threshold		Maximum allowed difference
980 * \param logMode		Logging mode
981 * \return true if comparison passes, false otherwise
982 *//*--------------------------------------------------------------------*/
983bool pixelThresholdCompare (TestLog& log, const char* imageSetName, const char* imageSetDesc, const Surface& reference, const Surface& result, const RGBA& threshold, CompareLogMode logMode)
984{
985	return intThresholdCompare(log, imageSetName, imageSetDesc, reference.getAccess(), result.getAccess(), threshold.toIVec().cast<deUint32>(), logMode);
986}
987
988/*--------------------------------------------------------------------*//*!
989 * \brief Bilinear image comparison
990 *
991 * \todo [pyry] Describe
992 *
993 * On failure error image is generated that shows where the failing pixels
994 * are.
995 *
996 * \note				Currently supports only RGBA, UNORM_INT8 formats
997 * \param log			Test log for results
998 * \param imageSetName	Name for image set when logging results
999 * \param imageSetDesc	Description for image set
1000 * \param reference		Reference image
1001 * \param result		Result image
1002 * \param threshold		Maximum local difference
1003 * \param logMode		Logging mode
1004 * \return true if comparison passes, false otherwise
1005 *//*--------------------------------------------------------------------*/
1006bool bilinearCompare (TestLog& log, const char* imageSetName, const char* imageSetDesc, const ConstPixelBufferAccess& reference, const ConstPixelBufferAccess& result, const RGBA threshold, CompareLogMode logMode)
1007{
1008	TextureLevel		errorMask		(TextureFormat(TextureFormat::RGB, TextureFormat::UNORM_INT8), reference.getWidth(), reference.getHeight());
1009	bool				isOk			= bilinearCompare(reference, result, errorMask, threshold);
1010	Vec4				pixelBias		(0.0f, 0.0f, 0.0f, 0.0f);
1011	Vec4				pixelScale		(1.0f, 1.0f, 1.0f, 1.0f);
1012
1013	if (!isOk || logMode == COMPARE_LOG_EVERYTHING)
1014	{
1015		if (result.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8) && reference.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8))
1016			computeScaleAndBias(reference, result, pixelScale, pixelBias);
1017
1018		if (!isOk)
1019			log << TestLog::Message << "Image comparison failed, threshold = " << threshold << TestLog::EndMessage;
1020
1021		log << TestLog::ImageSet(imageSetName, imageSetDesc)
1022			<< TestLog::Image("Result",		"Result",		result,		pixelScale, pixelBias)
1023			<< TestLog::Image("Reference",	"Reference",	reference,	pixelScale, pixelBias)
1024			<< TestLog::Image("ErrorMask",	"Error mask",	errorMask)
1025			<< TestLog::EndImageSet;
1026	}
1027	else if (logMode == COMPARE_LOG_RESULT)
1028	{
1029		if (result.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8))
1030			computePixelScaleBias(result, pixelScale, pixelBias);
1031
1032		log << TestLog::ImageSet(imageSetName, imageSetDesc)
1033			<< TestLog::Image("Result",		"Result",		result, pixelScale, pixelBias)
1034			<< TestLog::EndImageSet;
1035	}
1036
1037	return isOk;
1038}
1039
1040} // tcu
1041