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