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