• 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 #include <cmath>
38 
39 namespace tcu
40 {
41 
42 namespace
43 {
44 
computeScaleAndBias(const ConstPixelBufferAccess & reference,const ConstPixelBufferAccess & result,tcu::Vec4 & scale,tcu::Vec4 & bias)45 void computeScaleAndBias(const ConstPixelBufferAccess &reference, const ConstPixelBufferAccess &result,
46                          tcu::Vec4 &scale, tcu::Vec4 &bias)
47 {
48     Vec4 minVal;
49     Vec4 maxVal;
50     const float eps = 0.0001f;
51 
52     {
53         Vec4 refMin;
54         Vec4 refMax;
55         estimatePixelValueRange(reference, refMin, refMax);
56 
57         minVal = refMin;
58         maxVal = refMax;
59     }
60 
61     {
62         Vec4 resMin;
63         Vec4 resMax;
64 
65         estimatePixelValueRange(result, resMin, resMax);
66 
67         minVal[0] = de::min(minVal[0], resMin[0]);
68         minVal[1] = de::min(minVal[1], resMin[1]);
69         minVal[2] = de::min(minVal[2], resMin[2]);
70         minVal[3] = de::min(minVal[3], resMin[3]);
71 
72         maxVal[0] = de::max(maxVal[0], resMax[0]);
73         maxVal[1] = de::max(maxVal[1], resMax[1]);
74         maxVal[2] = de::max(maxVal[2], resMax[2]);
75         maxVal[3] = de::max(maxVal[3], resMax[3]);
76     }
77 
78     for (int c = 0; c < 4; c++)
79     {
80         if (maxVal[c] - minVal[c] < eps)
81         {
82             scale[c] = (maxVal[c] < eps) ? 1.0f : (1.0f / maxVal[c]);
83             bias[c]  = (c == 3) ? (1.0f - maxVal[c] * scale[c]) : (0.0f - minVal[c] * scale[c]);
84         }
85         else
86         {
87             scale[c] = 1.0f / (maxVal[c] - minVal[c]);
88             bias[c]  = 0.0f - minVal[c] * scale[c];
89         }
90     }
91 }
92 
findNumPositionDeviationFailingPixels(const PixelBufferAccess & errorMask,const ConstPixelBufferAccess & reference,const ConstPixelBufferAccess & result,const UVec4 & threshold,const tcu::IVec3 & maxPositionDeviation,bool acceptOutOfBoundsAsAnyValue)93 static int findNumPositionDeviationFailingPixels(const PixelBufferAccess &errorMask,
94                                                  const ConstPixelBufferAccess &reference,
95                                                  const ConstPixelBufferAccess &result, const UVec4 &threshold,
96                                                  const tcu::IVec3 &maxPositionDeviation,
97                                                  bool acceptOutOfBoundsAsAnyValue)
98 {
99     const tcu::IVec4 okColor(0, 255, 0, 255);
100     const tcu::IVec4 errorColor(255, 0, 0, 255);
101     const int width      = reference.getWidth();
102     const int height     = reference.getHeight();
103     const int depth      = reference.getDepth();
104     int numFailingPixels = 0;
105 
106     // Accept pixels "sampling" over the image bounds pixels since "taps" could be anything
107     const int beginX = (acceptOutOfBoundsAsAnyValue) ? (maxPositionDeviation.x()) : (0);
108     const int beginY = (acceptOutOfBoundsAsAnyValue) ? (maxPositionDeviation.y()) : (0);
109     const int beginZ = (acceptOutOfBoundsAsAnyValue) ? (maxPositionDeviation.z()) : (0);
110     const int endX   = (acceptOutOfBoundsAsAnyValue) ? (width - maxPositionDeviation.x()) : (width);
111     const int endY   = (acceptOutOfBoundsAsAnyValue) ? (height - maxPositionDeviation.y()) : (height);
112     const int endZ   = (acceptOutOfBoundsAsAnyValue) ? (depth - maxPositionDeviation.z()) : (depth);
113 
114     TCU_CHECK_INTERNAL(result.getWidth() == width && result.getHeight() == height && result.getDepth() == depth);
115     DE_ASSERT(endX > 0 && endY > 0 && endZ > 0); // most likely a bug
116 
117     tcu::clear(errorMask, okColor);
118 
119     for (int z = beginZ; z < endZ; z++)
120     {
121         for (int y = beginY; y < endY; y++)
122         {
123             for (int x = beginX; x < endX; x++)
124             {
125                 const IVec4 refPix = reference.getPixelInt(x, y, z);
126                 const IVec4 cmpPix = result.getPixelInt(x, y, z);
127 
128                 // Exact match
129                 {
130                     const UVec4 diff = abs(refPix - cmpPix).cast<uint32_t>();
131                     const bool isOk  = boolAll(lessThanEqual(diff, threshold));
132 
133                     if (isOk)
134                         continue;
135                 }
136 
137                 // Find matching pixels for both result and reference pixel
138 
139                 {
140                     bool pixelFoundForReference = false;
141 
142                     // Find deviated result pixel for reference
143 
144                     for (int sz = de::max(0, z - maxPositionDeviation.z());
145                          sz <= de::min(depth - 1, z + maxPositionDeviation.z()) && !pixelFoundForReference; ++sz)
146                         for (int sy = de::max(0, y - maxPositionDeviation.y());
147                              sy <= de::min(height - 1, y + maxPositionDeviation.y()) && !pixelFoundForReference; ++sy)
148                             for (int sx = de::max(0, x - maxPositionDeviation.x());
149                                  sx <= de::min(width - 1, x + maxPositionDeviation.x()) && !pixelFoundForReference;
150                                  ++sx)
151                             {
152                                 const IVec4 deviatedCmpPix = result.getPixelInt(sx, sy, sz);
153                                 const UVec4 diff           = abs(refPix - deviatedCmpPix).cast<uint32_t>();
154                                 const bool isOk            = boolAll(lessThanEqual(diff, threshold));
155 
156                                 pixelFoundForReference = isOk;
157                             }
158 
159                     if (!pixelFoundForReference)
160                     {
161                         errorMask.setPixel(errorColor, x, y, z);
162                         ++numFailingPixels;
163                         continue;
164                     }
165                 }
166                 {
167                     bool pixelFoundForResult = false;
168 
169                     // Find deviated reference pixel for result
170 
171                     for (int sz = de::max(0, z - maxPositionDeviation.z());
172                          sz <= de::min(depth - 1, z + maxPositionDeviation.z()) && !pixelFoundForResult; ++sz)
173                         for (int sy = de::max(0, y - maxPositionDeviation.y());
174                              sy <= de::min(height - 1, y + maxPositionDeviation.y()) && !pixelFoundForResult; ++sy)
175                             for (int sx = de::max(0, x - maxPositionDeviation.x());
176                                  sx <= de::min(width - 1, x + maxPositionDeviation.x()) && !pixelFoundForResult; ++sx)
177                             {
178                                 const IVec4 deviatedRefPix = reference.getPixelInt(sx, sy, sz);
179                                 const UVec4 diff           = abs(cmpPix - deviatedRefPix).cast<uint32_t>();
180                                 const bool isOk            = boolAll(lessThanEqual(diff, threshold));
181 
182                                 pixelFoundForResult = isOk;
183                             }
184 
185                     if (!pixelFoundForResult)
186                     {
187                         errorMask.setPixel(errorColor, x, y, z);
188                         ++numFailingPixels;
189                         continue;
190                     }
191                 }
192             }
193         }
194     }
195 
196     return numFailingPixels;
197 }
198 
199 } // namespace
200 
201 /*--------------------------------------------------------------------*//*!
202  * \brief Fuzzy image comparison
203  *
204  * This image comparison is designed for comparing images rendered by 3D
205  * graphics APIs such as OpenGL. The comparison allows small local differences
206  * and compensates for aliasing.
207  *
208  * The algorithm first performs light blurring on both images and then
209  * does per-pixel analysis. Pixels are compared to 3x3 bilinear surface
210  * defined by adjecent pixels. This compensates for both 1-pixel deviations
211  * in geometry and aliasing in texture data.
212  *
213  * Error metric is computed based on the differences. On valid images the
214  * metric is usually <0.01. Thus good threshold values are in range 0.02 to
215  * 0.05.
216  *
217  * On failure error image is generated that shows where the failing pixels
218  * are.
219  *
220  * \note                Currently supports only UNORM_INT8 formats
221  * \param log            Test log for results
222  * \param imageSetName    Name for image set when logging results
223  * \param imageSetDesc    Description for image set
224  * \param reference        Reference image
225  * \param result        Result image
226  * \param threshold        Error metric threshold (good values are 0.02-0.05)
227  * \param logMode        Logging mode
228  * \return true if comparison passes, false otherwise
229  *//*--------------------------------------------------------------------*/
fuzzyCompare(TestLog & log,const char * imageSetName,const char * imageSetDesc,const ConstPixelBufferAccess & reference,const ConstPixelBufferAccess & result,float threshold,CompareLogMode logMode)230 bool fuzzyCompare(TestLog &log, const char *imageSetName, const char *imageSetDesc,
231                   const ConstPixelBufferAccess &reference, const ConstPixelBufferAccess &result, float threshold,
232                   CompareLogMode logMode)
233 {
234     FuzzyCompareParams params; // Use defaults.
235     TextureLevel errorMask(TextureFormat(TextureFormat::RGB, TextureFormat::UNORM_INT8), reference.getWidth(),
236                            reference.getHeight());
237     float difference = fuzzyCompare(params, reference, result, errorMask.getAccess());
238     bool isOk        = difference <= threshold;
239     Vec4 pixelBias(0.0f, 0.0f, 0.0f, 0.0f);
240     Vec4 pixelScale(1.0f, 1.0f, 1.0f, 1.0f);
241 
242     if (!isOk || logMode == COMPARE_LOG_EVERYTHING)
243     {
244         // Generate more accurate error mask.
245         params.maxSampleSkip = 0;
246         fuzzyCompare(params, reference, result, errorMask.getAccess());
247 
248         if (result.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8) &&
249             reference.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8))
250             computeScaleAndBias(reference, result, pixelScale, pixelBias);
251 
252         if (!isOk)
253             log << TestLog::Message << "Image comparison failed: difference = " << difference
254                 << ", threshold = " << threshold << TestLog::EndMessage;
255 
256         log << TestLog::ImageSet(imageSetName, imageSetDesc)
257             << TestLog::Image("Result", "Result", result, pixelScale, pixelBias)
258             << TestLog::Image("Reference", "Reference", reference, pixelScale, pixelBias)
259             << TestLog::Image("ErrorMask", "Error mask", errorMask) << TestLog::EndImageSet;
260     }
261     else if (logMode == COMPARE_LOG_RESULT)
262     {
263         if (result.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8))
264             computePixelScaleBias(result, pixelScale, pixelBias);
265 
266         log << TestLog::ImageSet(imageSetName, imageSetDesc)
267             << TestLog::Image("Result", "Result", result, pixelScale, pixelBias) << TestLog::EndImageSet;
268     }
269 
270     return isOk;
271 }
272 
273 /*--------------------------------------------------------------------*//*!
274  * \brief Per-pixel bitwise comparison
275  *
276  * This compare expects bit precision between result and reference image.
277  * Comparison fails if any pixels do not match bitwise.
278  * Reference and result format must match.
279  *
280  * This comparison can be used for any type texture formats since it does
281  * not care about types.
282  *
283  * On failure error image is generated that shows where the failing pixels
284  * are.
285  *
286  * \param log            Test log for results
287  * \param imageSetName    Name for image set when logging results
288  * \param imageSetDesc    Description for image set
289  * \param reference        Reference image
290  * \param result        Result image
291  * \param logMode        Logging mode
292  * \return true if comparison passes, false otherwise
293  *//*--------------------------------------------------------------------*/
bitwiseCompare(TestLog & log,const char * imageSetName,const char * imageSetDesc,const ConstPixelBufferAccess & reference,const ConstPixelBufferAccess & result,CompareLogMode logMode)294 bool bitwiseCompare(TestLog &log, const char *imageSetName, const char *imageSetDesc,
295                     const ConstPixelBufferAccess &reference, const ConstPixelBufferAccess &result,
296                     CompareLogMode logMode)
297 {
298     int width  = reference.getWidth();
299     int height = reference.getHeight();
300     int depth  = reference.getDepth();
301     TCU_CHECK_INTERNAL(result.getWidth() == width && result.getHeight() == height && result.getDepth() == depth);
302 
303     // Enforce texture has same channel count and channel size
304     TCU_CHECK_INTERNAL(reference.getFormat() == result.getFormat());
305     result.getPixelPitch();
306 
307     TextureLevel errorMaskStorage(TextureFormat(TextureFormat::RGB, TextureFormat::UNORM_INT8), width, height, depth);
308     PixelBufferAccess errorMask = errorMaskStorage.getAccess();
309     Vec4 pixelBias(0.0f, 0.0f, 0.0f, 0.0f);
310     Vec4 pixelScale(1.0f, 1.0f, 1.0f, 1.0f);
311     bool compareOk = true;
312 
313     for (int z = 0; z < depth; z++)
314     {
315         for (int y = 0; y < height; y++)
316         {
317             for (int x = 0; x < width; x++)
318             {
319                 const U64Vec4 refPix = reference.getPixelBitsAsUint64(x, y, z);
320                 const U64Vec4 cmpPix = result.getPixelBitsAsUint64(x, y, z);
321                 const bool isOk      = (refPix == cmpPix);
322 
323                 errorMask.setPixel(isOk ? IVec4(0, 0xff, 0, 0xff) : IVec4(0xff, 0, 0, 0xff), x, y, z);
324                 compareOk &= isOk;
325             }
326         }
327     }
328 
329     if (!compareOk || logMode == COMPARE_LOG_EVERYTHING)
330     {
331         {
332             const auto refChannelClass = tcu::getTextureChannelClass(reference.getFormat().type);
333             const auto resChannelClass = tcu::getTextureChannelClass(result.getFormat().type);
334 
335             const bool refIsUint8 = (reference.getFormat().type == TextureFormat::UNSIGNED_INT8);
336             const bool resIsUint8 = (result.getFormat().type == TextureFormat::UNSIGNED_INT8);
337 
338             const bool calcScaleBias =
339                 ((refChannelClass != tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT && !refIsUint8) ||
340                  (resChannelClass != tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT && !resIsUint8));
341 
342             // All formats except normalized unsigned fixed point ones need remapping in order to fit into unorm channels in logged images.
343             if (calcScaleBias)
344             {
345                 computeScaleAndBias(reference, result, pixelScale, pixelBias);
346                 log << TestLog::Message << "Result and reference images are normalized with formula p * " << pixelScale
347                     << " + " << pixelBias << TestLog::EndMessage;
348             }
349         }
350 
351         if (!compareOk)
352             log << TestLog::Message
353                 << "Image comparison failed: Pixels with different values were found when bitwise precision is expected"
354                 << TestLog::EndMessage;
355 
356         log << TestLog::ImageSet(imageSetName, imageSetDesc)
357             << TestLog::Image("Result", "Result", result, pixelScale, pixelBias)
358             << TestLog::Image("Reference", "Reference", reference, pixelScale, pixelBias)
359             << TestLog::Image("ErrorMask", "Error mask", errorMask) << TestLog::EndImageSet;
360     }
361     else if (logMode == COMPARE_LOG_RESULT)
362     {
363         if (result.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8))
364             computePixelScaleBias(result, pixelScale, pixelBias);
365 
366         log << TestLog::ImageSet(imageSetName, imageSetDesc)
367             << TestLog::Image("Result", "Result", result, pixelScale, pixelBias) << TestLog::EndImageSet;
368     }
369 
370     return compareOk;
371 }
372 
373 /*--------------------------------------------------------------------*//*!
374  * \brief Fuzzy image comparison using maximum error
375  *
376  * Variant of fuzzyCompare that uses the maximum error per pixel as a metric,
377  * instead of accumulating errors for the entire image.
378  *
379  * The minimum possible error is sqrt(1)/255 (~0.0039), corresponding to a
380  * 5-shade difference (1 over MIN_ERR_THRESHOLD) on one channel.
381  *
382  * The maximum possible error is sqrt(4*(251^2))/255 (~1.96), corresponding
383  * to a 255-shade difference on all four channels.
384  *
385  * This image comparison is designed for comparing images rendered by 3D
386  * graphics APIs such as OpenGL. The comparison allows small local differences
387  * and compensates for aliasing.
388  *
389  * The algorithm first performs light blurring on both images and then
390  * does per-pixel analysis. Pixels are compared to 3x3 bilinear surface
391  * defined by adjecent pixels. This compensates for both 1-pixel deviations
392  * in geometry and aliasing in texture data.
393  *
394  * On failure error image is generated that shows where the failing pixels
395  * are.
396  *
397  * \note                Currently supports only UNORM_INT8 formats
398  * \param log            Test log for results
399  * \param imageSetName    Name for image set when logging results
400  * \param imageSetDesc    Description for image set
401  * \param reference        Reference image
402  * \param result        Result image
403  * \param threshold        Error metric threshold
404  * \param logMode        Logging mode
405  * \return true if comparison passes, false otherwise
406  *//*--------------------------------------------------------------------*/
fuzzyCompareMaxError(TestLog & log,const char * imageSetName,const char * imageSetDesc,const ConstPixelBufferAccess & reference,const ConstPixelBufferAccess & result,float threshold,CompareLogMode logMode)407 bool fuzzyCompareMaxError(TestLog &log, const char *imageSetName, const char *imageSetDesc,
408                           const ConstPixelBufferAccess &reference, const ConstPixelBufferAccess &result,
409                           float threshold, CompareLogMode logMode)
410 {
411     FuzzyCompareParams params(8, true);
412     TextureLevel errorMask(TextureFormat(TextureFormat::RGB, TextureFormat::UNORM_INT8), reference.getWidth(),
413                            reference.getHeight());
414     float difference = fuzzyCompare(params, reference, result, errorMask.getAccess());
415     bool isOk        = difference <= threshold;
416     Vec4 pixelBias(0.0f, 0.0f, 0.0f, 0.0f);
417     Vec4 pixelScale(1.0f, 1.0f, 1.0f, 1.0f);
418 
419     if (!isOk || logMode == COMPARE_LOG_EVERYTHING)
420     {
421         // Generate more accurate error mask.
422         params.maxSampleSkip = 0;
423         fuzzyCompare(params, reference, result, errorMask.getAccess());
424 
425         if (result.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8) &&
426             reference.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8))
427             computeScaleAndBias(reference, result, pixelScale, pixelBias);
428 
429         if (!isOk)
430             log << TestLog::Message << "Image comparison failed: difference = " << difference
431                 << ", threshold = " << threshold << TestLog::EndMessage;
432 
433         log << TestLog::ImageSet(imageSetName, imageSetDesc)
434             << TestLog::Image("Result", "Result", result, pixelScale, pixelBias)
435             << TestLog::Image("Reference", "Reference", reference, pixelScale, pixelBias)
436             << TestLog::Image("ErrorMask", "Error mask", errorMask) << TestLog::EndImageSet;
437     }
438     else if (logMode == COMPARE_LOG_RESULT)
439     {
440         if (result.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8))
441             computePixelScaleBias(result, pixelScale, pixelBias);
442 
443         log << TestLog::ImageSet(imageSetName, imageSetDesc)
444             << TestLog::Image("Result", "Result", result, pixelScale, pixelBias) << TestLog::EndImageSet;
445     }
446 
447     return isOk;
448 }
449 
450 /*--------------------------------------------------------------------*//*!
451  * \brief Fuzzy image comparison
452  *
453  * This image comparison is designed for comparing images rendered by 3D
454  * graphics APIs such as OpenGL. The comparison allows small local differences
455  * and compensates for aliasing.
456  *
457  * The algorithm first performs light blurring on both images and then
458  * does per-pixel analysis. Pixels are compared to 3x3 bilinear surface
459  * defined by adjecent pixels. This compensates for both 1-pixel deviations
460  * in geometry and aliasing in texture data.
461  *
462  * Error metric is computed based on the differences. On valid images the
463  * metric is usually <0.01. Thus good threshold values are in range 0.02 to
464  * 0.05.
465  *
466  * On failure error image is generated that shows where the failing pixels
467  * are.
468  *
469  * \note                Currently supports only UNORM_INT8 formats
470  * \param log            Test log for results
471  * \param imageSetName    Name for image set when logging results
472  * \param imageSetDesc    Description for image set
473  * \param reference        Reference image
474  * \param result        Result image
475  * \param threshold        Error metric threshold (good values are 0.02-0.05)
476  * \param logMode        Logging mode
477  * \return true if comparison passes, false otherwise
478  *//*--------------------------------------------------------------------*/
fuzzyCompare(TestLog & log,const char * imageSetName,const char * imageSetDesc,const Surface & reference,const Surface & result,float threshold,CompareLogMode logMode)479 bool fuzzyCompare(TestLog &log, const char *imageSetName, const char *imageSetDesc, const Surface &reference,
480                   const Surface &result, float threshold, CompareLogMode logMode)
481 {
482     return fuzzyCompare(log, imageSetName, imageSetDesc, reference.getAccess(), result.getAccess(), threshold, logMode);
483 }
484 
485 /*--------------------------------------------------------------------*//*!
486  * \brief Fuzzy image comparison using maximum error
487  *
488  * Variant of fuzzyCompare that uses the maximum error per pixel as a metric,
489  * instead of accumulating errors for the entire image.
490  *
491  * The minimum possible error is sqrt(1)/255 (~0.0039), corresponding to a
492  * 5-shade difference (1 over MIN_ERR_THRESHOLD) on one channel.
493  *
494  * The maximum possible error is sqrt(4*(251^2))/255 (~1.96), corresponding
495  * to a 255-shade difference on all four channels.
496  *
497  * This image comparison is designed for comparing images rendered by 3D
498  * graphics APIs such as OpenGL. The comparison allows small local differences
499  * and compensates for aliasing.
500  *
501  * The algorithm first performs light blurring on both images and then
502  * does per-pixel analysis. Pixels are compared to 3x3 bilinear surface
503  * defined by adjecent pixels. This compensates for both 1-pixel deviations
504  * in geometry and aliasing in texture data.
505  *
506  * On failure error image is generated that shows where the failing pixels
507  * are.
508  *
509  * \note                Currently supports only UNORM_INT8 formats
510  * \param log            Test log for results
511  * \param imageSetName    Name for image set when logging results
512  * \param imageSetDesc    Description for image set
513  * \param reference        Reference image
514  * \param result        Result image
515  * \param threshold        Error metric threshold
516  * \param logMode        Logging mode
517  * \return true if comparison passes, false otherwise
518  *//*--------------------------------------------------------------------*/
fuzzyCompareMaxError(TestLog & log,const char * imageSetName,const char * imageSetDesc,const Surface & reference,const Surface & result,float threshold,CompareLogMode logMode)519 bool fuzzyCompareMaxError(TestLog &log, const char *imageSetName, const char *imageSetDesc, const Surface &reference,
520                           const Surface &result, float threshold, CompareLogMode logMode)
521 {
522     return fuzzyCompareMaxError(log, imageSetName, imageSetDesc, reference.getAccess(), result.getAccess(), threshold,
523                                 logMode);
524 }
525 
computeSquaredDiffSum(const ConstPixelBufferAccess & ref,const ConstPixelBufferAccess & cmp,const PixelBufferAccess & diffMask,int diffFactor)526 static int64_t computeSquaredDiffSum(const ConstPixelBufferAccess &ref, const ConstPixelBufferAccess &cmp,
527                                      const PixelBufferAccess &diffMask, int diffFactor)
528 {
529     TCU_CHECK_INTERNAL(ref.getFormat().type == TextureFormat::UNORM_INT8 &&
530                        cmp.getFormat().type == TextureFormat::UNORM_INT8);
531     DE_ASSERT(ref.getWidth() == cmp.getWidth() && ref.getWidth() == diffMask.getWidth());
532     DE_ASSERT(ref.getHeight() == cmp.getHeight() && ref.getHeight() == diffMask.getHeight());
533 
534     int64_t diffSum = 0;
535 
536     for (int y = 0; y < cmp.getHeight(); y++)
537     {
538         for (int x = 0; x < cmp.getWidth(); x++)
539         {
540             IVec4 a    = ref.getPixelInt(x, y);
541             IVec4 b    = cmp.getPixelInt(x, y);
542             IVec4 diff = abs(a - b);
543             int sum    = diff.x() + diff.y() + diff.z() + diff.w();
544             int sqSum  = diff.x() * diff.x() + diff.y() * diff.y() + diff.z() * diff.z() + diff.w() * diff.w();
545 
546             diffMask.setPixel(
547                 tcu::RGBA(deClamp32(sum * diffFactor, 0, 255), deClamp32(255 - sum * diffFactor, 0, 255), 0, 255)
548                     .toVec(),
549                 x, y);
550 
551             diffSum += (int64_t)sqSum;
552         }
553     }
554 
555     return diffSum;
556 }
557 
558 /*--------------------------------------------------------------------*//*!
559  * \brief Per-pixel difference accuracy metric
560  *
561  * Computes accuracy metric using per-pixel differences between reference
562  * and result images.
563  *
564  * \note                    Supports only integer- and fixed-point formats
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 bestScoreDiff        Scaling factor
571  * \param worstScoreDiff    Scaling factor
572  * \param logMode            Logging mode
573  * \return true if comparison passes, false otherwise
574  *//*--------------------------------------------------------------------*/
measurePixelDiffAccuracy(TestLog & log,const char * imageSetName,const char * imageSetDesc,const ConstPixelBufferAccess & reference,const ConstPixelBufferAccess & result,int bestScoreDiff,int worstScoreDiff,CompareLogMode logMode)575 int measurePixelDiffAccuracy(TestLog &log, const char *imageSetName, const char *imageSetDesc,
576                              const ConstPixelBufferAccess &reference, const ConstPixelBufferAccess &result,
577                              int bestScoreDiff, int worstScoreDiff, CompareLogMode logMode)
578 {
579     TextureLevel diffMask(TextureFormat(TextureFormat::RGB, TextureFormat::UNORM_INT8), reference.getWidth(),
580                           reference.getHeight());
581     int diffFactor     = 8;
582     int64_t squaredSum = computeSquaredDiffSum(reference, result, diffMask.getAccess(), diffFactor);
583     float sum          = deFloatSqrt((float)squaredSum);
584     int score          = deClamp32(
585         deFloorFloatToInt32(
586             100.0f - (de::max(sum - (float)bestScoreDiff, 0.0f) / (float)(worstScoreDiff - bestScoreDiff)) * 100.0f),
587         0, 100);
588     const int failThreshold = 10;
589     Vec4 pixelBias(0.0f, 0.0f, 0.0f, 0.0f);
590     Vec4 pixelScale(1.0f, 1.0f, 1.0f, 1.0f);
591 
592     if (logMode == COMPARE_LOG_EVERYTHING || score <= failThreshold)
593     {
594         if (result.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8) &&
595             reference.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8))
596             computeScaleAndBias(reference, result, pixelScale, pixelBias);
597 
598         log << TestLog::ImageSet(imageSetName, imageSetDesc)
599             << TestLog::Image("Result", "Result", result, pixelScale, pixelBias)
600             << TestLog::Image("Reference", "Reference", reference, pixelScale, pixelBias)
601             << TestLog::Image("DiffMask", "Difference", diffMask) << TestLog::EndImageSet;
602     }
603     else if (logMode == COMPARE_LOG_RESULT)
604     {
605         if (result.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8))
606             computePixelScaleBias(result, pixelScale, pixelBias);
607 
608         log << TestLog::ImageSet(imageSetName, imageSetDesc)
609             << TestLog::Image("Result", "Result", result, pixelScale, pixelBias) << TestLog::EndImageSet;
610     }
611 
612     if (logMode != COMPARE_LOG_ON_ERROR || score <= failThreshold)
613         log << TestLog::Integer("DiffSum", "Squared difference sum", "", QP_KEY_TAG_NONE, squaredSum)
614             << TestLog::Integer("Score", "Score", "", QP_KEY_TAG_QUALITY, score);
615 
616     return score;
617 }
618 
619 /*--------------------------------------------------------------------*//*!
620  * \brief Per-pixel difference accuracy metric
621  *
622  * Computes accuracy metric using per-pixel differences between reference
623  * and result images.
624  *
625  * \note                    Supports only integer- and fixed-point formats
626  * \param log                Test log for results
627  * \param imageSetName        Name for image set when logging results
628  * \param imageSetDesc        Description for image set
629  * \param reference            Reference image
630  * \param result            Result image
631  * \param bestScoreDiff        Scaling factor
632  * \param worstScoreDiff    Scaling factor
633  * \param logMode            Logging mode
634  * \return true if comparison passes, false otherwise
635  *//*--------------------------------------------------------------------*/
measurePixelDiffAccuracy(TestLog & log,const char * imageSetName,const char * imageSetDesc,const Surface & reference,const Surface & result,int bestScoreDiff,int worstScoreDiff,CompareLogMode logMode)636 int measurePixelDiffAccuracy(TestLog &log, const char *imageSetName, const char *imageSetDesc, const Surface &reference,
637                              const Surface &result, int bestScoreDiff, int worstScoreDiff, CompareLogMode logMode)
638 {
639     return measurePixelDiffAccuracy(log, imageSetName, imageSetDesc, reference.getAccess(), result.getAccess(),
640                                     bestScoreDiff, worstScoreDiff, logMode);
641 }
642 
643 /*--------------------------------------------------------------------*//*!
644  * Returns the index of float in a float space without denormals
645  * so that:
646  * 1) f(0.0) = 0
647  * 2) f(-0.0) = 0
648  * 3) f(b) = f(a) + 1  <==>  b = nextAfter(a)
649  *
650  * See computeFloatFlushRelaxedULPDiff for details
651  *//*--------------------------------------------------------------------*/
getPositionOfIEEEFloatWithoutDenormals(float x)652 static int32_t getPositionOfIEEEFloatWithoutDenormals(float x)
653 {
654     DE_ASSERT(!std::isnan(x)); // not valid
655 
656     if (x == 0.0f)
657         return 0;
658     else if (x < 0.0f)
659         return -getPositionOfIEEEFloatWithoutDenormals(-x);
660     else
661     {
662         DE_ASSERT(x > 0.0f);
663 
664         const tcu::Float32 f(x);
665 
666         if (f.isDenorm())
667         {
668             // Denorms are flushed to zero
669             return 0;
670         }
671         else
672         {
673             // sign is 0, and it's a normal number. Natural position is its bit
674             // pattern but since we've collapsed the denorms, we must remove
675             // the gap here too to keep the float enumeration continuous.
676             //
677             // Denormals occupy one exponent pattern. Removing one from
678             // exponent should to the trick. Add one since the removed range
679             // contained one representable value, 0.
680             return (int32_t)(f.bits() - (1u << 23u) + 1u);
681         }
682     }
683 }
684 
computeFloatFlushRelaxedULPDiff(float a,float b)685 static uint32_t computeFloatFlushRelaxedULPDiff(float a, float b)
686 {
687     if (std::isnan(a) && std::isnan(b))
688         return 0;
689     else if (std::isnan(a) || std::isnan(b))
690     {
691         return 0xFFFFFFFFu;
692     }
693     else
694     {
695         // Using the "definition 5" in Muller, Jean-Michel. "On the definition of ulp (x)" (2005)
696         // assuming a floating point space is IEEE single precision floating point space without
697         // denormals (and signed zeros).
698         const int32_t aIndex = getPositionOfIEEEFloatWithoutDenormals(a);
699         const int32_t bIndex = getPositionOfIEEEFloatWithoutDenormals(b);
700         return (uint32_t)de::abs(aIndex - bIndex);
701     }
702 }
703 
computeFlushRelaxedULPDiff(const tcu::Vec4 & a,const tcu::Vec4 & b)704 static tcu::UVec4 computeFlushRelaxedULPDiff(const tcu::Vec4 &a, const tcu::Vec4 &b)
705 {
706     return tcu::UVec4(computeFloatFlushRelaxedULPDiff(a.x(), b.x()), computeFloatFlushRelaxedULPDiff(a.y(), b.y()),
707                       computeFloatFlushRelaxedULPDiff(a.z(), b.z()), computeFloatFlushRelaxedULPDiff(a.w(), b.w()));
708 }
709 
710 /*--------------------------------------------------------------------*//*!
711  * \brief Per-pixel threshold-based comparison
712  *
713  * This compare computes per-pixel differences between result and reference
714  * image. Comparison fails if any pixels exceed the given threshold value.
715  *
716  * This comparison uses ULP (units in last place) metric for computing the
717  * difference between floating-point values and thus this function can
718  * be used only for comparing floating-point texture data. In ULP calculation
719  * the denormal numbers are allowed to be flushed to zero.
720  *
721  * On failure error image is generated that shows where the failing pixels
722  * are.
723  *
724  * \param log            Test log for results
725  * \param imageSetName    Name for image set when logging results
726  * \param imageSetDesc    Description for image set
727  * \param reference        Reference image
728  * \param result        Result image
729  * \param threshold        Maximum allowed difference
730  * \param logMode        Logging mode
731  * \return true if comparison passes, false otherwise
732  *//*--------------------------------------------------------------------*/
floatUlpThresholdCompare(TestLog & log,const char * imageSetName,const char * imageSetDesc,const ConstPixelBufferAccess & reference,const ConstPixelBufferAccess & result,const UVec4 & threshold,CompareLogMode logMode)733 bool floatUlpThresholdCompare(TestLog &log, const char *imageSetName, const char *imageSetDesc,
734                               const ConstPixelBufferAccess &reference, const ConstPixelBufferAccess &result,
735                               const UVec4 &threshold, CompareLogMode logMode)
736 {
737     int width  = reference.getWidth();
738     int height = reference.getHeight();
739     int depth  = reference.getDepth();
740     TextureLevel errorMaskStorage(TextureFormat(TextureFormat::RGB, TextureFormat::UNORM_INT8), width, height, depth);
741     PixelBufferAccess errorMask = errorMaskStorage.getAccess();
742     UVec4 maxDiff(0, 0, 0, 0);
743     Vec4 pixelBias(0.0f, 0.0f, 0.0f, 0.0f);
744     Vec4 pixelScale(1.0f, 1.0f, 1.0f, 1.0f);
745 
746     TCU_CHECK(result.getWidth() == width && result.getHeight() == height && result.getDepth() == depth);
747 
748     for (int z = 0; z < depth; z++)
749     {
750         for (int y = 0; y < height; y++)
751         {
752             for (int x = 0; x < width; x++)
753             {
754                 const Vec4 refPix = reference.getPixel(x, y, z);
755                 const Vec4 cmpPix = result.getPixel(x, y, z);
756                 const UVec4 diff  = computeFlushRelaxedULPDiff(refPix, cmpPix);
757                 const bool isOk   = boolAll(lessThanEqual(diff, threshold));
758 
759                 maxDiff = max(maxDiff, diff);
760 
761                 errorMask.setPixel(isOk ? Vec4(0.0f, 1.0f, 0.0f, 1.0f) : Vec4(1.0f, 0.0f, 0.0f, 1.0f), x, y, z);
762             }
763         }
764     }
765 
766     bool compareOk = boolAll(lessThanEqual(maxDiff, threshold));
767 
768     if (!compareOk || logMode == COMPARE_LOG_EVERYTHING)
769     {
770         // All formats except normalized unsigned fixed point ones need remapping in order to fit into unorm channels in logged images.
771         if (tcu::getTextureChannelClass(reference.getFormat().type) != tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT ||
772             tcu::getTextureChannelClass(result.getFormat().type) != tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT)
773         {
774             computeScaleAndBias(reference, result, pixelScale, pixelBias);
775             log << TestLog::Message << "Result and reference images are normalized with formula p * " << pixelScale
776                 << " + " << pixelBias << TestLog::EndMessage;
777         }
778 
779         if (!compareOk)
780             log << TestLog::Message << "Image comparison failed: max difference = " << maxDiff
781                 << ", threshold = " << threshold << TestLog::EndMessage;
782 
783         log << TestLog::ImageSet(imageSetName, imageSetDesc)
784             << TestLog::Image("Result", "Result", result, pixelScale, pixelBias)
785             << TestLog::Image("Reference", "Reference", reference, pixelScale, pixelBias)
786             << TestLog::Image("ErrorMask", "Error mask", errorMask) << TestLog::EndImageSet;
787     }
788     else if (logMode == COMPARE_LOG_RESULT)
789     {
790         if (result.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8))
791             computePixelScaleBias(result, pixelScale, pixelBias);
792 
793         log << TestLog::ImageSet(imageSetName, imageSetDesc)
794             << TestLog::Image("Result", "Result", result, pixelScale, pixelBias) << TestLog::EndImageSet;
795     }
796 
797     return compareOk;
798 }
799 
800 /*--------------------------------------------------------------------*//*!
801  * \brief Per-pixel threshold-based comparison
802  *
803  * This compare computes per-pixel differences between result and reference
804  * image. Comparison fails if any pixels exceed the given threshold value.
805  *
806  * This comparison can be used for floating-point and fixed-point formats.
807  * Difference is computed in floating-point space.
808  *
809  * On failure an error image is generated that shows where the failing
810  * pixels are.
811  *
812  * \param log            Test log for results
813  * \param imageSetName    Name for image set when logging results
814  * \param imageSetDesc    Description for image set
815  * \param reference        Reference image
816  * \param result        Result image
817  * \param threshold        Maximum allowed difference
818  * \param logMode        Logging mode
819  * \return true if comparison passes, false otherwise
820  *//*--------------------------------------------------------------------*/
floatThresholdCompare(TestLog & log,const char * imageSetName,const char * imageSetDesc,const ConstPixelBufferAccess & reference,const ConstPixelBufferAccess & result,const Vec4 & threshold,CompareLogMode logMode)821 bool floatThresholdCompare(TestLog &log, const char *imageSetName, const char *imageSetDesc,
822                            const ConstPixelBufferAccess &reference, const ConstPixelBufferAccess &result,
823                            const Vec4 &threshold, CompareLogMode logMode)
824 {
825     int width  = reference.getWidth();
826     int height = reference.getHeight();
827     int depth  = reference.getDepth();
828     TextureLevel errorMaskStorage(TextureFormat(TextureFormat::RGB, TextureFormat::UNORM_INT8), width, height, depth);
829     PixelBufferAccess errorMask = errorMaskStorage.getAccess();
830     Vec4 maxDiff(0.0f, 0.0f, 0.0f, 0.0f);
831     Vec4 pixelBias(0.0f, 0.0f, 0.0f, 0.0f);
832     Vec4 pixelScale(1.0f, 1.0f, 1.0f, 1.0f);
833 
834     TCU_CHECK_INTERNAL(result.getWidth() == width && result.getHeight() == height && result.getDepth() == depth);
835 
836     for (int z = 0; z < depth; z++)
837     {
838         for (int y = 0; y < height; y++)
839         {
840             for (int x = 0; x < width; x++)
841             {
842                 Vec4 refPix = reference.getPixel(x, y, z);
843                 Vec4 cmpPix = result.getPixel(x, y, z);
844 
845                 Vec4 diff = abs(refPix - cmpPix);
846                 bool isOk = boolAll(lessThanEqual(diff, threshold));
847 
848                 maxDiff = max(maxDiff, diff);
849 
850                 errorMask.setPixel(isOk ? Vec4(0.0f, 1.0f, 0.0f, 1.0f) : Vec4(1.0f, 0.0f, 0.0f, 1.0f), x, y, z);
851             }
852         }
853     }
854 
855     bool compareOk = boolAll(lessThanEqual(maxDiff, threshold));
856 
857     if (!compareOk || logMode == COMPARE_LOG_EVERYTHING)
858     {
859         // All formats except normalized unsigned fixed point ones need remapping in order to fit into unorm channels in logged images.
860         if (tcu::getTextureChannelClass(reference.getFormat().type) != tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT ||
861             tcu::getTextureChannelClass(result.getFormat().type) != tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT)
862         {
863             computeScaleAndBias(reference, result, pixelScale, pixelBias);
864             log << TestLog::Message << "Result and reference images are normalized with formula p * " << pixelScale
865                 << " + " << pixelBias << TestLog::EndMessage;
866         }
867 
868         if (!compareOk)
869             log << TestLog::Message << "Image comparison failed: max difference = " << maxDiff
870                 << ", threshold = " << threshold << TestLog::EndMessage;
871 
872         log << TestLog::ImageSet(imageSetName, imageSetDesc)
873             << TestLog::Image("Result", "Result", result, pixelScale, pixelBias)
874             << TestLog::Image("Reference", "Reference", reference, pixelScale, pixelBias)
875             << TestLog::Image("ErrorMask", "Error mask", errorMask) << TestLog::EndImageSet;
876     }
877     else if (logMode == COMPARE_LOG_RESULT)
878     {
879         if (result.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8))
880             computePixelScaleBias(result, pixelScale, pixelBias);
881 
882         log << TestLog::ImageSet(imageSetName, imageSetDesc)
883             << TestLog::Image("Result", "Result", result, pixelScale, pixelBias) << TestLog::EndImageSet;
884     }
885 
886     return compareOk;
887 }
888 
889 /*--------------------------------------------------------------------*//*!
890  * \brief Per-pixel threshold-based comparison with ignore key
891  *
892  * This compare computes per-pixel differences between result and reference
893  * image. Comparison fails if any pixels exceed the given threshold value.
894  *
895  * Any pixels in reference that match the ignore key are ignored.
896  *
897  * This comparison can be used for floating-point and fixed-point formats.
898  * Difference is computed in floating-point space.
899  *
900  * On failure an error image is generated that shows where the failing
901  * pixels are.
902  *
903  * \param log            Test log for results
904  * \param imageSetName    Name for image set when logging results
905  * \param imageSetDesc    Description for image set
906  * \param reference        Reference image
907  * \param result        Result image
908  * \param ignorekey     Ignore key
909  * \param threshold        Maximum allowed difference
910  * \param logMode        Logging mode
911  * \return true if comparison passes, false otherwise
912  *//*--------------------------------------------------------------------*/
floatThresholdCompare(TestLog & log,const char * imageSetName,const char * imageSetDesc,const ConstPixelBufferAccess & reference,const ConstPixelBufferAccess & result,const Vec4 & ignorekey,const Vec4 & threshold,CompareLogMode logMode)913 bool floatThresholdCompare(TestLog &log, const char *imageSetName, const char *imageSetDesc,
914                            const ConstPixelBufferAccess &reference, const ConstPixelBufferAccess &result,
915                            const Vec4 &ignorekey, const Vec4 &threshold, CompareLogMode logMode)
916 {
917     int width  = reference.getWidth();
918     int height = reference.getHeight();
919     int depth  = reference.getDepth();
920     TextureLevel errorMaskStorage(TextureFormat(TextureFormat::RGB, TextureFormat::UNORM_INT8), width, height, depth);
921     PixelBufferAccess errorMask = errorMaskStorage.getAccess();
922     Vec4 maxDiff(0.0f, 0.0f, 0.0f, 0.0f);
923     Vec4 pixelBias(0.0f, 0.0f, 0.0f, 0.0f);
924     Vec4 pixelScale(1.0f, 1.0f, 1.0f, 1.0f);
925 
926     TCU_CHECK_INTERNAL(result.getWidth() == width && result.getHeight() == height && result.getDepth() == depth);
927 
928     for (int z = 0; z < depth; z++)
929     {
930         for (int y = 0; y < height; y++)
931         {
932             for (int x = 0; x < width; x++)
933             {
934                 Vec4 refPix = reference.getPixel(x, y, z);
935                 Vec4 cmpPix = result.getPixel(x, y, z);
936 
937                 if (refPix != ignorekey)
938                 {
939 
940                     Vec4 diff = abs(refPix - cmpPix);
941                     bool isOk = boolAll(lessThanEqual(diff, threshold));
942 
943                     maxDiff = max(maxDiff, diff);
944 
945                     errorMask.setPixel(isOk ? Vec4(0.0f, 1.0f, 0.0f, 1.0f) : Vec4(1.0f, 0.0f, 0.0f, 1.0f), x, y, z);
946                 }
947             }
948         }
949     }
950 
951     bool compareOk = boolAll(lessThanEqual(maxDiff, threshold));
952 
953     if (!compareOk || logMode == COMPARE_LOG_EVERYTHING)
954     {
955         // All formats except normalized unsigned fixed point ones need remapping in order to fit into unorm channels in logged images.
956         if (tcu::getTextureChannelClass(reference.getFormat().type) != tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT ||
957             tcu::getTextureChannelClass(result.getFormat().type) != tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT)
958         {
959             computeScaleAndBias(reference, result, pixelScale, pixelBias);
960             log << TestLog::Message << "Result and reference images are normalized with formula p * " << pixelScale
961                 << " + " << pixelBias << TestLog::EndMessage;
962         }
963 
964         if (!compareOk)
965             log << TestLog::Message << "Image comparison failed: max difference = " << maxDiff
966                 << ", threshold = " << threshold << TestLog::EndMessage;
967 
968         log << TestLog::ImageSet(imageSetName, imageSetDesc)
969             << TestLog::Image("Result", "Result", result, pixelScale, pixelBias)
970             << TestLog::Image("Reference", "Reference", reference, pixelScale, pixelBias)
971             << TestLog::Image("ErrorMask", "Error mask", errorMask) << TestLog::EndImageSet;
972     }
973     else if (logMode == COMPARE_LOG_RESULT)
974     {
975         if (result.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8))
976             computePixelScaleBias(result, pixelScale, pixelBias);
977 
978         log << TestLog::ImageSet(imageSetName, imageSetDesc)
979             << TestLog::Image("Result", "Result", result, pixelScale, pixelBias) << TestLog::EndImageSet;
980     }
981 
982     return compareOk;
983 }
984 
985 /*--------------------------------------------------------------------*//*!
986  * \brief Per-pixel threshold-based comparison
987  *
988  * This compare computes per-pixel differences between result and reference
989  * color. Comparison fails if any pixels exceed the given threshold value.
990  *
991  * This comparison can be used for floating-point and fixed-point formats.
992  * Difference is computed in floating-point space.
993  *
994  * On failure an error image is generated that shows where the failing
995  * pixels are.
996  *
997  * \param log            Test log for results
998  * \param imageSetName    Name for image set when logging results
999  * \param imageSetDesc    Description for image set
1000  * \param reference        Reference color
1001  * \param result        Result image
1002  * \param threshold        Maximum allowed difference
1003  * \param logMode        Logging mode
1004  * \return true if comparison passes, false otherwise
1005  *//*--------------------------------------------------------------------*/
floatThresholdCompare(TestLog & log,const char * imageSetName,const char * imageSetDesc,const Vec4 & reference,const ConstPixelBufferAccess & result,const Vec4 & threshold,CompareLogMode logMode)1006 bool floatThresholdCompare(TestLog &log, const char *imageSetName, const char *imageSetDesc, const Vec4 &reference,
1007                            const ConstPixelBufferAccess &result, const Vec4 &threshold, CompareLogMode logMode)
1008 {
1009     const int width  = result.getWidth();
1010     const int height = result.getHeight();
1011     const int depth  = result.getDepth();
1012 
1013     TextureLevel errorMaskStorage(TextureFormat(TextureFormat::RGB, TextureFormat::UNORM_INT8), width, height, depth);
1014     PixelBufferAccess errorMask = errorMaskStorage.getAccess();
1015     Vec4 maxDiff(0.0f, 0.0f, 0.0f, 0.0f);
1016     Vec4 pixelBias(0.0f, 0.0f, 0.0f, 0.0f);
1017     Vec4 pixelScale(1.0f, 1.0f, 1.0f, 1.0f);
1018 
1019     for (int z = 0; z < depth; z++)
1020     {
1021         for (int y = 0; y < height; y++)
1022         {
1023             for (int x = 0; x < width; x++)
1024             {
1025                 const Vec4 cmpPix = result.getPixel(x, y, z);
1026                 const Vec4 diff   = abs(reference - cmpPix);
1027                 const bool isOk   = boolAll(lessThanEqual(diff, threshold));
1028 
1029                 maxDiff = max(maxDiff, diff);
1030 
1031                 if (isOk)
1032                     errorMask.setPixel(Vec4(0.0f, 1.0f, 0.0f, 1.0f), x, y, z);
1033                 else
1034                     errorMask.setPixel(Vec4(1.0f, 0.0f, 0.0f, 1.0f), x, y, z);
1035             }
1036         }
1037     }
1038 
1039     bool compareOk = boolAll(lessThanEqual(maxDiff, threshold));
1040 
1041     if (!compareOk || logMode == COMPARE_LOG_EVERYTHING)
1042     {
1043         // All formats except normalized unsigned fixed point ones need remapping in order to fit into unorm channels in logged images.
1044         if (tcu::getTextureChannelClass(result.getFormat().type) != tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT)
1045         {
1046             computeScaleAndBias(result, result, pixelScale, pixelBias);
1047             log << TestLog::Message << "Result image is normalized with formula p * " << pixelScale << " + "
1048                 << pixelBias << TestLog::EndMessage;
1049         }
1050 
1051         if (!compareOk)
1052             log << TestLog::Message << "Image comparison failed: max difference = " << maxDiff
1053                 << ", threshold = " << threshold << ", reference = " << reference << TestLog::EndMessage;
1054 
1055         log << TestLog::ImageSet(imageSetName, imageSetDesc)
1056             << TestLog::Image("Result", "Result", result, pixelScale, pixelBias)
1057             << TestLog::Image("ErrorMask", "Error mask", errorMask) << TestLog::EndImageSet;
1058     }
1059     else if (logMode == COMPARE_LOG_RESULT)
1060     {
1061         if (result.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8))
1062             computePixelScaleBias(result, pixelScale, pixelBias);
1063 
1064         log << TestLog::ImageSet(imageSetName, imageSetDesc)
1065             << TestLog::Image("Result", "Result", result, pixelScale, pixelBias) << TestLog::EndImageSet;
1066     }
1067 
1068     return compareOk;
1069 }
1070 
1071 /*--------------------------------------------------------------------*//*!
1072  * \brief Per-pixel threshold-based comparison
1073  *
1074  * This compare computes per-pixel differences between result and reference
1075  * image. Comparison fails if any pixels exceed the given threshold value.
1076  *
1077  * This comparison can be used for integer- and fixed-point texture formats.
1078  * Difference is computed in integer space.
1079  *
1080  * On failure error image is generated that shows where the failing pixels
1081  * are.
1082  *
1083  * \param log            Test log for results
1084  * \param imageSetName    Name for image set when logging results
1085  * \param imageSetDesc    Description for image set
1086  * \param reference        Reference image
1087  * \param result        Result image
1088  * \param threshold        Maximum allowed difference
1089  * \param logMode        Logging mode
1090  * \param use64Bits        Use 64-bit components when reading image data.
1091  * \return true if comparison passes, false otherwise
1092  *//*--------------------------------------------------------------------*/
intThresholdCompare(TestLog & log,const char * imageSetName,const char * imageSetDesc,const ConstPixelBufferAccess & reference,const ConstPixelBufferAccess & result,const UVec4 & threshold,CompareLogMode logMode,bool use64Bits)1093 bool intThresholdCompare(TestLog &log, const char *imageSetName, const char *imageSetDesc,
1094                          const ConstPixelBufferAccess &reference, const ConstPixelBufferAccess &result,
1095                          const UVec4 &threshold, CompareLogMode logMode, bool use64Bits)
1096 {
1097     int width  = reference.getWidth();
1098     int height = reference.getHeight();
1099     int depth  = reference.getDepth();
1100     TextureLevel errorMaskStorage(TextureFormat(TextureFormat::RGB, TextureFormat::UNORM_INT8), width, height, depth);
1101     PixelBufferAccess errorMask = errorMaskStorage.getAccess();
1102     U64Vec4 maxDiff(0u, 0u, 0u, 0u);
1103     U64Vec4 diff(0u, 0u, 0u, 0u);
1104     const U64Vec4 threshold64 = threshold.cast<uint64_t>();
1105     Vec4 pixelBias(0.0f, 0.0f, 0.0f, 0.0f);
1106     Vec4 pixelScale(1.0f, 1.0f, 1.0f, 1.0f);
1107 
1108     I64Vec4 refPix64;
1109     I64Vec4 cmpPix64;
1110     IVec4 refPix;
1111     IVec4 cmpPix;
1112 
1113     TCU_CHECK_INTERNAL(result.getWidth() == width && result.getHeight() == height && result.getDepth() == depth);
1114 
1115     for (int z = 0; z < depth; z++)
1116     {
1117         for (int y = 0; y < height; y++)
1118         {
1119             for (int x = 0; x < width; x++)
1120             {
1121                 if (use64Bits)
1122                 {
1123                     refPix64 = reference.getPixelInt64(x, y, z);
1124                     cmpPix64 = result.getPixelInt64(x, y, z);
1125                     diff     = abs(refPix64 - cmpPix64).cast<uint64_t>();
1126                 }
1127                 else
1128                 {
1129                     refPix = reference.getPixelInt(x, y, z);
1130                     cmpPix = result.getPixelInt(x, y, z);
1131                     diff   = abs(refPix - cmpPix).cast<uint64_t>();
1132                 }
1133 
1134                 maxDiff = max(maxDiff, diff);
1135 
1136                 const bool isOk = boolAll(lessThanEqual(diff, threshold64));
1137                 if (isOk)
1138                     errorMask.setPixel(IVec4(0, 0xff, 0, 0xff), x, y, z);
1139                 else
1140                     errorMask.setPixel(IVec4(0xff, 0, 0, 0xff), x, y, z);
1141             }
1142         }
1143     }
1144 
1145     bool compareOk = boolAll(lessThanEqual(maxDiff, threshold64));
1146 
1147     if (!compareOk || logMode == COMPARE_LOG_EVERYTHING)
1148     {
1149         {
1150             const auto refChannelClass = tcu::getTextureChannelClass(reference.getFormat().type);
1151             const auto resChannelClass = tcu::getTextureChannelClass(result.getFormat().type);
1152 
1153             const bool refIsUint8 = (reference.getFormat().type == TextureFormat::UNSIGNED_INT8);
1154             const bool resIsUint8 = (result.getFormat().type == TextureFormat::UNSIGNED_INT8);
1155 
1156             const bool calcScaleBias =
1157                 ((refChannelClass != tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT && !refIsUint8) ||
1158                  (resChannelClass != tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT && !resIsUint8));
1159 
1160             // All formats except normalized unsigned fixed point ones need remapping in order to fit into unorm channels in logged images.
1161             if (calcScaleBias)
1162             {
1163                 computeScaleAndBias(reference, result, pixelScale, pixelBias);
1164                 log << TestLog::Message << "Result and reference images are normalized with formula p * " << pixelScale
1165                     << " + " << pixelBias << TestLog::EndMessage;
1166             }
1167         }
1168 
1169         if (!compareOk)
1170             log << TestLog::Message << "Image comparison failed: max difference = " << maxDiff
1171                 << ", threshold = " << threshold << TestLog::EndMessage;
1172 
1173         log << TestLog::ImageSet(imageSetName, imageSetDesc)
1174             << TestLog::Image("Result", "Result", result, pixelScale, pixelBias)
1175             << TestLog::Image("Reference", "Reference", reference, pixelScale, pixelBias)
1176             << TestLog::Image("ErrorMask", "Error mask", errorMask) << TestLog::EndImageSet;
1177     }
1178     else if (logMode == COMPARE_LOG_RESULT)
1179     {
1180         if (result.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8))
1181             computePixelScaleBias(result, pixelScale, pixelBias);
1182 
1183         log << TestLog::ImageSet(imageSetName, imageSetDesc)
1184             << TestLog::Image("Result", "Result", result, pixelScale, pixelBias) << TestLog::EndImageSet;
1185     }
1186 
1187     return compareOk;
1188 }
1189 
1190 /*--------------------------------------------------------------------*//*!
1191  * \brief Per-pixel depth/stencil threshold-based comparison
1192  *
1193  * This compare computes per-pixel differences between result and reference
1194  * image. Comparison fails if any pixels exceed the given threshold value.
1195  *
1196  * This comparison can be used for depth and depth/stencil images.
1197  * Difference is computed in integer space.
1198  *
1199  * On failure error image is generated that shows where the failing pixels
1200  * are.
1201  *
1202  * \param log            Test log for results
1203  * \param imageSetName    Name for image set when logging results
1204  * \param imageSetDesc    Description for image set
1205  * \param reference        Reference image
1206  * \param result        Result image
1207  * \param threshold        Maximum allowed depth difference (stencil must be exact)
1208  * \param logMode        Logging mode
1209  * \return true if comparison passes, false otherwise
1210  *//*--------------------------------------------------------------------*/
dsThresholdCompare(TestLog & log,const char * imageSetName,const char * imageSetDesc,const ConstPixelBufferAccess & reference,const ConstPixelBufferAccess & result,const float threshold,CompareLogMode logMode)1211 bool dsThresholdCompare(TestLog &log, const char *imageSetName, const char *imageSetDesc,
1212                         const ConstPixelBufferAccess &reference, const ConstPixelBufferAccess &result,
1213                         const float threshold, CompareLogMode logMode)
1214 {
1215     int width  = reference.getWidth();
1216     int height = reference.getHeight();
1217     int depth  = reference.getDepth();
1218     TextureLevel errorLevelDepth(TextureFormat(TextureFormat::RGB, TextureFormat::UNORM_INT8), width, height, depth);
1219     TextureLevel errorLevelStencil(TextureFormat(TextureFormat::RGB, TextureFormat::UNORM_INT8), width, height, depth);
1220     PixelBufferAccess errorMaskDepth   = errorLevelDepth.getAccess();
1221     PixelBufferAccess errorMaskStencil = errorLevelStencil.getAccess();
1222     float maxDiff                      = 0.0;
1223     bool allStencilOk                  = true;
1224     bool hasDepth                      = tcu::hasDepthComponent(result.getFormat().order);
1225     bool hasStencil                    = tcu::hasStencilComponent(result.getFormat().order);
1226 
1227     TCU_CHECK_INTERNAL(result.getWidth() == width && result.getHeight() == height && result.getDepth() == depth);
1228 
1229     for (int z = 0; z < depth; z++)
1230     {
1231         for (int y = 0; y < height; y++)
1232         {
1233             for (int x = 0; x < width; x++)
1234             {
1235                 if (hasDepth)
1236                 {
1237                     float refDepth = reference.getPixDepth(x, y, z);
1238                     float cmpDepth = result.getPixDepth(x, y, z);
1239                     float diff     = de::abs(refDepth - cmpDepth);
1240 
1241                     const bool depthOk = (diff <= threshold);
1242                     maxDiff            = (float)deMax(maxDiff, diff);
1243 
1244                     if (depthOk)
1245                         errorMaskDepth.setPixel(Vec4(0.0f, 1.0f, 0.0f, 1.0f), x, y, z);
1246                     else
1247                         errorMaskDepth.setPixel(Vec4(1.0f, 0.0f, 0.0f, 1.0f), x, y, z);
1248                 }
1249 
1250                 if (hasStencil)
1251                 {
1252                     uint8_t refStencil = (uint8_t)reference.getPixStencil(x, y, z);
1253                     uint8_t cmpStencil = (uint8_t)result.getPixStencil(x, y, z);
1254 
1255                     const bool isStencilOk = (refStencil == cmpStencil);
1256 
1257                     if (isStencilOk)
1258                         errorMaskStencil.setPixel(Vec4(0.0f, 1.0f, 0.0f, 1.0f), x, y, z);
1259                     else
1260                         errorMaskStencil.setPixel(Vec4(1.0f, 0.0f, 0.0f, 1.0f), x, y, z);
1261 
1262                     allStencilOk = allStencilOk && isStencilOk;
1263                 }
1264             }
1265         }
1266     }
1267 
1268     const bool allDepthOk = (!hasDepth || (maxDiff <= threshold));
1269     bool compareOk        = allDepthOk && allStencilOk;
1270 
1271     if (!compareOk || logMode == COMPARE_LOG_EVERYTHING)
1272     {
1273         if (!compareOk)
1274         {
1275             if (maxDiff > threshold)
1276                 log << TestLog::Message << "Depth comparison failed: max difference = " << maxDiff
1277                     << ", threshold = " << threshold << TestLog::EndMessage;
1278             if (!allStencilOk)
1279                 log << TestLog::Message << "Stencil comparison failed" << TestLog::EndMessage;
1280         }
1281 
1282         log << TestLog::ImageSet(imageSetName, imageSetDesc);
1283 
1284         if (!allDepthOk)
1285         {
1286             TextureLevel refDepthLevel(TextureFormat(TextureFormat::RGB, TextureFormat::UNORM_INT8), width, height,
1287                                        depth);
1288             TextureLevel resDepthLevel(TextureFormat(TextureFormat::RGB, TextureFormat::UNORM_INT8), width, height,
1289                                        depth);
1290             tcu::PixelBufferAccess refDepthAccess = refDepthLevel.getAccess();
1291             tcu::PixelBufferAccess resDepthAccess = resDepthLevel.getAccess();
1292 
1293             for (int z = 0; z < depth; z++)
1294                 for (int y = 0; y < height; y++)
1295                     for (int x = 0; x < width; x++)
1296                     {
1297                         const float refDepth = reference.getPixDepth(x, y, z);
1298                         const float resDepth = result.getPixDepth(x, y, z);
1299                         refDepthAccess.setPixel(Vec4(refDepth, refDepth, refDepth, 1.0f), x, y, z);
1300                         resDepthAccess.setPixel(Vec4(resDepth, resDepth, resDepth, 1.0f), x, y, z);
1301                     }
1302 
1303             log << TestLog::Image("ResultDepth", "", resDepthAccess)
1304                 << TestLog::Image("ReferenceDepth", "", refDepthAccess)
1305                 << TestLog::Image("ErrorMaskDepth", "", errorMaskDepth);
1306         }
1307 
1308         if (!allStencilOk)
1309         {
1310             TextureLevel refStencilLevel(TextureFormat(TextureFormat::RGB, TextureFormat::UNORM_INT8), width, height,
1311                                          depth);
1312             TextureLevel resStencilLevel(TextureFormat(TextureFormat::RGB, TextureFormat::UNORM_INT8), width, height,
1313                                          depth);
1314             tcu::PixelBufferAccess refStencilAccess = refStencilLevel.getAccess();
1315             tcu::PixelBufferAccess resStencilAccess = resStencilLevel.getAccess();
1316 
1317             for (int z = 0; z < depth; z++)
1318                 for (int y = 0; y < height; y++)
1319                     for (int x = 0; x < width; x++)
1320                     {
1321                         const float refStencil = static_cast<float>(reference.getPixStencil(x, y, z)) / 255.0f;
1322                         const float resStencil = static_cast<float>(result.getPixStencil(x, y, z)) / 255.0f;
1323                         refStencilAccess.setPixel(Vec4(refStencil, refStencil, refStencil, 1.0f), x, y, z);
1324                         resStencilAccess.setPixel(Vec4(resStencil, resStencil, resStencil, 1.0f), x, y, z);
1325                     }
1326 
1327             log << TestLog::Image("ResultStencil", "", resStencilAccess)
1328                 << TestLog::Image("ReferenceStencil", "", refStencilAccess)
1329                 << TestLog::Image("ErrorMaskStencil", "", errorMaskStencil);
1330         }
1331 
1332         log << TestLog::EndImageSet;
1333     }
1334     else if (logMode == COMPARE_LOG_RESULT)
1335     {
1336 #if 0
1337         if (result.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8))
1338             computePixelScaleBias(result, pixelScale, pixelBias);
1339 
1340         log << TestLog::ImageSet(imageSetName, imageSetDesc)
1341             << TestLog::Image("Result", "Result", result, pixelScale, pixelBias)
1342             << TestLog::EndImageSet;
1343 #endif
1344     }
1345 
1346     return compareOk;
1347 }
1348 
1349 /*--------------------------------------------------------------------*//*!
1350  * \brief Per-pixel threshold-based deviation-ignoring comparison
1351  *
1352  * This compare computes per-pixel differences between result and reference
1353  * image. Comparison fails if there is no pixel matching the given threshold
1354  * value in the search volume.
1355  *
1356  * If the search volume contains out-of-bounds pixels, comparison can be set
1357  * to either ignore these pixels in search or to accept any pixel that has
1358  * out-of-bounds pixels in its search volume.
1359  *
1360  * This comparison can be used for integer- and fixed-point texture formats.
1361  * Difference is computed in integer space.
1362  *
1363  * On failure error image is generated that shows where the failing pixels
1364  * are.
1365  *
1366  * \param log                            Test log for results
1367  * \param imageSetName                    Name for image set when logging results
1368  * \param imageSetDesc                    Description for image set
1369  * \param reference                        Reference image
1370  * \param result                        Result image
1371  * \param threshold                        Maximum allowed difference
1372  * \param maxPositionDeviation            Maximum allowed distance in the search
1373  *                                        volume.
1374  * \param acceptOutOfBoundsAsAnyValue    Accept any pixel in the boundary region
1375  * \param logMode                        Logging mode
1376  * \return true if comparison passes, false otherwise
1377  *//*--------------------------------------------------------------------*/
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)1378 bool intThresholdPositionDeviationCompare(TestLog &log, const char *imageSetName, const char *imageSetDesc,
1379                                           const ConstPixelBufferAccess &reference, const ConstPixelBufferAccess &result,
1380                                           const UVec4 &threshold, const tcu::IVec3 &maxPositionDeviation,
1381                                           bool acceptOutOfBoundsAsAnyValue, CompareLogMode logMode)
1382 {
1383     const int width  = reference.getWidth();
1384     const int height = reference.getHeight();
1385     const int depth  = reference.getDepth();
1386     TextureLevel errorMaskStorage(TextureFormat(TextureFormat::RGB, TextureFormat::UNORM_INT8), width, height, depth);
1387     PixelBufferAccess errorMask = errorMaskStorage.getAccess();
1388     const int numFailingPixels  = findNumPositionDeviationFailingPixels(
1389         errorMask, reference, result, threshold, maxPositionDeviation, acceptOutOfBoundsAsAnyValue);
1390     const bool compareOk = numFailingPixels == 0;
1391     Vec4 pixelBias(0.0f, 0.0f, 0.0f, 0.0f);
1392     Vec4 pixelScale(1.0f, 1.0f, 1.0f, 1.0f);
1393 
1394     if (!compareOk || logMode == COMPARE_LOG_EVERYTHING)
1395     {
1396         // All formats except normalized unsigned fixed point ones need remapping in order to fit into unorm channels in logged images.
1397         if (tcu::getTextureChannelClass(reference.getFormat().type) != tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT ||
1398             tcu::getTextureChannelClass(result.getFormat().type) != tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT)
1399         {
1400             computeScaleAndBias(reference, result, pixelScale, pixelBias);
1401             log << TestLog::Message << "Result and reference images are normalized with formula p * " << pixelScale
1402                 << " + " << pixelBias << TestLog::EndMessage;
1403         }
1404 
1405         if (!compareOk)
1406             log << TestLog::Message << "Image comparison failed:\n"
1407                 << "\tallowed position deviation = " << maxPositionDeviation << "\n"
1408                 << "\tcolor threshold = " << threshold << TestLog::EndMessage;
1409 
1410         log << TestLog::ImageSet(imageSetName, imageSetDesc)
1411             << TestLog::Image("Result", "Result", result, pixelScale, pixelBias)
1412             << TestLog::Image("Reference", "Reference", reference, pixelScale, pixelBias)
1413             << TestLog::Image("ErrorMask", "Error mask", errorMask) << TestLog::EndImageSet;
1414     }
1415     else if (logMode == COMPARE_LOG_RESULT)
1416     {
1417         if (result.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8))
1418             computePixelScaleBias(result, pixelScale, pixelBias);
1419 
1420         log << TestLog::ImageSet(imageSetName, imageSetDesc)
1421             << TestLog::Image("Result", "Result", result, pixelScale, pixelBias) << TestLog::EndImageSet;
1422     }
1423 
1424     return compareOk;
1425 }
1426 
1427 /*--------------------------------------------------------------------*//*!
1428  * \brief Per-pixel threshold-based deviation-ignoring comparison
1429  *
1430  * This compare computes per-pixel differences between result and reference
1431  * image. Pixel fails the test if there is no pixel matching the given
1432  * threshold value in the search volume. Comparison fails if the number of
1433  * failing pixels exceeds the given limit.
1434  *
1435  * If the search volume contains out-of-bounds pixels, comparison can be set
1436  * to either ignore these pixels in search or to accept any pixel that has
1437  * out-of-bounds pixels in its search volume.
1438  *
1439  * This comparison can be used for integer- and fixed-point texture formats.
1440  * Difference is computed in integer space.
1441  *
1442  * On failure error image is generated that shows where the failing pixels
1443  * are.
1444  *
1445  * \param log                            Test log for results
1446  * \param imageSetName                    Name for image set when logging results
1447  * \param imageSetDesc                    Description for image set
1448  * \param reference                        Reference image
1449  * \param result                        Result image
1450  * \param threshold                        Maximum allowed difference
1451  * \param maxPositionDeviation            Maximum allowed distance in the search
1452  *                                        volume.
1453  * \param acceptOutOfBoundsAsAnyValue    Accept any pixel in the boundary region
1454  * \param maxAllowedFailingPixels        Maximum number of failing pixels
1455  * \param logMode                        Logging mode
1456  * \return true if comparison passes, false otherwise
1457  *//*--------------------------------------------------------------------*/
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)1458 bool intThresholdPositionDeviationErrorThresholdCompare(
1459     TestLog &log, const char *imageSetName, const char *imageSetDesc, const ConstPixelBufferAccess &reference,
1460     const ConstPixelBufferAccess &result, const UVec4 &threshold, const tcu::IVec3 &maxPositionDeviation,
1461     bool acceptOutOfBoundsAsAnyValue, int maxAllowedFailingPixels, CompareLogMode logMode)
1462 {
1463     const int width  = reference.getWidth();
1464     const int height = reference.getHeight();
1465     const int depth  = reference.getDepth();
1466     TextureLevel errorMaskStorage(TextureFormat(TextureFormat::RGB, TextureFormat::UNORM_INT8), width, height, depth);
1467     PixelBufferAccess errorMask = errorMaskStorage.getAccess();
1468     const int numFailingPixels  = findNumPositionDeviationFailingPixels(
1469         errorMask, reference, result, threshold, maxPositionDeviation, acceptOutOfBoundsAsAnyValue);
1470     const bool compareOk = numFailingPixels <= maxAllowedFailingPixels;
1471     Vec4 pixelBias(0.0f, 0.0f, 0.0f, 0.0f);
1472     Vec4 pixelScale(1.0f, 1.0f, 1.0f, 1.0f);
1473 
1474     if (!compareOk || logMode == COMPARE_LOG_EVERYTHING)
1475     {
1476         // All formats except normalized unsigned fixed point ones need remapping in order to fit into unorm channels in logged images.
1477         if (tcu::getTextureChannelClass(reference.getFormat().type) != tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT ||
1478             tcu::getTextureChannelClass(result.getFormat().type) != tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT)
1479         {
1480             computeScaleAndBias(reference, result, pixelScale, pixelBias);
1481             log << TestLog::Message << "Result and reference images are normalized with formula p * " << pixelScale
1482                 << " + " << pixelBias << TestLog::EndMessage;
1483         }
1484 
1485         if (!compareOk)
1486             log << TestLog::Message << "Image comparison failed:\n"
1487                 << "\tallowed position deviation = " << maxPositionDeviation << "\n"
1488                 << "\tcolor threshold = " << threshold << TestLog::EndMessage;
1489         log << TestLog::Message << "Number of failing pixels = " << numFailingPixels
1490             << ", max allowed = " << maxAllowedFailingPixels << TestLog::EndMessage;
1491 
1492         log << TestLog::ImageSet(imageSetName, imageSetDesc)
1493             << TestLog::Image("Result", "Result", result, pixelScale, pixelBias)
1494             << TestLog::Image("Reference", "Reference", reference, pixelScale, pixelBias)
1495             << TestLog::Image("ErrorMask", "Error mask", errorMask) << TestLog::EndImageSet;
1496     }
1497     else if (logMode == COMPARE_LOG_RESULT)
1498     {
1499         if (result.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8))
1500             computePixelScaleBias(result, pixelScale, pixelBias);
1501 
1502         log << TestLog::ImageSet(imageSetName, imageSetDesc)
1503             << TestLog::Image("Result", "Result", result, pixelScale, pixelBias) << TestLog::EndImageSet;
1504     }
1505 
1506     return compareOk;
1507 }
1508 
1509 /*--------------------------------------------------------------------*//*!
1510  * \brief Per-pixel threshold-based comparison
1511  *
1512  * This compare computes per-pixel differences between result and reference
1513  * image. Comparison fails if any pixels exceed the given threshold value.
1514  *
1515  * On failure error image is generated that shows where the failing pixels
1516  * are.
1517  *
1518  * \param log            Test log for results
1519  * \param imageSetName    Name for image set when logging results
1520  * \param imageSetDesc    Description for image set
1521  * \param reference        Reference image
1522  * \param result        Result image
1523  * \param threshold        Maximum allowed difference
1524  * \param logMode        Logging mode
1525  * \return true if comparison passes, false otherwise
1526  *//*--------------------------------------------------------------------*/
pixelThresholdCompare(TestLog & log,const char * imageSetName,const char * imageSetDesc,const Surface & reference,const Surface & result,const RGBA & threshold,CompareLogMode logMode)1527 bool pixelThresholdCompare(TestLog &log, const char *imageSetName, const char *imageSetDesc, const Surface &reference,
1528                            const Surface &result, const RGBA &threshold, CompareLogMode logMode)
1529 {
1530     return intThresholdCompare(log, imageSetName, imageSetDesc, reference.getAccess(), result.getAccess(),
1531                                threshold.toIVec().cast<uint32_t>(), logMode);
1532 }
1533 
1534 /*--------------------------------------------------------------------*//*!
1535  * \brief Bilinear image comparison
1536  *
1537  * \todo [pyry] Describe
1538  *
1539  * On failure error image is generated that shows where the failing pixels
1540  * are.
1541  *
1542  * \note                Currently supports only RGBA, UNORM_INT8 formats
1543  * \param log            Test log for results
1544  * \param imageSetName    Name for image set when logging results
1545  * \param imageSetDesc    Description for image set
1546  * \param reference        Reference image
1547  * \param result        Result image
1548  * \param threshold        Maximum local difference
1549  * \param logMode        Logging mode
1550  * \return true if comparison passes, false otherwise
1551  *//*--------------------------------------------------------------------*/
bilinearCompare(TestLog & log,const char * imageSetName,const char * imageSetDesc,const ConstPixelBufferAccess & reference,const ConstPixelBufferAccess & result,const RGBA threshold,CompareLogMode logMode)1552 bool bilinearCompare(TestLog &log, const char *imageSetName, const char *imageSetDesc,
1553                      const ConstPixelBufferAccess &reference, const ConstPixelBufferAccess &result,
1554                      const RGBA threshold, CompareLogMode logMode)
1555 {
1556     TextureLevel errorMask(TextureFormat(TextureFormat::RGB, TextureFormat::UNORM_INT8), reference.getWidth(),
1557                            reference.getHeight());
1558     bool isOk = bilinearCompare(reference, result, errorMask, threshold);
1559     Vec4 pixelBias(0.0f, 0.0f, 0.0f, 0.0f);
1560     Vec4 pixelScale(1.0f, 1.0f, 1.0f, 1.0f);
1561 
1562     if (!isOk || logMode == COMPARE_LOG_EVERYTHING)
1563     {
1564         if (result.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8) &&
1565             reference.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8))
1566             computeScaleAndBias(reference, result, pixelScale, pixelBias);
1567 
1568         if (!isOk)
1569             log << TestLog::Message << "Image comparison failed, threshold = " << threshold << TestLog::EndMessage;
1570 
1571         log << TestLog::ImageSet(imageSetName, imageSetDesc)
1572             << TestLog::Image("Result", "Result", result, pixelScale, pixelBias)
1573             << TestLog::Image("Reference", "Reference", reference, pixelScale, pixelBias)
1574             << TestLog::Image("ErrorMask", "Error mask", errorMask) << TestLog::EndImageSet;
1575     }
1576     else if (logMode == COMPARE_LOG_RESULT)
1577     {
1578         if (result.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8))
1579             computePixelScaleBias(result, pixelScale, pixelBias);
1580 
1581         log << TestLog::ImageSet(imageSetName, imageSetDesc)
1582             << TestLog::Image("Result", "Result", result, pixelScale, pixelBias) << TestLog::EndImageSet;
1583     }
1584 
1585     return isOk;
1586 }
1587 
1588 } // namespace tcu
1589