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