tcuImageCompare.js (35650B)
1 /*------------------------------------------------------------------------- 2 * drawElements Quality Program OpenGL ES Utilities 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 21 'use strict'; 22 goog.provide('framework.common.tcuImageCompare'); 23 goog.require('framework.common.tcuBilinearImageCompare'); 24 goog.require('framework.common.tcuFloat'); 25 goog.require('framework.common.tcuFuzzyImageCompare'); 26 goog.require('framework.common.tcuLogImage'); 27 goog.require('framework.common.tcuRGBA'); 28 goog.require('framework.common.tcuSurface'); 29 goog.require('framework.common.tcuTexture'); 30 goog.require('framework.common.tcuTextureUtil'); 31 goog.require('framework.delibs.debase.deMath'); 32 33 goog.scope(function() { 34 35 var tcuImageCompare = framework.common.tcuImageCompare; 36 var tcuSurface = framework.common.tcuSurface; 37 var deMath = framework.delibs.debase.deMath; 38 var tcuTexture = framework.common.tcuTexture; 39 var tcuTextureUtil = framework.common.tcuTextureUtil; 40 var tcuFloat = framework.common.tcuFloat; 41 var tcuFuzzyImageCompare = framework.common.tcuFuzzyImageCompare; 42 var tcuBilinearImageCompare = framework.common.tcuBilinearImageCompare; 43 var tcuRGBA = framework.common.tcuRGBA; 44 var tcuLogImage = framework.common.tcuLogImage; 45 46 /** 47 * @enum 48 */ 49 tcuImageCompare.CompareLogMode = { 50 EVERYTHING: 0, 51 RESULT: 1, 52 ON_ERROR: 2 53 }; 54 55 /** 56 * @param {framework.common.tcuTexture.ConstPixelBufferAccess} result 57 * @param {framework.common.tcuTexture.ConstPixelBufferAccess} reference 58 * @param {framework.common.tcuTexture.ConstPixelBufferAccess=} diff 59 */ 60 tcuImageCompare.displayImages = function(result, reference, diff) { 61 var limits = tcuImageCompare.computeScaleAndBias(reference, result); 62 tcuLogImage.logImage('Result', '', result, limits.scale, limits.bias); 63 tcuLogImage.logImage('Reference', '', reference, limits.scale, limits.bias); 64 if (diff) 65 tcuLogImage.logImage('Error', 'error mask', diff); 66 }; 67 68 /** 69 * @param {tcuTexture.ConstPixelBufferAccess} reference 70 * @param {tcuTexture.ConstPixelBufferAccess} result 71 * @return {{scale: Array<number>, bias: Array<number>}} 72 */ 73 tcuImageCompare.computeScaleAndBias = function(reference, result) { 74 var minVal = []; 75 var maxVal = []; 76 var scale = []; 77 var bias = []; 78 79 var eps = 0.0001; 80 var referenceRange = tcuTextureUtil.estimatePixelValueRange(reference); 81 var resultRange = tcuTextureUtil.estimatePixelValueRange(result); 82 83 minVal[0] = Math.min(referenceRange[0][0], resultRange[0][0]); 84 minVal[1] = Math.min(referenceRange[0][1], resultRange[0][1]); 85 minVal[2] = Math.min(referenceRange[0][2], resultRange[0][2]); 86 minVal[3] = Math.min(referenceRange[0][3], resultRange[0][3]); 87 88 maxVal[0] = Math.max(referenceRange[1][0], resultRange[1][0]); 89 maxVal[1] = Math.max(referenceRange[1][1], resultRange[1][1]); 90 maxVal[2] = Math.max(referenceRange[1][2], resultRange[1][2]); 91 maxVal[3] = Math.max(referenceRange[1][3], resultRange[1][3]); 92 93 for (var c = 0; c < 4; c++) { 94 if (maxVal[c] - minVal[c] < eps) { 95 scale[c] = (maxVal[c] < eps) ? 1 : (1 / maxVal[c]); 96 bias[c] = (c == 3) ? (1 - maxVal[c] * scale[c]) : (0 - minVal[c] * scale[c]); 97 } else { 98 scale[c] = 1 / (maxVal[c] - minVal[c]); 99 bias[c] = 0 - minVal[c] * scale[c]; 100 } 101 } 102 return { 103 scale: scale, 104 bias: bias 105 }; 106 }; 107 108 /** 109 * \brief Per-pixel threshold-based comparison 110 * 111 * This compare computes per-pixel differences between result and reference 112 * image. Comparison fails if any pixels exceed the given threshold value. 113 * 114 * This comparison can be used for integer- and fixed-point texture formats. 115 * Difference is computed in integer space. 116 * 117 * On failure error image is generated that shows where the failing pixels 118 * are. 119 * 120 * @param {string} imageSetName Name for image set when logging results 121 * @param {string} imageSetDesc Description for image set 122 * @param {tcuTexture.ConstPixelBufferAccess} reference Reference image 123 * @param {tcuTexture.ConstPixelBufferAccess} result Result image 124 * @param {Array<number>} threshold Maximum allowed difference 125 * @param {tcuImageCompare.CompareLogMode=} logMode 126 * @param {Array< Array<number> >} skipPixels pixels that are skipped comparison 127 * @return {boolean} true if comparison passes, false otherwise 128 */ 129 tcuImageCompare.intThresholdCompare = function(imageSetName, imageSetDesc, reference, result, threshold, logMode, skipPixels) { 130 var width = reference.getWidth(); 131 var height = reference.getHeight(); 132 var depth = reference.getDepth(); 133 var errorMask = new tcuSurface.Surface(width, height); 134 135 var maxDiff = [0, 0, 0, 0]; 136 // var pixelBias = [0, 0, 0, 0]; // Vec4 // TODO: check, only used in computeScaleAndBias, which is not included 137 // var pixelScale = [1, 1, 1, 1]; // Vec4 // TODO: check, only used in computeScaleAndBias 138 139 assertMsgOptions(result.getWidth() == width && result.getHeight() == height && result.getDepth() == depth, 140 'Reference and result images have different dimensions', false, true); 141 142 for (var z = 0; z < depth; z++) { 143 for (var y = 0; y < height; y++) { 144 for (var x = 0; x < width; x++) { 145 if (skipPixels && skipPixels.length > 0) { 146 var skip = false; 147 for (var ii = 0; ii < skipPixels.length; ++ii) { 148 var refZ = (skipPixels[ii].length > 2 ? skipPixels[ii][2] : 0); 149 if (x == skipPixels[ii][0] && y == skipPixels[ii][1] && z == refZ) { 150 skip = true; 151 break; 152 } 153 } 154 if (skip) 155 continue; 156 } 157 var refPix = reference.getPixelInt(x, y, z); 158 var cmpPix = result.getPixelInt(x, y, z); 159 160 var diff = deMath.absDiff(refPix, cmpPix); 161 var isOk = deMath.boolAll(deMath.lessThanEqual(diff, threshold)); 162 163 maxDiff = deMath.max(maxDiff, diff); 164 var color = [0, 255, 0, 255]; 165 if (!isOk) 166 color = [255, 0, 0, 255]; 167 errorMask.setPixel(x, y, color); 168 } 169 } 170 } 171 172 var compareOk = deMath.boolAll(deMath.lessThanEqual(maxDiff, threshold)); 173 174 if (!compareOk) { 175 debug('Image comparison failed: max difference = ' + maxDiff + ', threshold = ' + threshold); 176 tcuImageCompare.displayImages(result, reference, errorMask.getAccess()); 177 } 178 179 return compareOk; 180 }; 181 182 /** 183 * \brief Per-pixel threshold-based deviation-ignoring comparison 184 * 185 * This compare computes per-pixel differences between result and reference 186 * image. Pixel fails the test if there is no pixel matching the given 187 * threshold value in the search volume. Comparison fails if the number of 188 * failing pixels exceeds the given limit. 189 * 190 * If the search volume contains out-of-bounds pixels, comparison can be set 191 * to either ignore these pixels in search or to accept any pixel that has 192 * out-of-bounds pixels in its search volume. 193 * 194 * This comparison can be used for integer- and fixed-point texture formats. 195 * Difference is computed in integer space. 196 * 197 * On failure error image is generated that shows where the failing pixels 198 * are. 199 * 200 * @param {string} imageSetName Name for image set when logging results 201 * @param {string} imageSetDesc Description for image set 202 * @param {tcuTexture.ConstPixelBufferAccess} reference Reference image 203 * @param {tcuTexture.ConstPixelBufferAccess} result Result image 204 * @param {Array<number>} threshold Maximum allowed difference 205 * @param {Array<number>} maxPositionDeviation Maximum allowed distance in the search volume. 206 * @param {boolean} acceptOutOfBoundsAsAnyValue Accept any pixel in the boundary region 207 * @param {number} maxAllowedFailingPixels Maximum number of failing pixels 208 * @return {boolean} true if comparison passes, false otherwise 209 */ 210 tcuImageCompare.intThresholdPositionDeviationErrorThresholdCompare = function( 211 imageSetName, imageSetDesc, reference, result, threshold, maxPositionDeviation, acceptOutOfBoundsAsAnyValue, maxAllowedFailingPixels) { 212 /** @type {number} */ var width = reference.getWidth(); 213 /** @type {number} */ var height = reference.getHeight(); 214 /** @type {number} */ var depth = reference.getDepth(); 215 /** @type {tcuSurface.Surface} */ var errorMask = new tcuSurface.Surface(width, height); 216 /** @type {number} */ var numFailingPixels = tcuImageCompare.findNumPositionDeviationFailingPixels(errorMask.getAccess(), reference, result, threshold, maxPositionDeviation, acceptOutOfBoundsAsAnyValue); 217 var compareOk = numFailingPixels <= maxAllowedFailingPixels; 218 /** @type {Array<number>} */ var pixelBias = [0.0, 0.0, 0.0, 0.0]; 219 /** @type {Array<number>} */ var pixelScale = [1.0, 1.0, 1.0, 1.0]; 220 221 if (!compareOk) { 222 debug('Position deviation error threshold image comparison failed: failed pixels = ' + numFailingPixels + ', threshold = ' + threshold); 223 tcuImageCompare.displayImages(result, reference, errorMask.getAccess()); 224 } else 225 tcuLogImage.logImage('Result', '', result); 226 227 /*if (!compareOk) { 228 // All formats except normalized unsigned fixed point ones need remapping in order to fit into unorm channels in logged images. 229 if (tcuTexture.getTextureChannelClass(reference.getFormat().type) != tcuTexture.TextureChannelClass.UNSIGNED_FIXED_POINT || 230 tcuTexture.getTextureChannelClass(result.getFormat().type) != tcuTexture.TextureChannelClass.UNSIGNED_FIXED_POINT) { 231 computeScaleAndBias(reference, result, pixelScale, pixelBias); 232 log << TestLog::Message << "Result and reference images are normalized with formula p * " << pixelScale << " + " << pixelBias << TestLog::EndMessage; 233 } 234 235 if (!compareOk) 236 log << TestLog::Message 237 << "Image comparison failed:\n" 238 << "\tallowed position deviation = " << maxPositionDeviation << "\n" 239 << "\tcolor threshold = " << threshold 240 << TestLog::EndMessage; 241 log << TestLog::Message << "Number of failing pixels = " << numFailingPixels << ", max allowed = " << maxAllowedFailingPixels << TestLog::EndMessage; 242 243 log << TestLog::ImageSet(imageSetName, imageSetDesc) 244 << TestLog::Image("Result", "Result", result, pixelScale, pixelBias) 245 << TestLog::Image("Reference", "Reference", reference, pixelScale, pixelBias) 246 << TestLog::Image("ErrorMask", "Error mask", errorMask) 247 << TestLog::EndImageSet; 248 } else if (logMode == COMPARE_LOG_RESULT) { 249 if (result.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8)) 250 computePixelScaleBias(result, pixelScale, pixelBias); 251 252 log << TestLog::ImageSet(imageSetName, imageSetDesc) 253 << TestLog::Image("Result", "Result", result, pixelScale, pixelBias) 254 << TestLog::EndImageSet; 255 }*/ 256 257 return compareOk; 258 }; 259 260 /** 261 * tcuImageCompare.floatUlpThresholdCompare 262 * @param {string} imageSetName 263 * @param {string} imageSetDesc 264 * @param {tcuTexture.ConstPixelBufferAccess} reference 265 * @param {tcuTexture.ConstPixelBufferAccess} result 266 * @param {Array<number>} threshold - previously used as an Uint32Array 267 * @return {boolean} 268 */ 269 tcuImageCompare.floatUlpThresholdCompare = function(imageSetName, imageSetDesc, reference, result, threshold) { 270 /** @type {number} */ var width = reference.getWidth(); 271 /** @type {number} */ var height = reference.getHeight(); 272 /** @type {number} */ var depth = reference.getDepth(); 273 /** @type {tcuSurface.Surface} */ var errorMask = new tcuSurface.Surface(width, height); 274 275 /** @type {Array<number>} */ var maxDiff = [0, 0, 0, 0]; // UVec4 276 // var pixelBias = [0, 0, 0, 0]; // Vec4 277 // var pixelScale = [1, 1, 1, 1]; // Vec4 278 279 assertMsgOptions(result.getWidth() == width && result.getHeight() == height && result.getDepth() == depth, 280 'Reference and result images have different dimensions', false, true); 281 282 for (var z = 0; z < depth; z++) { 283 for (var y = 0; y < height; y++) { 284 for (var x = 0; x < width; x++) { 285 /** @type {ArrayBuffer} */ var arrayBufferRef = new ArrayBuffer(4 * 4); 286 /** @type {ArrayBuffer} */ var arrayBufferCmp = new ArrayBuffer(4 * 4); 287 288 /** @type {Array<number>} */ var refPix = reference.getPixel(x, y, z); // getPixel returns a Vec4 pixel color 289 290 /** @type {Array<number>} */ var cmpPix = result.getPixel(x, y, z); // getPixel returns a Vec4 pixel color 291 292 /** @type {Uint32Array} */ var refBits = new Uint32Array(arrayBufferRef); // UVec4 293 /** @type {Uint32Array} */ var cmpBits = new Uint32Array(arrayBufferCmp); // UVec4 294 295 // Instead of memcpy(), which is the way to do float->uint32 reinterpretation in C++ 296 for (var i = 0; i < refPix.length; i++) { 297 refBits[i] = tcuFloat.convertFloat32Inline(refPix[i], tcuFloat.description32); 298 cmpBits[i] = tcuFloat.convertFloat32Inline(cmpPix[i], tcuFloat.description32); 299 } 300 301 /** @type {Array<number>} */ var diff = deMath.absDiff(refBits, cmpBits); // UVec4 302 /** @type {boolean} */ var isOk = deMath.boolAll(deMath.lessThanEqual(diff, threshold)); 303 304 maxDiff = deMath.max(maxDiff, diff); 305 306 errorMask.setPixel(x, y, isOk ? [0, 255, 0, 255] : [255, 0, 0, 255]); 307 } 308 } 309 } 310 311 /** @type {boolean} */ var compareOk = deMath.boolAll(deMath.lessThanEqual(maxDiff, threshold)); 312 313 if (!compareOk) { 314 debug('Image comparison failed: max difference = ' + maxDiff + ', threshold = ' + threshold); 315 tcuImageCompare.displayImages(result, reference, errorMask.getAccess()); 316 } 317 318 /*if (!compareOk || logMode == COMPARE_LOG_EVERYTHING) { 319 // All formats except normalized unsigned fixed point ones need remapping in order to fit into unorm channels in logged images. 320 if (tcu::getTextureChannelClass(reference.getFormat().type) != tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT || 321 tcu::getTextureChannelClass(result.getFormat().type) != tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT) { 322 computeScaleAndBias(reference, result, pixelScale, pixelBias); 323 log << TestLog::Message << "Result and reference images are normalized with formula p * " << pixelScale << " + " << pixelBias << TestLog::EndMessage; 324 } 325 326 if (!compareOk) 327 log << TestLog::Message << "Image comparison failed: max difference = " << maxDiff << ", threshold = " << threshold << TestLog::EndMessage; 328 329 log << TestLog::ImageSet(imageSetName, imageSetDesc) 330 << TestLog::Image("Result", "Result", result, pixelScale, pixelBias) 331 << TestLog::Image("Reference", "Reference", reference, pixelScale, pixelBias) 332 << TestLog::Image("ErrorMask", "Error mask", errorMask) 333 << TestLog::EndImageSet; 334 } else if (logMode == COMPARE_LOG_RESULT) { 335 if (result.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8)) 336 computePixelScaleBias(result, pixelScale, pixelBias); 337 338 log << TestLog::ImageSet(imageSetName, imageSetDesc) 339 << TestLog::Image("Result", "Result", result, pixelScale, pixelBias) 340 << TestLog::EndImageSet; 341 }*/ 342 343 return compareOk; 344 }; 345 346 /** 347 * tcuImageCompare.floatThresholdCompare 348 * @param {string} imageSetName 349 * @param {string} imageSetDesc 350 * @param {tcuTexture.ConstPixelBufferAccess} reference 351 * @param {tcuTexture.ConstPixelBufferAccess} result 352 * @param {Array<number>} threshold 353 * @return {boolean} 354 */ 355 tcuImageCompare.floatThresholdCompare = function(imageSetName, imageSetDesc, reference, result, threshold) { 356 /** @type {number} */ var width = reference.getWidth(); 357 /** @type {number} */ var height = reference.getHeight(); 358 /** @type {number} */ var depth = reference.getDepth(); 359 /** @type {tcuSurface.Surface} */ var errorMask = new tcuSurface.Surface(width, height); 360 361 /** @type {Array<number>} */ var maxDiff = [0, 0, 0, 0]; // Vec4 362 // var pixelBias = [0, 0, 0, 0]; // Vec4 363 // var pixelScale = [1, 1, 1, 1]; // Vec4 364 365 assertMsgOptions(result.getWidth() == width && result.getHeight() == height && result.getDepth() == depth, 366 'Reference and result images have different dimensions', false, true); 367 368 for (var z = 0; z < depth; z++) { 369 for (var y = 0; y < height; y++) { 370 for (var x = 0; x < width; x++) { 371 var refPix = reference.getPixel(x, y, z); // Vec4 372 var cmpPix = result.getPixel(x, y, z); // Vec4 373 374 /** @type {Array<number>} */ var diff = deMath.absDiff(refPix, cmpPix); // Vec4 375 /** @type {boolean} */ var isOk = deMath.boolAll(deMath.lessThanEqual(diff, threshold)); 376 377 maxDiff = deMath.max(maxDiff, diff); 378 379 errorMask.setPixel(x, y, isOk ? [0, 255, 0, 255] : [255, 0, 0, 255]); 380 } 381 } 382 } 383 384 /** @type {boolean} */ var compareOk = deMath.boolAll(deMath.lessThanEqual(maxDiff, threshold)); 385 386 if (!compareOk) { 387 debug('Image comparison failed: max difference = ' + maxDiff + ', threshold = ' + threshold); 388 tcuImageCompare.displayImages(result, reference, errorMask.getAccess()); 389 } 390 391 /*if (!compareOk || logMode == COMPARE_LOG_EVERYTHING) { 392 // All formats except normalized unsigned fixed point ones need remapping in order to fit into unorm channels in logged images. 393 if (tcu::getTextureChannelClass(reference.getFormat().type) != tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT || 394 tcu::getTextureChannelClass(result.getFormat().type) != tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT) { 395 computeScaleAndBias(reference, result, pixelScale, pixelBias); 396 log << TestLog::Message << "Result and reference images are normalized with formula p * " << pixelScale << " + " << pixelBias << TestLog::EndMessage; 397 } 398 399 if (!compareOk) 400 log << TestLog::Message << "Image comparison failed: max difference = " << maxDiff << ", threshold = " << threshold << TestLog::EndMessage; 401 402 log << TestLog::ImageSet(imageSetName, imageSetDesc) 403 << TestLog::Image("Result", "Result", result, pixelScale, pixelBias) 404 << TestLog::Image("Reference", "Reference", reference, pixelScale, pixelBias) 405 << TestLog::Image("ErrorMask", "Error mask", errorMask) 406 << TestLog::EndImageSet; 407 } else if (logMode == COMPARE_LOG_RESULT) { 408 if (result.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8)) 409 computePixelScaleBias(result, pixelScale, pixelBias); 410 411 log << TestLog::ImageSet(imageSetName, imageSetDesc) 412 << TestLog::Image("Result", "Result", result, pixelScale, pixelBias) 413 << TestLog::EndImageSet; 414 }*/ 415 416 return compareOk; 417 }; 418 419 /** 420 * \brief Per-pixel threshold-based comparison 421 * 422 * This compare computes per-pixel differences between result and reference 423 * image. Comparison fails if any pixels exceed the given threshold value. 424 * 425 * On failure error image is generated that shows where the failing pixels 426 * are. 427 * 428 * @param {string} imageSetName Name for image set when logging results 429 * @param {string} imageSetDesc Description for image set 430 * @param {tcuSurface.Surface} reference Reference image 431 * @param {tcuSurface.Surface} result Result image 432 * @param {Array<number>} threshold Maximum allowed difference 433 * @param {tcuImageCompare.CompareLogMode=} logMode 434 * @param {Array< Array<number> >} skipPixels pixels that are skipped comparison 435 * @return {boolean} true if comparison passes, false otherwise 436 */ 437 tcuImageCompare.pixelThresholdCompare = function(imageSetName, imageSetDesc, reference, result, threshold, logMode, skipPixels) { 438 return tcuImageCompare.intThresholdCompare(imageSetName, imageSetDesc, reference.getAccess(), result.getAccess(), threshold, logMode, skipPixels); 439 }; 440 441 /** 442 * @param {tcuTexture.PixelBufferAccess} errorMask 443 * @param {tcuTexture.ConstPixelBufferAccess} reference 444 * @param {tcuTexture.ConstPixelBufferAccess} result 445 * @param {Array<number>} threshold 446 * @param {Array<number>} maxPositionDeviation 447 * @param {boolean} acceptOutOfBoundsAsAnyValue 448 * @return {number} 449 */ 450 tcuImageCompare.findNumPositionDeviationFailingPixels = function(errorMask, reference, result, threshold, maxPositionDeviation, acceptOutOfBoundsAsAnyValue) { 451 /** @type {number} */ var width = reference.getWidth(); 452 /** @type {number} */ var height = reference.getHeight(); 453 /** @type {number} */ var depth = reference.getDepth(); 454 /** @type {number} */ var numFailingPixels = 0; 455 456 checkMessage(result.getWidth() == width && result.getHeight() == height && result.getDepth() == depth, 'Surfaces have different dimensions'); 457 458 for (var z = 0; z < depth; z++) { 459 for (var y = 0; y < height; y++) { 460 for (var x = 0; x < width; x++) { 461 /** @type {Array<number>} */ var refPix = reference.getPixelInt(x, y, z); 462 /** @type {Array<number>} */ var cmpPix = result.getPixelInt(x, y, z); 463 464 // Exact match 465 /** @type {Array<number>} */ var diff = deMath.absDiff(refPix, cmpPix); 466 /** @type {boolean} */ var isOk = deMath.boolAll(deMath.lessThanEqual(diff, threshold)); 467 468 if (isOk) { 469 errorMask.setPixel([0, 0xff, 0, 0xff], x, y, z); 470 continue; 471 } 472 473 // Accept over the image bounds pixels since they could be anything 474 475 if (acceptOutOfBoundsAsAnyValue && 476 (x < maxPositionDeviation[0] || x + maxPositionDeviation[0] >= width || 477 y < maxPositionDeviation[1] || y + maxPositionDeviation[1] >= height || 478 z < maxPositionDeviation[2] || z + maxPositionDeviation[2] >= depth)) { 479 errorMask.setPixel([0, 0xff, 0, 0xff], x, y, z); 480 continue; 481 } 482 483 // Find matching pixels for both result and reference pixel 484 485 var pixelFoundForReference = false; 486 var pixelFoundForResult = false; 487 488 // Find deviated result pixel for reference 489 490 for (var sz = Math.max(0, z - maxPositionDeviation[2]); sz <= Math.min(depth - 1, z + maxPositionDeviation[2]) && !pixelFoundForReference; ++sz) 491 for (var sy = Math.max(0, y - maxPositionDeviation[1]); sy <= Math.min(height - 1, y + maxPositionDeviation[1]) && !pixelFoundForReference; ++sy) 492 for (var sx = Math.max(0, x - maxPositionDeviation[0]); sx <= Math.min(width - 1, x + maxPositionDeviation[0]) && !pixelFoundForReference; ++sx) { 493 /** @type {Array<number>} */ var deviatedCmpPix = result.getPixelInt(sx, sy, sz); 494 diff = deMath.absDiff(refPix, deviatedCmpPix); 495 isOk = deMath.boolAll(deMath.lessThanEqual(diff, threshold)); 496 497 pixelFoundForReference |= isOk; 498 } 499 500 // Find deviated reference pixel for result 501 502 for (var sz = Math.max(0, z - maxPositionDeviation[2]); sz <= Math.min(depth - 1, z + maxPositionDeviation[2]) && !pixelFoundForResult; ++sz) 503 for (var sy = Math.max(0, y - maxPositionDeviation[1]); sy <= Math.min(height - 1, y + maxPositionDeviation[1]) && !pixelFoundForResult; ++sy) 504 for (var sx = Math.max(0, x - maxPositionDeviation[0]); sx <= Math.min(width - 1, x + maxPositionDeviation[0]) && !pixelFoundForResult; ++sx) { 505 /** @type {Array<number>} */ var deviatedRefPix = reference.getPixelInt(sx, sy, sz); 506 diff = deMath.absDiff(cmpPix, deviatedRefPix); 507 isOk = deMath.boolAll(deMath.lessThanEqual(diff, threshold)); 508 509 pixelFoundForResult |= isOk; 510 } 511 512 if (pixelFoundForReference && pixelFoundForResult) 513 errorMask.setPixel([0, 0xff, 0, 0xff], x, y, z); 514 else { 515 errorMask.setPixel([0xff, 0, 0, 0xff], x, y, z); 516 ++numFailingPixels; 517 } 518 } 519 } 520 } 521 522 return numFailingPixels; 523 }; 524 525 /** 526 * tcuImageCompare.fuzzyCompare 527 * @param {string} imageSetName 528 * @param {string} imageSetDesc 529 * @param {tcuTexture.ConstPixelBufferAccess} reference 530 * @param {tcuTexture.ConstPixelBufferAccess} result 531 * @param {number} threshold 532 * @param {tcuImageCompare.CompareLogMode=} logMode 533 * @return {boolean} 534 */ 535 tcuImageCompare.fuzzyCompare = function(imageSetName, imageSetDesc, reference, result, threshold, logMode) { 536 /** @type {tcuFuzzyImageCompare.FuzzyCompareParams} */ var params = new tcuFuzzyImageCompare.FuzzyCompareParams(); // Use defaults. 537 /** @type {tcuTexture.TextureLevel} */ var errorMask = new tcuTexture.TextureLevel( 538 new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGB, 539 tcuTexture.ChannelType.UNORM_INT8), 540 reference.getWidth(), 541 reference.getHeight() 542 ); 543 /** @type {number} */ var difference = tcuFuzzyImageCompare.fuzzyCompare( 544 params, 545 reference, 546 result, 547 tcuTexture.PixelBufferAccess.newFromTextureLevel(errorMask) 548 ); 549 /** @type {boolean} */ var isOk = difference <= threshold; 550 /** @type {Array<number>} */ var pixelBias = [0.0, 0.0, 0.0, 0.0]; 551 /** @type {Array<number>} */ var pixelScale = [1.0, 1.0, 1.0, 1.0]; 552 553 if (!isOk) { 554 debug('Fuzzy image comparison failed: difference = ' + difference + ', threshold = ' + threshold); 555 tcuImageCompare.displayImages(result, reference, errorMask.getAccess()); 556 } 557 558 /* 559 if (!isOk || logMode == COMPARE_LOG_EVERYTHING) { 560 // Generate more accurate error mask. 561 params.maxSampleSkip = 0; 562 tcuImageCompare.fuzzyCompare(params, reference, result, errorMask.getAccess()); 563 564 if (result.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8) && reference.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8)) 565 computeScaleAndBias(reference, result, pixelScale, pixelBias); 566 567 if (!isOk) 568 log << TestLog::Message << "Image comparison failed: difference = " << difference << ", threshold = " << threshold << TestLog::EndMessage; 569 570 log << TestLog::ImageSet(imageSetName, imageSetDesc) 571 << TestLog::Image("Result", "Result", result, pixelScale, pixelBias) 572 << TestLog::Image("Reference", "Reference", reference, pixelScale, pixelBias) 573 << TestLog::Image("ErrorMask", "Error mask", errorMask) 574 << TestLog::EndImageSet; 575 } else if (logMode == COMPARE_LOG_RESULT) { 576 if (result.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8)) 577 computePixelScaleBias(result, pixelScale, pixelBias); 578 579 log << TestLog::ImageSet(imageSetName, imageSetDesc) 580 << TestLog::Image("Result", "Result", result, pixelScale, pixelBias) 581 << TestLog::EndImageSet; 582 } 583 */ 584 return isOk; 585 }; 586 587 tcuImageCompare.unitTest = function() { 588 var width = 128; 589 var height = 128; 590 591 var weirdLevel = new tcuTexture.TextureLevel(new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RG, tcuTexture.ChannelType.SNORM_INT32), width, height); 592 var access = weirdLevel.getAccess(); 593 access.clear([0.1, 0.5, 0, 0]); 594 access.clear([0.11, 0.52, 0, 0], [0, width], [0, height / 2]); 595 access.clear([0.12, 0.52, 0, 0], [0, width], [height / 2, height / 2 + height / 8]); 596 var limits = tcuTextureUtil.computePixelScaleBias(access); 597 debug('Scale: ' + limits.scale); 598 debug('Bias: ' + limits.bias); 599 tcuLogImage.logImage('Weird', 'weird format without scaling', access); 600 tcuLogImage.logImage('Weird', 'weird format', access, limits.scale, limits.bias); 601 602 var srcLevel = new tcuTexture.TextureLevel(new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNORM_INT8), width, height); 603 var dstLevel = new tcuTexture.TextureLevel(new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNORM_INT8), width, height); 604 var src = srcLevel.getAccess(); 605 var dst = dstLevel.getAccess(); 606 607 src.clear(); 608 dst.clear(); 609 610 for (var i = 0; i < width - 1; i++) { 611 for (var j = 0; j < height - 1; j++) { 612 src.setPixelInt([i, j, 90, 255], i, j); 613 dst.setPixelInt([i, j, 90, 255], i + 1, j + 1); 614 } 615 } 616 617 debug('Src format: ' + src.getFormat()); 618 debug('Destination: ' + dst); 619 debug(src); 620 tcuLogImage.logImage('Source', 'Source image', src); 621 622 if (!tcuImageCompare.fuzzyCompare('compare', 'compare similar images', src, dst, 0.05)) 623 throw new Error('Compare should return true'); 624 625 src.clear(); 626 dst.clear(); 627 628 for (var i = 0; i < width - 2; i++) { 629 for (var j = 0; j < height - 2; j++) { 630 src.setPixelInt([i, j, 90, 255], i, j); 631 dst.setPixelInt([i, j, 90, 255], i + 2, j + 2); 632 } 633 } 634 635 if (tcuImageCompare.fuzzyCompare('compare', 'compare different images', src, dst, 0.05)) 636 throw new Error('Compare should return false'); 637 638 debug('Passed'); 639 }; 640 641 tcuImageCompare.unitTest2 = function() { 642 var width = 128; 643 var height = 128; 644 var srcLevel = new tcuTexture.TextureLevel(new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNORM_INT8), width, height); 645 var dstLevel = new tcuTexture.TextureLevel(new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNORM_INT8), width, height); 646 var src = srcLevel.getAccess(); 647 var dst = dstLevel.getAccess(); 648 var threshold = tcuRGBA.newRGBAComponents(1, 1, 1, 1); 649 debug('Threshold: ' + threshold); 650 651 src.clear(); 652 dst.clear(); 653 654 for (var i = 0; i < width - 1; i++) { 655 for (var j = 0; j < height - 1; j++) { 656 src.setPixelInt([i, j, 90, 255], i, j); 657 dst.setPixelInt([i, j, 90, 255], i, j); 658 } 659 } 660 if (!tcuImageCompare.bilinearCompare('compare', 'compare similar images', src, dst, threshold)) 661 throw new Error('Compare should return true'); 662 debug('bilinear compare the same images passed'); 663 664 src.clear(); 665 dst.clear(); 666 667 for (var i = 0; i < width - 1; i++) { 668 for (var j = 0; j < height - 1; j++) { 669 src.setPixelInt([i, j, 90, 255], i, j); 670 dst.setPixelInt([i, j + 1, 90, 255], i, j + 1); 671 } 672 } 673 if (!tcuImageCompare.bilinearCompare('compare', 'compare similar images', src, dst, threshold)) 674 throw new Error('Compare should return true'); 675 debug('bilinear compare very similar images passed'); 676 677 src.clear(); 678 dst.clear(); 679 680 for (var i = 0; i < width - 2; i++) { 681 for (var j = 0; j < height - 2; j++) { 682 src.setPixelInt([i, j, 90, 255], i, j); 683 // dst.setPixelInt([i, j, 90, 255], i + 2, j + 2); 684 } 685 } 686 687 if (tcuImageCompare.bilinearCompare('compare', 'compare different images', src, dst, threshold)) 688 throw new Error('Compare should return false'); 689 690 debug('bilinear compare very different images passed'); 691 }; 692 693 /** 694 * Bilinear image comparison 695 * On failure error image is generated that shows where the failing pixels 696 * are. 697 * Currently supports only RGBA, UNORM_INT8 formats 698 * 699 * @param {string} imageSetName Name for image set when logging results 700 * @param {string} imageSetDesc Description for image set 701 * @param {tcuTexture.ConstPixelBufferAccess} reference Reference image 702 * @param {tcuTexture.ConstPixelBufferAccess} result Result image 703 * @param {tcuRGBA.RGBA} threshold Maximum local difference 704 * @param {tcuImageCompare.CompareLogMode=} logMode Logging mode 705 * @return {boolean} if comparison passes, false otherwise 706 */ 707 tcuImageCompare.bilinearCompare = function(imageSetName, imageSetDesc, reference, result, threshold, logMode) { 708 /** @type {tcuTexture.TextureLevel} */ 709 var errorMask = new tcuTexture.TextureLevel( 710 new tcuTexture.TextureFormat( 711 tcuTexture.ChannelOrder.RGB, 712 tcuTexture.ChannelType.UNORM_INT8), 713 reference.getWidth(), 714 reference.getHeight()); 715 716 /** @type {boolean} */ 717 var isOk = tcuBilinearImageCompare.bilinearCompare( 718 reference, 719 result, 720 tcuTexture.PixelBufferAccess.newFromTextureLevel(errorMask), 721 threshold); 722 723 if (!isOk) { 724 debug('Image comparison failed: threshold = ' + threshold); 725 tcuImageCompare.displayImages(result, reference, errorMask.getAccess()); 726 } 727 728 // /* @type {Array<number>} */ var pixelBias = [0.0, 0.0, 0.0, 0.0]; 729 // /* @type {Array<number>} */ var pixelScale = [1.0, 1.0, 1.0, 1.0]; 730 // if (!isOk || logMode == COMPARE_LOG_EVERYTHING) 731 // { 732 // if (result.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8) && reference.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8)) 733 // computeScaleAndBias(reference, result, pixelScale, pixelBias); 734 // 735 // if (!isOk) 736 // log << TestLog::Message << "Image comparison failed, threshold = " << threshold << TestLog::EndMessage; 737 // 738 // log << TestLog::ImageSet(imageSetName, imageSetDesc) 739 // << TestLog::Image("Result", "Result", result, pixelScale, pixelBias) 740 // << TestLog::Image("Reference", "Reference", reference, pixelScale, pixelBias) 741 // << TestLog::Image("ErrorMask", "Error mask", errorMask) 742 // << TestLog::EndImageSet; 743 // } 744 // else if (logMode == COMPARE_LOG_RESULT) 745 // { 746 // if (result.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8)) 747 // computePixelScaleBias(result, pixelScale, pixelBias); 748 // 749 // log << TestLog::ImageSet(imageSetName, imageSetDesc) 750 // << TestLog::Image("Result", "Result", result, pixelScale, pixelBias) 751 // << TestLog::EndImageSet; 752 // } 753 754 return isOk; 755 }; 756 757 });