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