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 * \param use64Bits Use 64-bit components when reading image data. 742 * \return true if comparison passes, false otherwise 743 *//*--------------------------------------------------------------------*/ intThresholdCompare(TestLog & log,const char * imageSetName,const char * imageSetDesc,const ConstPixelBufferAccess & reference,const ConstPixelBufferAccess & result,const UVec4 & threshold,CompareLogMode logMode,bool use64Bits)744 bool intThresholdCompare (TestLog& log, const char* imageSetName, const char* imageSetDesc, const ConstPixelBufferAccess& reference, const ConstPixelBufferAccess& result, const UVec4& threshold, CompareLogMode logMode, bool use64Bits) 745 { 746 int width = reference.getWidth(); 747 int height = reference.getHeight(); 748 int depth = reference.getDepth(); 749 TextureLevel errorMaskStorage (TextureFormat(TextureFormat::RGB, TextureFormat::UNORM_INT8), width, height, depth); 750 PixelBufferAccess errorMask = errorMaskStorage.getAccess(); 751 U64Vec4 maxDiff (0u, 0u, 0u, 0u); 752 U64Vec4 diff (0u, 0u, 0u, 0u); 753 const U64Vec4 threshold64 = threshold.cast<deUint64>(); 754 Vec4 pixelBias (0.0f, 0.0f, 0.0f, 0.0f); 755 Vec4 pixelScale (1.0f, 1.0f, 1.0f, 1.0f); 756 757 TCU_CHECK_INTERNAL(result.getWidth() == width && result.getHeight() == height && result.getDepth() == depth); 758 759 for (int z = 0; z < depth; z++) 760 { 761 for (int y = 0; y < height; y++) 762 { 763 for (int x = 0; x < width; x++) 764 { 765 if (use64Bits) 766 { 767 I64Vec4 refPix = reference.getPixelInt64(x, y, z); 768 I64Vec4 cmpPix = result.getPixelInt64(x, y, z); 769 diff = abs(refPix - cmpPix).cast<deUint64>(); 770 } 771 else 772 { 773 IVec4 refPix = reference.getPixelInt(x, y, z); 774 IVec4 cmpPix = result.getPixelInt(x, y, z); 775 diff = abs(refPix - cmpPix).cast<deUint64>(); 776 } 777 778 maxDiff = max(maxDiff, diff); 779 780 const bool isOk = boolAll(lessThanEqual(diff, threshold64)); 781 errorMask.setPixel(isOk ? IVec4(0, 0xff, 0, 0xff) : IVec4(0xff, 0, 0, 0xff), x, y, z); 782 } 783 } 784 } 785 786 bool compareOk = boolAll(lessThanEqual(maxDiff, threshold64)); 787 788 if (!compareOk || logMode == COMPARE_LOG_EVERYTHING) 789 { 790 // All formats except normalized unsigned fixed point ones need remapping in order to fit into unorm channels in logged images. 791 if (tcu::getTextureChannelClass(reference.getFormat().type) != tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT || 792 tcu::getTextureChannelClass(result.getFormat().type) != tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT) 793 { 794 computeScaleAndBias(reference, result, pixelScale, pixelBias); 795 log << TestLog::Message << "Result and reference images are normalized with formula p * " << pixelScale << " + " << pixelBias << TestLog::EndMessage; 796 } 797 798 if (!compareOk) 799 log << TestLog::Message << "Image comparison failed: max difference = " << maxDiff << ", threshold = " << threshold << TestLog::EndMessage; 800 801 log << TestLog::ImageSet(imageSetName, imageSetDesc) 802 << TestLog::Image("Result", "Result", result, pixelScale, pixelBias) 803 << TestLog::Image("Reference", "Reference", reference, pixelScale, pixelBias) 804 << TestLog::Image("ErrorMask", "Error mask", errorMask) 805 << TestLog::EndImageSet; 806 } 807 else if (logMode == COMPARE_LOG_RESULT) 808 { 809 if (result.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8)) 810 computePixelScaleBias(result, pixelScale, pixelBias); 811 812 log << TestLog::ImageSet(imageSetName, imageSetDesc) 813 << TestLog::Image("Result", "Result", result, pixelScale, pixelBias) 814 << TestLog::EndImageSet; 815 } 816 817 return compareOk; 818 } 819 820 /*--------------------------------------------------------------------*//*! 821 * \brief Per-pixel depth/stencil threshold-based comparison 822 * 823 * This compare computes per-pixel differences between result and reference 824 * image. Comparison fails if any pixels exceed the given threshold value. 825 * 826 * This comparison can be used for depth and depth/stencil images. 827 * Difference is computed in integer space. 828 * 829 * On failure error image is generated that shows where the failing pixels 830 * are. 831 * 832 * \param log Test log for results 833 * \param imageSetName Name for image set when logging results 834 * \param imageSetDesc Description for image set 835 * \param reference Reference image 836 * \param result Result image 837 * \param threshold Maximum allowed depth difference (stencil must be exact) 838 * \param logMode Logging mode 839 * \return true if comparison passes, false otherwise 840 *//*--------------------------------------------------------------------*/ dsThresholdCompare(TestLog & log,const char * imageSetName,const char * imageSetDesc,const ConstPixelBufferAccess & reference,const ConstPixelBufferAccess & result,const float threshold,CompareLogMode logMode)841 bool dsThresholdCompare(TestLog& log, const char* imageSetName, const char* imageSetDesc, const ConstPixelBufferAccess& reference, const ConstPixelBufferAccess& result, const float threshold, CompareLogMode logMode) 842 { 843 int width = reference.getWidth(); 844 int height = reference.getHeight(); 845 int depth = reference.getDepth(); 846 TextureLevel errorMaskStorage(TextureFormat(TextureFormat::RGB, TextureFormat::UNORM_INT8), width, height, depth); 847 PixelBufferAccess errorMask = errorMaskStorage.getAccess(); 848 float maxDiff = 0.0; 849 bool allStencilOk = true; 850 bool hasDepth = tcu::hasDepthComponent(result.getFormat().order); 851 bool hasStencil = tcu::hasStencilComponent(result.getFormat().order); 852 853 TCU_CHECK_INTERNAL(result.getWidth() == width && result.getHeight() == height && result.getDepth() == depth); 854 855 for (int z = 0; z < depth; z++) 856 { 857 for (int y = 0; y < height; y++) 858 { 859 for (int x = 0; x < width; x++) 860 { 861 bool isOk = true; 862 863 if (hasDepth) 864 { 865 float refDepth = reference.getPixDepth(x, y, z); 866 float cmpDepth = result.getPixDepth(x, y, z); 867 float diff = de::abs(refDepth - cmpDepth); 868 869 isOk = diff <= threshold; 870 maxDiff = (float) deMax(maxDiff, diff); 871 } 872 873 if (hasStencil) 874 { 875 deUint8 refStencil = (deUint8) reference.getPixStencil(x, y, z); 876 deUint8 cmpStencil = (deUint8) result.getPixStencil(x, y, z); 877 878 bool isStencilOk = (refStencil == cmpStencil); 879 allStencilOk = allStencilOk && isStencilOk; 880 isOk = isOk && isStencilOk; 881 } 882 883 errorMask.setPixel(isOk ? IVec4(0, 0xff, 0, 0xff) : IVec4(0xff, 0, 0, 0xff), x, y, z); 884 } 885 } 886 } 887 888 bool compareOk = (maxDiff <= threshold) && allStencilOk; 889 890 if (!compareOk || logMode == COMPARE_LOG_EVERYTHING) 891 { 892 if (!compareOk) 893 { 894 if (maxDiff > threshold) 895 log << TestLog::Message << "Depth comparison failed: max difference = " << maxDiff << ", threshold = " << threshold << TestLog::EndMessage; 896 if (!allStencilOk) 897 log << TestLog::Message << "Stencil comparison failed" << TestLog::EndMessage; 898 } 899 900 log << TestLog::ImageSet(imageSetName, imageSetDesc) 901 // TODO: Convert depth/stencil buffers into separate depth & stencil for logging? 902 // << TestLog::Image("Result", "Result", result, pixelScale, pixelBias) 903 // << TestLog::Image("Reference", "Reference", reference, pixelScale, pixelBias) 904 << TestLog::Image("ErrorMask", "Error mask", errorMask) 905 << TestLog::EndImageSet; 906 } 907 else if (logMode == COMPARE_LOG_RESULT) 908 { 909 #if 0 910 if (result.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8)) 911 computePixelScaleBias(result, pixelScale, pixelBias); 912 913 log << TestLog::ImageSet(imageSetName, imageSetDesc) 914 << TestLog::Image("Result", "Result", result, pixelScale, pixelBias) 915 << TestLog::EndImageSet; 916 #endif 917 } 918 919 return compareOk; 920 } 921 922 /*--------------------------------------------------------------------*//*! 923 * \brief Per-pixel threshold-based deviation-ignoring comparison 924 * 925 * This compare computes per-pixel differences between result and reference 926 * image. Comparison fails if there is no pixel matching the given threshold 927 * value in the search volume. 928 * 929 * If the search volume contains out-of-bounds pixels, comparison can be set 930 * to either ignore these pixels in search or to accept any pixel that has 931 * out-of-bounds pixels in its search volume. 932 * 933 * This comparison can be used for integer- and fixed-point texture formats. 934 * Difference is computed in integer space. 935 * 936 * On failure error image is generated that shows where the failing pixels 937 * are. 938 * 939 * \param log Test log for results 940 * \param imageSetName Name for image set when logging results 941 * \param imageSetDesc Description for image set 942 * \param reference Reference image 943 * \param result Result image 944 * \param threshold Maximum allowed difference 945 * \param maxPositionDeviation Maximum allowed distance in the search 946 * volume. 947 * \param acceptOutOfBoundsAsAnyValue Accept any pixel in the boundary region 948 * \param logMode Logging mode 949 * \return true if comparison passes, false otherwise 950 *//*--------------------------------------------------------------------*/ 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)951 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) 952 { 953 const int width = reference.getWidth(); 954 const int height = reference.getHeight(); 955 const int depth = reference.getDepth(); 956 TextureLevel errorMaskStorage (TextureFormat(TextureFormat::RGB, TextureFormat::UNORM_INT8), width, height, depth); 957 PixelBufferAccess errorMask = errorMaskStorage.getAccess(); 958 const int numFailingPixels = findNumPositionDeviationFailingPixels(errorMask, reference, result, threshold, maxPositionDeviation, acceptOutOfBoundsAsAnyValue); 959 const bool compareOk = numFailingPixels == 0; 960 Vec4 pixelBias (0.0f, 0.0f, 0.0f, 0.0f); 961 Vec4 pixelScale (1.0f, 1.0f, 1.0f, 1.0f); 962 963 if (!compareOk || logMode == COMPARE_LOG_EVERYTHING) 964 { 965 // All formats except normalized unsigned fixed point ones need remapping in order to fit into unorm channels in logged images. 966 if (tcu::getTextureChannelClass(reference.getFormat().type) != tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT || 967 tcu::getTextureChannelClass(result.getFormat().type) != tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT) 968 { 969 computeScaleAndBias(reference, result, pixelScale, pixelBias); 970 log << TestLog::Message << "Result and reference images are normalized with formula p * " << pixelScale << " + " << pixelBias << TestLog::EndMessage; 971 } 972 973 if (!compareOk) 974 log << TestLog::Message 975 << "Image comparison failed:\n" 976 << "\tallowed position deviation = " << maxPositionDeviation << "\n" 977 << "\tcolor threshold = " << threshold 978 << TestLog::EndMessage; 979 980 log << TestLog::ImageSet(imageSetName, imageSetDesc) 981 << TestLog::Image("Result", "Result", result, pixelScale, pixelBias) 982 << TestLog::Image("Reference", "Reference", reference, pixelScale, pixelBias) 983 << TestLog::Image("ErrorMask", "Error mask", errorMask) 984 << TestLog::EndImageSet; 985 } 986 else if (logMode == COMPARE_LOG_RESULT) 987 { 988 if (result.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8)) 989 computePixelScaleBias(result, pixelScale, pixelBias); 990 991 log << TestLog::ImageSet(imageSetName, imageSetDesc) 992 << TestLog::Image("Result", "Result", result, pixelScale, pixelBias) 993 << TestLog::EndImageSet; 994 } 995 996 return compareOk; 997 } 998 999 /*--------------------------------------------------------------------*//*! 1000 * \brief Per-pixel threshold-based deviation-ignoring comparison 1001 * 1002 * This compare computes per-pixel differences between result and reference 1003 * image. Pixel fails the test if there is no pixel matching the given 1004 * threshold value in the search volume. Comparison fails if the number of 1005 * failing pixels exceeds the given limit. 1006 * 1007 * If the search volume contains out-of-bounds pixels, comparison can be set 1008 * to either ignore these pixels in search or to accept any pixel that has 1009 * out-of-bounds pixels in its search volume. 1010 * 1011 * This comparison can be used for integer- and fixed-point texture formats. 1012 * Difference is computed in integer space. 1013 * 1014 * On failure error image is generated that shows where the failing pixels 1015 * are. 1016 * 1017 * \param log Test log for results 1018 * \param imageSetName Name for image set when logging results 1019 * \param imageSetDesc Description for image set 1020 * \param reference Reference image 1021 * \param result Result image 1022 * \param threshold Maximum allowed difference 1023 * \param maxPositionDeviation Maximum allowed distance in the search 1024 * volume. 1025 * \param acceptOutOfBoundsAsAnyValue Accept any pixel in the boundary region 1026 * \param maxAllowedFailingPixels Maximum number of failing pixels 1027 * \param logMode Logging mode 1028 * \return true if comparison passes, false otherwise 1029 *//*--------------------------------------------------------------------*/ 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)1030 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) 1031 { 1032 const int width = reference.getWidth(); 1033 const int height = reference.getHeight(); 1034 const int depth = reference.getDepth(); 1035 TextureLevel errorMaskStorage (TextureFormat(TextureFormat::RGB, TextureFormat::UNORM_INT8), width, height, depth); 1036 PixelBufferAccess errorMask = errorMaskStorage.getAccess(); 1037 const int numFailingPixels = findNumPositionDeviationFailingPixels(errorMask, reference, result, threshold, maxPositionDeviation, acceptOutOfBoundsAsAnyValue); 1038 const bool compareOk = numFailingPixels <= maxAllowedFailingPixels; 1039 Vec4 pixelBias (0.0f, 0.0f, 0.0f, 0.0f); 1040 Vec4 pixelScale (1.0f, 1.0f, 1.0f, 1.0f); 1041 1042 if (!compareOk || logMode == COMPARE_LOG_EVERYTHING) 1043 { 1044 // All formats except normalized unsigned fixed point ones need remapping in order to fit into unorm channels in logged images. 1045 if (tcu::getTextureChannelClass(reference.getFormat().type) != tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT || 1046 tcu::getTextureChannelClass(result.getFormat().type) != tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT) 1047 { 1048 computeScaleAndBias(reference, result, pixelScale, pixelBias); 1049 log << TestLog::Message << "Result and reference images are normalized with formula p * " << pixelScale << " + " << pixelBias << TestLog::EndMessage; 1050 } 1051 1052 if (!compareOk) 1053 log << TestLog::Message 1054 << "Image comparison failed:\n" 1055 << "\tallowed position deviation = " << maxPositionDeviation << "\n" 1056 << "\tcolor threshold = " << threshold 1057 << TestLog::EndMessage; 1058 log << TestLog::Message << "Number of failing pixels = " << numFailingPixels << ", max allowed = " << maxAllowedFailingPixels << TestLog::EndMessage; 1059 1060 log << TestLog::ImageSet(imageSetName, imageSetDesc) 1061 << TestLog::Image("Result", "Result", result, pixelScale, pixelBias) 1062 << TestLog::Image("Reference", "Reference", reference, pixelScale, pixelBias) 1063 << TestLog::Image("ErrorMask", "Error mask", errorMask) 1064 << TestLog::EndImageSet; 1065 } 1066 else if (logMode == COMPARE_LOG_RESULT) 1067 { 1068 if (result.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8)) 1069 computePixelScaleBias(result, pixelScale, pixelBias); 1070 1071 log << TestLog::ImageSet(imageSetName, imageSetDesc) 1072 << TestLog::Image("Result", "Result", result, pixelScale, pixelBias) 1073 << TestLog::EndImageSet; 1074 } 1075 1076 return compareOk; 1077 } 1078 1079 /*--------------------------------------------------------------------*//*! 1080 * \brief Per-pixel threshold-based comparison 1081 * 1082 * This compare computes per-pixel differences between result and reference 1083 * image. Comparison fails if any pixels exceed the given threshold value. 1084 * 1085 * On failure error image is generated that shows where the failing pixels 1086 * are. 1087 * 1088 * \param log Test log for results 1089 * \param imageSetName Name for image set when logging results 1090 * \param imageSetDesc Description for image set 1091 * \param reference Reference image 1092 * \param result Result image 1093 * \param threshold Maximum allowed difference 1094 * \param logMode Logging mode 1095 * \return true if comparison passes, false otherwise 1096 *//*--------------------------------------------------------------------*/ pixelThresholdCompare(TestLog & log,const char * imageSetName,const char * imageSetDesc,const Surface & reference,const Surface & result,const RGBA & threshold,CompareLogMode logMode)1097 bool pixelThresholdCompare (TestLog& log, const char* imageSetName, const char* imageSetDesc, const Surface& reference, const Surface& result, const RGBA& threshold, CompareLogMode logMode) 1098 { 1099 return intThresholdCompare(log, imageSetName, imageSetDesc, reference.getAccess(), result.getAccess(), threshold.toIVec().cast<deUint32>(), logMode); 1100 } 1101 1102 /*--------------------------------------------------------------------*//*! 1103 * \brief Bilinear image comparison 1104 * 1105 * \todo [pyry] Describe 1106 * 1107 * On failure error image is generated that shows where the failing pixels 1108 * are. 1109 * 1110 * \note Currently supports only RGBA, UNORM_INT8 formats 1111 * \param log Test log for results 1112 * \param imageSetName Name for image set when logging results 1113 * \param imageSetDesc Description for image set 1114 * \param reference Reference image 1115 * \param result Result image 1116 * \param threshold Maximum local difference 1117 * \param logMode Logging mode 1118 * \return true if comparison passes, false otherwise 1119 *//*--------------------------------------------------------------------*/ bilinearCompare(TestLog & log,const char * imageSetName,const char * imageSetDesc,const ConstPixelBufferAccess & reference,const ConstPixelBufferAccess & result,const RGBA threshold,CompareLogMode logMode)1120 bool bilinearCompare (TestLog& log, const char* imageSetName, const char* imageSetDesc, const ConstPixelBufferAccess& reference, const ConstPixelBufferAccess& result, const RGBA threshold, CompareLogMode logMode) 1121 { 1122 TextureLevel errorMask (TextureFormat(TextureFormat::RGB, TextureFormat::UNORM_INT8), reference.getWidth(), reference.getHeight()); 1123 bool isOk = bilinearCompare(reference, result, errorMask, threshold); 1124 Vec4 pixelBias (0.0f, 0.0f, 0.0f, 0.0f); 1125 Vec4 pixelScale (1.0f, 1.0f, 1.0f, 1.0f); 1126 1127 if (!isOk || logMode == COMPARE_LOG_EVERYTHING) 1128 { 1129 if (result.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8) && reference.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8)) 1130 computeScaleAndBias(reference, result, pixelScale, pixelBias); 1131 1132 if (!isOk) 1133 log << TestLog::Message << "Image comparison failed, threshold = " << threshold << TestLog::EndMessage; 1134 1135 log << TestLog::ImageSet(imageSetName, imageSetDesc) 1136 << TestLog::Image("Result", "Result", result, pixelScale, pixelBias) 1137 << TestLog::Image("Reference", "Reference", reference, pixelScale, pixelBias) 1138 << TestLog::Image("ErrorMask", "Error mask", errorMask) 1139 << TestLog::EndImageSet; 1140 } 1141 else if (logMode == COMPARE_LOG_RESULT) 1142 { 1143 if (result.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8)) 1144 computePixelScaleBias(result, pixelScale, pixelBias); 1145 1146 log << TestLog::ImageSet(imageSetName, imageSetDesc) 1147 << TestLog::Image("Result", "Result", result, pixelScale, pixelBias) 1148 << TestLog::EndImageSet; 1149 } 1150 1151 return isOk; 1152 } 1153 1154 } // tcu 1155