• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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   * \param use64Bits		Use 64-bit components when reading image data.
742   * \return true if comparison passes, false otherwise
743   *//*--------------------------------------------------------------------*/
intThresholdCompare(TestLog & log,const char * imageSetName,const char * imageSetDesc,const ConstPixelBufferAccess & reference,const ConstPixelBufferAccess & result,const UVec4 & threshold,CompareLogMode logMode,bool use64Bits)744  bool intThresholdCompare (TestLog& log, const char* imageSetName, const char* imageSetDesc, const ConstPixelBufferAccess& reference, const ConstPixelBufferAccess& result, const UVec4& threshold, CompareLogMode logMode, bool use64Bits)
745  {
746  	int					width				= reference.getWidth();
747  	int					height				= reference.getHeight();
748  	int					depth				= reference.getDepth();
749  	TextureLevel		errorMaskStorage	(TextureFormat(TextureFormat::RGB, TextureFormat::UNORM_INT8), width, height, depth);
750  	PixelBufferAccess	errorMask			= errorMaskStorage.getAccess();
751  	U64Vec4				maxDiff				(0u, 0u, 0u, 0u);
752  	U64Vec4				diff				(0u, 0u, 0u, 0u);
753  	const U64Vec4		threshold64			= threshold.cast<deUint64>();
754  	Vec4				pixelBias			(0.0f, 0.0f, 0.0f, 0.0f);
755  	Vec4				pixelScale			(1.0f, 1.0f, 1.0f, 1.0f);
756  
757  	TCU_CHECK_INTERNAL(result.getWidth() == width && result.getHeight() == height && result.getDepth() == depth);
758  
759  	for (int z = 0; z < depth; z++)
760  	{
761  		for (int y = 0; y < height; y++)
762  		{
763  			for (int x = 0; x < width; x++)
764  			{
765  				if (use64Bits)
766  				{
767  					I64Vec4	refPix	= reference.getPixelInt64(x, y, z);
768  					I64Vec4	cmpPix	= result.getPixelInt64(x, y, z);
769  					diff			= abs(refPix - cmpPix).cast<deUint64>();
770  				}
771  				else
772  				{
773  					IVec4	refPix	= reference.getPixelInt(x, y, z);
774  					IVec4	cmpPix	= result.getPixelInt(x, y, z);
775  					diff			= abs(refPix - cmpPix).cast<deUint64>();
776  				}
777  
778  				maxDiff = max(maxDiff, diff);
779  
780  				const bool isOk = boolAll(lessThanEqual(diff, threshold64));
781  				errorMask.setPixel(isOk ? IVec4(0, 0xff, 0, 0xff) : IVec4(0xff, 0, 0, 0xff), x, y, z);
782  			}
783  		}
784  	}
785  
786  	bool compareOk = boolAll(lessThanEqual(maxDiff, threshold64));
787  
788  	if (!compareOk || logMode == COMPARE_LOG_EVERYTHING)
789  	{
790  		// All formats except normalized unsigned fixed point ones need remapping in order to fit into unorm channels in logged images.
791  		if (tcu::getTextureChannelClass(reference.getFormat().type)	!= tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT ||
792  			tcu::getTextureChannelClass(result.getFormat().type)	!= tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT)
793  		{
794  			computeScaleAndBias(reference, result, pixelScale, pixelBias);
795  			log << TestLog::Message << "Result and reference images are normalized with formula p * " << pixelScale << " + " << pixelBias << TestLog::EndMessage;
796  		}
797  
798  		if (!compareOk)
799  			log << TestLog::Message << "Image comparison failed: max difference = " << maxDiff << ", threshold = " << threshold << TestLog::EndMessage;
800  
801  		log << TestLog::ImageSet(imageSetName, imageSetDesc)
802  			<< TestLog::Image("Result",		"Result",		result,		pixelScale, pixelBias)
803  			<< TestLog::Image("Reference",	"Reference",	reference,	pixelScale, pixelBias)
804  			<< TestLog::Image("ErrorMask",	"Error mask",	errorMask)
805  			<< TestLog::EndImageSet;
806  	}
807  	else if (logMode == COMPARE_LOG_RESULT)
808  	{
809  		if (result.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8))
810  			computePixelScaleBias(result, pixelScale, pixelBias);
811  
812  		log << TestLog::ImageSet(imageSetName, imageSetDesc)
813  			<< TestLog::Image("Result",		"Result",		result,		pixelScale, pixelBias)
814  			<< TestLog::EndImageSet;
815  	}
816  
817  	return compareOk;
818  }
819  
820  /*--------------------------------------------------------------------*//*!
821   * \brief Per-pixel depth/stencil threshold-based comparison
822   *
823   * This compare computes per-pixel differences between result and reference
824   * image. Comparison fails if any pixels exceed the given threshold value.
825   *
826   * This comparison can be used for depth and depth/stencil images.
827   * Difference is computed in integer space.
828   *
829   * On failure error image is generated that shows where the failing pixels
830   * are.
831   *
832   * \param log			Test log for results
833   * \param imageSetName	Name for image set when logging results
834   * \param imageSetDesc	Description for image set
835   * \param reference		Reference image
836   * \param result		Result image
837   * \param threshold		Maximum allowed depth difference (stencil must be exact)
838   * \param logMode		Logging mode
839   * \return true if comparison passes, false otherwise
840   *//*--------------------------------------------------------------------*/
dsThresholdCompare(TestLog & log,const char * imageSetName,const char * imageSetDesc,const ConstPixelBufferAccess & reference,const ConstPixelBufferAccess & result,const float threshold,CompareLogMode logMode)841  bool dsThresholdCompare(TestLog& log, const char* imageSetName, const char* imageSetDesc, const ConstPixelBufferAccess& reference, const ConstPixelBufferAccess& result, const float threshold, CompareLogMode logMode)
842  {
843  	int					width = reference.getWidth();
844  	int					height = reference.getHeight();
845  	int					depth = reference.getDepth();
846  	TextureLevel		errorMaskStorage(TextureFormat(TextureFormat::RGB, TextureFormat::UNORM_INT8), width, height, depth);
847  	PixelBufferAccess	errorMask = errorMaskStorage.getAccess();
848  	float				maxDiff = 0.0;
849  	bool				allStencilOk = true;
850  	bool				hasDepth = tcu::hasDepthComponent(result.getFormat().order);
851  	bool				hasStencil = tcu::hasStencilComponent(result.getFormat().order);
852  
853  	TCU_CHECK_INTERNAL(result.getWidth() == width && result.getHeight() == height && result.getDepth() == depth);
854  
855  	for (int z = 0; z < depth; z++)
856  	{
857  		for (int y = 0; y < height; y++)
858  		{
859  			for (int x = 0; x < width; x++)
860  			{
861  				bool	isOk = true;
862  
863  				if (hasDepth)
864  				{
865  					float refDepth	= reference.getPixDepth(x, y, z);
866  					float cmpDepth	= result.getPixDepth(x, y, z);
867  					float diff		= de::abs(refDepth - cmpDepth);
868  
869  					isOk = diff <= threshold;
870  					maxDiff = (float) deMax(maxDiff, diff);
871  				}
872  
873  				if (hasStencil)
874  				{
875  					deUint8 refStencil = (deUint8) reference.getPixStencil(x, y, z);
876  					deUint8 cmpStencil = (deUint8) result.getPixStencil(x, y, z);
877  
878  					bool isStencilOk = (refStencil == cmpStencil);
879  					allStencilOk = allStencilOk && isStencilOk;
880  					isOk = isOk && isStencilOk;
881  				}
882  
883  				errorMask.setPixel(isOk ? IVec4(0, 0xff, 0, 0xff) : IVec4(0xff, 0, 0, 0xff), x, y, z);
884  			}
885  		}
886  	}
887  
888  	bool compareOk = (maxDiff <= threshold) && allStencilOk;
889  
890  	if (!compareOk || logMode == COMPARE_LOG_EVERYTHING)
891  	{
892  		if (!compareOk)
893  		{
894  			if (maxDiff > threshold)
895  				log << TestLog::Message << "Depth comparison failed: max difference = " << maxDiff << ", threshold = " << threshold << TestLog::EndMessage;
896  			if (!allStencilOk)
897  				log << TestLog::Message << "Stencil comparison failed" << TestLog::EndMessage;
898  		}
899  
900  		log << TestLog::ImageSet(imageSetName, imageSetDesc)
901  			// TODO: Convert depth/stencil buffers into separate depth & stencil for logging?
902  //			<< TestLog::Image("Result", "Result", result, pixelScale, pixelBias)
903  //			<< TestLog::Image("Reference", "Reference", reference, pixelScale, pixelBias)
904  			<< TestLog::Image("ErrorMask", "Error mask", errorMask)
905  			<< TestLog::EndImageSet;
906  	}
907  	else if (logMode == COMPARE_LOG_RESULT)
908  	{
909  #if 0
910  		if (result.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8))
911  			computePixelScaleBias(result, pixelScale, pixelBias);
912  
913  		log << TestLog::ImageSet(imageSetName, imageSetDesc)
914  			<< TestLog::Image("Result", "Result", result, pixelScale, pixelBias)
915  			<< TestLog::EndImageSet;
916  #endif
917  	}
918  
919  	return compareOk;
920  }
921  
922  /*--------------------------------------------------------------------*//*!
923   * \brief Per-pixel threshold-based deviation-ignoring comparison
924   *
925   * This compare computes per-pixel differences between result and reference
926   * image. Comparison fails if there is no pixel matching the given threshold
927   * value in the search volume.
928   *
929   * If the search volume contains out-of-bounds pixels, comparison can be set
930   * to either ignore these pixels in search or to accept any pixel that has
931   * out-of-bounds pixels in its search volume.
932   *
933   * This comparison can be used for integer- and fixed-point texture formats.
934   * Difference is computed in integer space.
935   *
936   * On failure error image is generated that shows where the failing pixels
937   * are.
938   *
939   * \param log							Test log for results
940   * \param imageSetName					Name for image set when logging results
941   * \param imageSetDesc					Description for image set
942   * \param reference						Reference image
943   * \param result						Result image
944   * \param threshold						Maximum allowed difference
945   * \param maxPositionDeviation			Maximum allowed distance in the search
946   *										volume.
947   * \param acceptOutOfBoundsAsAnyValue	Accept any pixel in the boundary region
948   * \param logMode						Logging mode
949   * \return true if comparison passes, false otherwise
950   *//*--------------------------------------------------------------------*/
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)951  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)
952  {
953  	const int			width				= reference.getWidth();
954  	const int			height				= reference.getHeight();
955  	const int			depth				= reference.getDepth();
956  	TextureLevel		errorMaskStorage	(TextureFormat(TextureFormat::RGB, TextureFormat::UNORM_INT8), width, height, depth);
957  	PixelBufferAccess	errorMask			= errorMaskStorage.getAccess();
958  	const int			numFailingPixels	= findNumPositionDeviationFailingPixels(errorMask, reference, result, threshold, maxPositionDeviation, acceptOutOfBoundsAsAnyValue);
959  	const bool			compareOk			= numFailingPixels == 0;
960  	Vec4				pixelBias			(0.0f, 0.0f, 0.0f, 0.0f);
961  	Vec4				pixelScale			(1.0f, 1.0f, 1.0f, 1.0f);
962  
963  	if (!compareOk || logMode == COMPARE_LOG_EVERYTHING)
964  	{
965  		// All formats except normalized unsigned fixed point ones need remapping in order to fit into unorm channels in logged images.
966  		if (tcu::getTextureChannelClass(reference.getFormat().type)	!= tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT ||
967  			tcu::getTextureChannelClass(result.getFormat().type)	!= tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT)
968  		{
969  			computeScaleAndBias(reference, result, pixelScale, pixelBias);
970  			log << TestLog::Message << "Result and reference images are normalized with formula p * " << pixelScale << " + " << pixelBias << TestLog::EndMessage;
971  		}
972  
973  		if (!compareOk)
974  			log	<< TestLog::Message
975  				<< "Image comparison failed:\n"
976  				<< "\tallowed position deviation = " << maxPositionDeviation << "\n"
977  				<< "\tcolor threshold = " << threshold
978  				<< TestLog::EndMessage;
979  
980  		log << TestLog::ImageSet(imageSetName, imageSetDesc)
981  			<< TestLog::Image("Result",		"Result",		result,		pixelScale, pixelBias)
982  			<< TestLog::Image("Reference",	"Reference",	reference,	pixelScale, pixelBias)
983  			<< TestLog::Image("ErrorMask",	"Error mask",	errorMask)
984  			<< TestLog::EndImageSet;
985  	}
986  	else if (logMode == COMPARE_LOG_RESULT)
987  	{
988  		if (result.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8))
989  			computePixelScaleBias(result, pixelScale, pixelBias);
990  
991  		log << TestLog::ImageSet(imageSetName, imageSetDesc)
992  			<< TestLog::Image("Result",		"Result",		result,		pixelScale, pixelBias)
993  			<< TestLog::EndImageSet;
994  	}
995  
996  	return compareOk;
997  }
998  
999  /*--------------------------------------------------------------------*//*!
1000   * \brief Per-pixel threshold-based deviation-ignoring comparison
1001   *
1002   * This compare computes per-pixel differences between result and reference
1003   * image. Pixel fails the test if there is no pixel matching the given
1004   * threshold value in the search volume. Comparison fails if the number of
1005   * failing pixels exceeds the given limit.
1006   *
1007   * If the search volume contains out-of-bounds pixels, comparison can be set
1008   * to either ignore these pixels in search or to accept any pixel that has
1009   * out-of-bounds pixels in its search volume.
1010   *
1011   * This comparison can be used for integer- and fixed-point texture formats.
1012   * Difference is computed in integer space.
1013   *
1014   * On failure error image is generated that shows where the failing pixels
1015   * are.
1016   *
1017   * \param log							Test log for results
1018   * \param imageSetName					Name for image set when logging results
1019   * \param imageSetDesc					Description for image set
1020   * \param reference						Reference image
1021   * \param result						Result image
1022   * \param threshold						Maximum allowed difference
1023   * \param maxPositionDeviation			Maximum allowed distance in the search
1024   *										volume.
1025   * \param acceptOutOfBoundsAsAnyValue	Accept any pixel in the boundary region
1026   * \param maxAllowedFailingPixels		Maximum number of failing pixels
1027   * \param logMode						Logging mode
1028   * \return true if comparison passes, false otherwise
1029   *//*--------------------------------------------------------------------*/
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)1030  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)
1031  {
1032  	const int			width				= reference.getWidth();
1033  	const int			height				= reference.getHeight();
1034  	const int			depth				= reference.getDepth();
1035  	TextureLevel		errorMaskStorage	(TextureFormat(TextureFormat::RGB, TextureFormat::UNORM_INT8), width, height, depth);
1036  	PixelBufferAccess	errorMask			= errorMaskStorage.getAccess();
1037  	const int			numFailingPixels	= findNumPositionDeviationFailingPixels(errorMask, reference, result, threshold, maxPositionDeviation, acceptOutOfBoundsAsAnyValue);
1038  	const bool			compareOk			= numFailingPixels <= maxAllowedFailingPixels;
1039  	Vec4				pixelBias			(0.0f, 0.0f, 0.0f, 0.0f);
1040  	Vec4				pixelScale			(1.0f, 1.0f, 1.0f, 1.0f);
1041  
1042  	if (!compareOk || logMode == COMPARE_LOG_EVERYTHING)
1043  	{
1044  		// All formats except normalized unsigned fixed point ones need remapping in order to fit into unorm channels in logged images.
1045  		if (tcu::getTextureChannelClass(reference.getFormat().type)	!= tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT ||
1046  			tcu::getTextureChannelClass(result.getFormat().type)	!= tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT)
1047  		{
1048  			computeScaleAndBias(reference, result, pixelScale, pixelBias);
1049  			log << TestLog::Message << "Result and reference images are normalized with formula p * " << pixelScale << " + " << pixelBias << TestLog::EndMessage;
1050  		}
1051  
1052  		if (!compareOk)
1053  			log	<< TestLog::Message
1054  				<< "Image comparison failed:\n"
1055  				<< "\tallowed position deviation = " << maxPositionDeviation << "\n"
1056  				<< "\tcolor threshold = " << threshold
1057  				<< TestLog::EndMessage;
1058  		log << TestLog::Message << "Number of failing pixels = " << numFailingPixels << ", max allowed = " << maxAllowedFailingPixels << TestLog::EndMessage;
1059  
1060  		log << TestLog::ImageSet(imageSetName, imageSetDesc)
1061  			<< TestLog::Image("Result",		"Result",		result,		pixelScale, pixelBias)
1062  			<< TestLog::Image("Reference",	"Reference",	reference,	pixelScale, pixelBias)
1063  			<< TestLog::Image("ErrorMask",	"Error mask",	errorMask)
1064  			<< TestLog::EndImageSet;
1065  	}
1066  	else if (logMode == COMPARE_LOG_RESULT)
1067  	{
1068  		if (result.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8))
1069  			computePixelScaleBias(result, pixelScale, pixelBias);
1070  
1071  		log << TestLog::ImageSet(imageSetName, imageSetDesc)
1072  			<< TestLog::Image("Result",		"Result",		result,		pixelScale, pixelBias)
1073  			<< TestLog::EndImageSet;
1074  	}
1075  
1076  	return compareOk;
1077  }
1078  
1079  /*--------------------------------------------------------------------*//*!
1080   * \brief Per-pixel threshold-based comparison
1081   *
1082   * This compare computes per-pixel differences between result and reference
1083   * image. Comparison fails if any pixels exceed the given threshold value.
1084   *
1085   * On failure error image is generated that shows where the failing pixels
1086   * are.
1087   *
1088   * \param log			Test log for results
1089   * \param imageSetName	Name for image set when logging results
1090   * \param imageSetDesc	Description for image set
1091   * \param reference		Reference image
1092   * \param result		Result image
1093   * \param threshold		Maximum allowed difference
1094   * \param logMode		Logging mode
1095   * \return true if comparison passes, false otherwise
1096   *//*--------------------------------------------------------------------*/
pixelThresholdCompare(TestLog & log,const char * imageSetName,const char * imageSetDesc,const Surface & reference,const Surface & result,const RGBA & threshold,CompareLogMode logMode)1097  bool pixelThresholdCompare (TestLog& log, const char* imageSetName, const char* imageSetDesc, const Surface& reference, const Surface& result, const RGBA& threshold, CompareLogMode logMode)
1098  {
1099  	return intThresholdCompare(log, imageSetName, imageSetDesc, reference.getAccess(), result.getAccess(), threshold.toIVec().cast<deUint32>(), logMode);
1100  }
1101  
1102  /*--------------------------------------------------------------------*//*!
1103   * \brief Bilinear image comparison
1104   *
1105   * \todo [pyry] Describe
1106   *
1107   * On failure error image is generated that shows where the failing pixels
1108   * are.
1109   *
1110   * \note				Currently supports only RGBA, UNORM_INT8 formats
1111   * \param log			Test log for results
1112   * \param imageSetName	Name for image set when logging results
1113   * \param imageSetDesc	Description for image set
1114   * \param reference		Reference image
1115   * \param result		Result image
1116   * \param threshold		Maximum local difference
1117   * \param logMode		Logging mode
1118   * \return true if comparison passes, false otherwise
1119   *//*--------------------------------------------------------------------*/
bilinearCompare(TestLog & log,const char * imageSetName,const char * imageSetDesc,const ConstPixelBufferAccess & reference,const ConstPixelBufferAccess & result,const RGBA threshold,CompareLogMode logMode)1120  bool bilinearCompare (TestLog& log, const char* imageSetName, const char* imageSetDesc, const ConstPixelBufferAccess& reference, const ConstPixelBufferAccess& result, const RGBA threshold, CompareLogMode logMode)
1121  {
1122  	TextureLevel		errorMask		(TextureFormat(TextureFormat::RGB, TextureFormat::UNORM_INT8), reference.getWidth(), reference.getHeight());
1123  	bool				isOk			= bilinearCompare(reference, result, errorMask, threshold);
1124  	Vec4				pixelBias		(0.0f, 0.0f, 0.0f, 0.0f);
1125  	Vec4				pixelScale		(1.0f, 1.0f, 1.0f, 1.0f);
1126  
1127  	if (!isOk || logMode == COMPARE_LOG_EVERYTHING)
1128  	{
1129  		if (result.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8) && reference.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8))
1130  			computeScaleAndBias(reference, result, pixelScale, pixelBias);
1131  
1132  		if (!isOk)
1133  			log << TestLog::Message << "Image comparison failed, threshold = " << threshold << TestLog::EndMessage;
1134  
1135  		log << TestLog::ImageSet(imageSetName, imageSetDesc)
1136  			<< TestLog::Image("Result",		"Result",		result,		pixelScale, pixelBias)
1137  			<< TestLog::Image("Reference",	"Reference",	reference,	pixelScale, pixelBias)
1138  			<< TestLog::Image("ErrorMask",	"Error mask",	errorMask)
1139  			<< TestLog::EndImageSet;
1140  	}
1141  	else if (logMode == COMPARE_LOG_RESULT)
1142  	{
1143  		if (result.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8))
1144  			computePixelScaleBias(result, pixelScale, pixelBias);
1145  
1146  		log << TestLog::ImageSet(imageSetName, imageSetDesc)
1147  			<< TestLog::Image("Result",		"Result",		result, pixelScale, pixelBias)
1148  			<< TestLog::EndImageSet;
1149  	}
1150  
1151  	return isOk;
1152  }
1153  
1154  } // tcu
1155