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