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