1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program Tester Core
3  * ----------------------------------------
4  *
5  * Copyright 2014 The Android Open Source Project
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Image comparison utilities.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "tcuImageCompare.hpp"
25 #include "tcuSurface.hpp"
26 #include "tcuFuzzyImageCompare.hpp"
27 #include "tcuBilinearImageCompare.hpp"
28 #include "tcuTestLog.hpp"
29 #include "tcuVector.hpp"
30 #include "tcuVectorUtil.hpp"
31 #include "tcuRGBA.hpp"
32 #include "tcuTexture.hpp"
33 #include "tcuTextureUtil.hpp"
34 #include "tcuFloat.hpp"
35 
36 #include <string.h>
37 
38 namespace tcu
39 {
40 
41 namespace
42 {
43 
computeScaleAndBias(const ConstPixelBufferAccess & reference,const ConstPixelBufferAccess & result,tcu::Vec4 & scale,tcu::Vec4 & bias)44 void computeScaleAndBias (const ConstPixelBufferAccess& reference, const ConstPixelBufferAccess& result, tcu::Vec4& scale, tcu::Vec4& bias)
45 {
46 	Vec4 minVal;
47 	Vec4 maxVal;
48 	const float eps = 0.0001f;
49 
50 	{
51 		Vec4 refMin;
52 		Vec4 refMax;
53 		estimatePixelValueRange(reference, refMin, refMax);
54 
55 		minVal	= refMin;
56 		maxVal	= refMax;
57 	}
58 
59 	{
60 		Vec4 resMin;
61 		Vec4 resMax;
62 
63 		estimatePixelValueRange(result, resMin, resMax);
64 
65 		minVal[0] = de::min(minVal[0], resMin[0]);
66 		minVal[1] = de::min(minVal[1], resMin[1]);
67 		minVal[2] = de::min(minVal[2], resMin[2]);
68 		minVal[3] = de::min(minVal[3], resMin[3]);
69 
70 		maxVal[0] = de::max(maxVal[0], resMax[0]);
71 		maxVal[1] = de::max(maxVal[1], resMax[1]);
72 		maxVal[2] = de::max(maxVal[2], resMax[2]);
73 		maxVal[3] = de::max(maxVal[3], resMax[3]);
74 	}
75 
76 	for (int c = 0; c < 4; c++)
77 	{
78 		if (maxVal[c] - minVal[c] < eps)
79 		{
80 			scale[c]	= (maxVal[c] < eps) ? 1.0f : (1.0f / maxVal[c]);
81 			bias[c]		= (c == 3) ? (1.0f - maxVal[c]*scale[c]) : (0.0f - minVal[c]*scale[c]);
82 		}
83 		else
84 		{
85 			scale[c]	= 1.0f / (maxVal[c] - minVal[c]);
86 			bias[c]		= 0.0f - minVal[c]*scale[c];
87 		}
88 	}
89 }
90 
findNumPositionDeviationFailingPixels(const PixelBufferAccess & errorMask,const ConstPixelBufferAccess & reference,const ConstPixelBufferAccess & result,const UVec4 & threshold,const tcu::IVec3 & maxPositionDeviation,bool acceptOutOfBoundsAsAnyValue)91 static int findNumPositionDeviationFailingPixels (const PixelBufferAccess& errorMask, const ConstPixelBufferAccess& reference, const ConstPixelBufferAccess& result, const UVec4& threshold, const tcu::IVec3& maxPositionDeviation, bool acceptOutOfBoundsAsAnyValue)
92 {
93 	const tcu::IVec4	okColor				(0, 255, 0, 255);
94 	const tcu::IVec4	errorColor			(255, 0, 0, 255);
95 	const int			width				= reference.getWidth();
96 	const int			height				= reference.getHeight();
97 	const int			depth				= reference.getDepth();
98 	int					numFailingPixels	= 0;
99 
100 	// Accept pixels "sampling" over the image bounds pixels since "taps" could be anything
101 	const int			beginX				= (acceptOutOfBoundsAsAnyValue) ? (maxPositionDeviation.x()) : (0);
102 	const int			beginY				= (acceptOutOfBoundsAsAnyValue) ? (maxPositionDeviation.y()) : (0);
103 	const int			beginZ				= (acceptOutOfBoundsAsAnyValue) ? (maxPositionDeviation.z()) : (0);
104 	const int			endX				= (acceptOutOfBoundsAsAnyValue) ? (width  - maxPositionDeviation.x()) : (width);
105 	const int			endY				= (acceptOutOfBoundsAsAnyValue) ? (height - maxPositionDeviation.y()) : (height);
106 	const int			endZ				= (acceptOutOfBoundsAsAnyValue) ? (depth  - maxPositionDeviation.z()) : (depth);
107 
108 	TCU_CHECK_INTERNAL(result.getWidth() == width && result.getHeight() == height && result.getDepth() == depth);
109 
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  *//*--------------------------------------------------------------------*/
fuzzyCompare(TestLog & log,const char * imageSetName,const char * imageSetDesc,const ConstPixelBufferAccess & reference,const ConstPixelBufferAccess & result,float threshold,CompareLogMode logMode)216 bool 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  *//*--------------------------------------------------------------------*/
fuzzyCompare(TestLog & log,const char * imageSetName,const char * imageSetDesc,const Surface & reference,const Surface & result,float threshold,CompareLogMode logMode)285 bool 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 
computeSquaredDiffSum(const ConstPixelBufferAccess & ref,const ConstPixelBufferAccess & cmp,const PixelBufferAccess & diffMask,int diffFactor)290 static 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  *//*--------------------------------------------------------------------*/
measurePixelDiffAccuracy(TestLog & log,const char * imageSetName,const char * imageSetDesc,const ConstPixelBufferAccess & reference,const ConstPixelBufferAccess & result,int bestScoreDiff,int worstScoreDiff,CompareLogMode logMode)334 int 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  *//*--------------------------------------------------------------------*/
measurePixelDiffAccuracy(TestLog & log,const char * imageSetName,const char * imageSetDesc,const Surface & reference,const Surface & result,int bestScoreDiff,int worstScoreDiff,CompareLogMode logMode)390 int 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  *//*--------------------------------------------------------------------*/
getPositionOfIEEEFloatWithoutDenormals(float x)404 static 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 
computeFloatFlushRelaxedULPDiff(float a,float b)437 static 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 
computeFlushRelaxedULPDiff(const tcu::Vec4 & a,const tcu::Vec4 & b)456 static 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  *//*--------------------------------------------------------------------*/
floatUlpThresholdCompare(TestLog & log,const char * imageSetName,const char * imageSetDesc,const ConstPixelBufferAccess & reference,const ConstPixelBufferAccess & result,const UVec4 & threshold,CompareLogMode logMode)487 bool 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  *//*--------------------------------------------------------------------*/
floatThresholdCompare(TestLog & log,const char * imageSetName,const char * imageSetDesc,const ConstPixelBufferAccess & reference,const ConstPixelBufferAccess & result,const Vec4 & threshold,CompareLogMode logMode)573 bool 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  *//*--------------------------------------------------------------------*/
floatThresholdCompare(TestLog & log,const char * imageSetName,const char * imageSetDesc,const Vec4 & reference,const ConstPixelBufferAccess & result,const Vec4 & threshold,CompareLogMode logMode)660 bool 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  *//*--------------------------------------------------------------------*/
intThresholdCompare(TestLog & log,const char * imageSetName,const char * imageSetDesc,const ConstPixelBufferAccess & reference,const ConstPixelBufferAccess & result,const UVec4 & threshold,CompareLogMode logMode)742 bool 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  *//*--------------------------------------------------------------------*/
intThresholdPositionDeviationCompare(TestLog & log,const char * imageSetName,const char * imageSetDesc,const ConstPixelBufferAccess & reference,const ConstPixelBufferAccess & result,const UVec4 & threshold,const tcu::IVec3 & maxPositionDeviation,bool acceptOutOfBoundsAsAnyValue,CompareLogMode logMode)837 bool intThresholdPositionDeviationCompare (TestLog& log, const char* imageSetName, const char* imageSetDesc, const ConstPixelBufferAccess& reference, const ConstPixelBufferAccess& result, const UVec4& threshold, const tcu::IVec3& maxPositionDeviation, bool acceptOutOfBoundsAsAnyValue, CompareLogMode logMode)
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  *//*--------------------------------------------------------------------*/
intThresholdPositionDeviationErrorThresholdCompare(TestLog & log,const char * imageSetName,const char * imageSetDesc,const ConstPixelBufferAccess & reference,const ConstPixelBufferAccess & result,const UVec4 & threshold,const tcu::IVec3 & maxPositionDeviation,bool acceptOutOfBoundsAsAnyValue,int maxAllowedFailingPixels,CompareLogMode logMode)916 bool intThresholdPositionDeviationErrorThresholdCompare (TestLog& log, const char* imageSetName, const char* imageSetDesc, const ConstPixelBufferAccess& reference, const ConstPixelBufferAccess& result, const UVec4& threshold, const tcu::IVec3& maxPositionDeviation, bool acceptOutOfBoundsAsAnyValue, int maxAllowedFailingPixels, CompareLogMode logMode)
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  *//*--------------------------------------------------------------------*/
pixelThresholdCompare(TestLog & log,const char * imageSetName,const char * imageSetDesc,const Surface & reference,const Surface & result,const RGBA & threshold,CompareLogMode logMode)983 bool 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  *//*--------------------------------------------------------------------*/
bilinearCompare(TestLog & log,const char * imageSetName,const char * imageSetDesc,const ConstPixelBufferAccess & reference,const ConstPixelBufferAccess & result,const RGBA threshold,CompareLogMode logMode)1006 bool 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