/*------------------------------------------------------------------------- * drawElements Quality Program OpenGL ES Utilities * ------------------------------------------------ * * Copyright 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ 'use strict'; goog.provide('framework.common.tcuImageCompare'); goog.require('framework.common.tcuBilinearImageCompare'); goog.require('framework.common.tcuFloat'); goog.require('framework.common.tcuFuzzyImageCompare'); goog.require('framework.common.tcuLogImage'); goog.require('framework.common.tcuRGBA'); goog.require('framework.common.tcuSurface'); goog.require('framework.common.tcuTexture'); goog.require('framework.common.tcuTextureUtil'); goog.require('framework.delibs.debase.deMath'); goog.scope(function() { var tcuImageCompare = framework.common.tcuImageCompare; var tcuSurface = framework.common.tcuSurface; var deMath = framework.delibs.debase.deMath; var tcuTexture = framework.common.tcuTexture; var tcuTextureUtil = framework.common.tcuTextureUtil; var tcuFloat = framework.common.tcuFloat; var tcuFuzzyImageCompare = framework.common.tcuFuzzyImageCompare; var tcuBilinearImageCompare = framework.common.tcuBilinearImageCompare; var tcuRGBA = framework.common.tcuRGBA; var tcuLogImage = framework.common.tcuLogImage; /** * @enum */ tcuImageCompare.CompareLogMode = { EVERYTHING: 0, RESULT: 1, ON_ERROR: 2 }; /** * @param {framework.common.tcuTexture.ConstPixelBufferAccess} result * @param {framework.common.tcuTexture.ConstPixelBufferAccess} reference * @param {framework.common.tcuTexture.ConstPixelBufferAccess=} diff */ tcuImageCompare.displayImages = function(result, reference, diff) { var limits = tcuImageCompare.computeScaleAndBias(reference, result); tcuLogImage.logImage('Result', '', result, limits.scale, limits.bias); tcuLogImage.logImage('Reference', '', reference, limits.scale, limits.bias); if (diff) tcuLogImage.logImage('Error', 'error mask', diff); }; /** * @param {tcuTexture.ConstPixelBufferAccess} reference * @param {tcuTexture.ConstPixelBufferAccess} result * @return {{scale: Array, bias: Array}} */ tcuImageCompare.computeScaleAndBias = function(reference, result) { var minVal = []; var maxVal = []; var scale = []; var bias = []; var eps = 0.0001; var referenceRange = tcuTextureUtil.estimatePixelValueRange(reference); var resultRange = tcuTextureUtil.estimatePixelValueRange(result); minVal[0] = Math.min(referenceRange[0][0], resultRange[0][0]); minVal[1] = Math.min(referenceRange[0][1], resultRange[0][1]); minVal[2] = Math.min(referenceRange[0][2], resultRange[0][2]); minVal[3] = Math.min(referenceRange[0][3], resultRange[0][3]); maxVal[0] = Math.max(referenceRange[1][0], resultRange[1][0]); maxVal[1] = Math.max(referenceRange[1][1], resultRange[1][1]); maxVal[2] = Math.max(referenceRange[1][2], resultRange[1][2]); maxVal[3] = Math.max(referenceRange[1][3], resultRange[1][3]); for (var c = 0; c < 4; c++) { if (maxVal[c] - minVal[c] < eps) { scale[c] = (maxVal[c] < eps) ? 1 : (1 / maxVal[c]); bias[c] = (c == 3) ? (1 - maxVal[c] * scale[c]) : (0 - minVal[c] * scale[c]); } else { scale[c] = 1 / (maxVal[c] - minVal[c]); bias[c] = 0 - minVal[c] * scale[c]; } } return { scale: scale, bias: bias }; }; /** * \brief Per-pixel threshold-based comparison * * This compare computes per-pixel differences between result and reference * image. Comparison fails if any pixels exceed the given threshold value. * * This comparison can be used for integer- and fixed-point texture formats. * Difference is computed in integer space. * * On failure error image is generated that shows where the failing pixels * are. * * @param {string} imageSetName Name for image set when logging results * @param {string} imageSetDesc Description for image set * @param {tcuTexture.ConstPixelBufferAccess} reference Reference image * @param {tcuTexture.ConstPixelBufferAccess} result Result image * @param {Array} threshold Maximum allowed difference * @param {tcuImageCompare.CompareLogMode=} logMode * @param {Array< Array >} skipPixels pixels that are skipped comparison * @return {boolean} true if comparison passes, false otherwise */ tcuImageCompare.intThresholdCompare = function(imageSetName, imageSetDesc, reference, result, threshold, logMode, skipPixels) { var width = reference.getWidth(); var height = reference.getHeight(); var depth = reference.getDepth(); var errorMask = new tcuSurface.Surface(width, height); var maxDiff = [0, 0, 0, 0]; // var pixelBias = [0, 0, 0, 0]; // Vec4 // TODO: check, only used in computeScaleAndBias, which is not included // var pixelScale = [1, 1, 1, 1]; // Vec4 // TODO: check, only used in computeScaleAndBias assertMsgOptions(result.getWidth() == width && result.getHeight() == height && result.getDepth() == depth, 'Reference and result images have different dimensions', false, true); for (var z = 0; z < depth; z++) { for (var y = 0; y < height; y++) { for (var x = 0; x < width; x++) { if (skipPixels && skipPixels.length > 0) { var skip = false; for (var ii = 0; ii < skipPixels.length; ++ii) { var refZ = (skipPixels[ii].length > 2 ? skipPixels[ii][2] : 0); if (x == skipPixels[ii][0] && y == skipPixels[ii][1] && z == refZ) { skip = true; break; } } if (skip) continue; } var refPix = reference.getPixelInt(x, y, z); var cmpPix = result.getPixelInt(x, y, z); var diff = deMath.absDiff(refPix, cmpPix); var isOk = deMath.boolAll(deMath.lessThanEqual(diff, threshold)); maxDiff = deMath.max(maxDiff, diff); var color = [0, 255, 0, 255]; if (!isOk) color = [255, 0, 0, 255]; errorMask.setPixel(x, y, color); } } } var compareOk = deMath.boolAll(deMath.lessThanEqual(maxDiff, threshold)); if (!compareOk) { debug('Image comparison failed: max difference = ' + maxDiff + ', threshold = ' + threshold); tcuImageCompare.displayImages(result, reference, errorMask.getAccess()); } return compareOk; }; /** * \brief Per-pixel threshold-based deviation-ignoring comparison * * This compare computes per-pixel differences between result and reference * image. Pixel fails the test if there is no pixel matching the given * threshold value in the search volume. Comparison fails if the number of * failing pixels exceeds the given limit. * * If the search volume contains out-of-bounds pixels, comparison can be set * to either ignore these pixels in search or to accept any pixel that has * out-of-bounds pixels in its search volume. * * This comparison can be used for integer- and fixed-point texture formats. * Difference is computed in integer space. * * On failure error image is generated that shows where the failing pixels * are. * * @param {string} imageSetName Name for image set when logging results * @param {string} imageSetDesc Description for image set * @param {tcuTexture.ConstPixelBufferAccess} reference Reference image * @param {tcuTexture.ConstPixelBufferAccess} result Result image * @param {Array} threshold Maximum allowed difference * @param {Array} maxPositionDeviation Maximum allowed distance in the search volume. * @param {boolean} acceptOutOfBoundsAsAnyValue Accept any pixel in the boundary region * @param {number} maxAllowedFailingPixels Maximum number of failing pixels * @return {boolean} true if comparison passes, false otherwise */ tcuImageCompare.intThresholdPositionDeviationErrorThresholdCompare = function( imageSetName, imageSetDesc, reference, result, threshold, maxPositionDeviation, acceptOutOfBoundsAsAnyValue, maxAllowedFailingPixels) { /** @type {number} */ var width = reference.getWidth(); /** @type {number} */ var height = reference.getHeight(); /** @type {number} */ var depth = reference.getDepth(); /** @type {tcuSurface.Surface} */ var errorMask = new tcuSurface.Surface(width, height); /** @type {number} */ var numFailingPixels = tcuImageCompare.findNumPositionDeviationFailingPixels(errorMask.getAccess(), reference, result, threshold, maxPositionDeviation, acceptOutOfBoundsAsAnyValue); var compareOk = numFailingPixels <= maxAllowedFailingPixels; /** @type {Array} */ var pixelBias = [0.0, 0.0, 0.0, 0.0]; /** @type {Array} */ var pixelScale = [1.0, 1.0, 1.0, 1.0]; if (!compareOk) { debug('Position deviation error threshold image comparison failed: failed pixels = ' + numFailingPixels + ', threshold = ' + threshold); tcuImageCompare.displayImages(result, reference, errorMask.getAccess()); } else tcuLogImage.logImage('Result', '', result); /*if (!compareOk) { // All formats except normalized unsigned fixed point ones need remapping in order to fit into unorm channels in logged images. if (tcuTexture.getTextureChannelClass(reference.getFormat().type) != tcuTexture.TextureChannelClass.UNSIGNED_FIXED_POINT || tcuTexture.getTextureChannelClass(result.getFormat().type) != tcuTexture.TextureChannelClass.UNSIGNED_FIXED_POINT) { computeScaleAndBias(reference, result, pixelScale, pixelBias); log << TestLog::Message << "Result and reference images are normalized with formula p * " << pixelScale << " + " << pixelBias << TestLog::EndMessage; } if (!compareOk) log << TestLog::Message << "Image comparison failed:\n" << "\tallowed position deviation = " << maxPositionDeviation << "\n" << "\tcolor threshold = " << threshold << TestLog::EndMessage; log << TestLog::Message << "Number of failing pixels = " << numFailingPixels << ", max allowed = " << maxAllowedFailingPixels << TestLog::EndMessage; log << TestLog::ImageSet(imageSetName, imageSetDesc) << TestLog::Image("Result", "Result", result, pixelScale, pixelBias) << TestLog::Image("Reference", "Reference", reference, pixelScale, pixelBias) << TestLog::Image("ErrorMask", "Error mask", errorMask) << TestLog::EndImageSet; } else if (logMode == COMPARE_LOG_RESULT) { if (result.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8)) computePixelScaleBias(result, pixelScale, pixelBias); log << TestLog::ImageSet(imageSetName, imageSetDesc) << TestLog::Image("Result", "Result", result, pixelScale, pixelBias) << TestLog::EndImageSet; }*/ return compareOk; }; /** * tcuImageCompare.floatUlpThresholdCompare * @param {string} imageSetName * @param {string} imageSetDesc * @param {tcuTexture.ConstPixelBufferAccess} reference * @param {tcuTexture.ConstPixelBufferAccess} result * @param {Array} threshold - previously used as an Uint32Array * @return {boolean} */ tcuImageCompare.floatUlpThresholdCompare = function(imageSetName, imageSetDesc, reference, result, threshold) { /** @type {number} */ var width = reference.getWidth(); /** @type {number} */ var height = reference.getHeight(); /** @type {number} */ var depth = reference.getDepth(); /** @type {tcuSurface.Surface} */ var errorMask = new tcuSurface.Surface(width, height); /** @type {Array} */ var maxDiff = [0, 0, 0, 0]; // UVec4 // var pixelBias = [0, 0, 0, 0]; // Vec4 // var pixelScale = [1, 1, 1, 1]; // Vec4 assertMsgOptions(result.getWidth() == width && result.getHeight() == height && result.getDepth() == depth, 'Reference and result images have different dimensions', false, true); for (var z = 0; z < depth; z++) { for (var y = 0; y < height; y++) { for (var x = 0; x < width; x++) { /** @type {ArrayBuffer} */ var arrayBufferRef = new ArrayBuffer(4 * 4); /** @type {ArrayBuffer} */ var arrayBufferCmp = new ArrayBuffer(4 * 4); /** @type {Array} */ var refPix = reference.getPixel(x, y, z); // getPixel returns a Vec4 pixel color /** @type {Array} */ var cmpPix = result.getPixel(x, y, z); // getPixel returns a Vec4 pixel color /** @type {Uint32Array} */ var refBits = new Uint32Array(arrayBufferRef); // UVec4 /** @type {Uint32Array} */ var cmpBits = new Uint32Array(arrayBufferCmp); // UVec4 // Instead of memcpy(), which is the way to do float->uint32 reinterpretation in C++ for (var i = 0; i < refPix.length; i++) { refBits[i] = tcuFloat.convertFloat32Inline(refPix[i], tcuFloat.description32); cmpBits[i] = tcuFloat.convertFloat32Inline(cmpPix[i], tcuFloat.description32); } /** @type {Array} */ var diff = deMath.absDiff(refBits, cmpBits); // UVec4 /** @type {boolean} */ var isOk = deMath.boolAll(deMath.lessThanEqual(diff, threshold)); maxDiff = deMath.max(maxDiff, diff); errorMask.setPixel(x, y, isOk ? [0, 255, 0, 255] : [255, 0, 0, 255]); } } } /** @type {boolean} */ var compareOk = deMath.boolAll(deMath.lessThanEqual(maxDiff, threshold)); if (!compareOk) { debug('Image comparison failed: max difference = ' + maxDiff + ', threshold = ' + threshold); tcuImageCompare.displayImages(result, reference, errorMask.getAccess()); } /*if (!compareOk || logMode == COMPARE_LOG_EVERYTHING) { // All formats except normalized unsigned fixed point ones need remapping in order to fit into unorm channels in logged images. if (tcu::getTextureChannelClass(reference.getFormat().type) != tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT || tcu::getTextureChannelClass(result.getFormat().type) != tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT) { computeScaleAndBias(reference, result, pixelScale, pixelBias); log << TestLog::Message << "Result and reference images are normalized with formula p * " << pixelScale << " + " << pixelBias << TestLog::EndMessage; } if (!compareOk) log << TestLog::Message << "Image comparison failed: max difference = " << maxDiff << ", threshold = " << threshold << TestLog::EndMessage; log << TestLog::ImageSet(imageSetName, imageSetDesc) << TestLog::Image("Result", "Result", result, pixelScale, pixelBias) << TestLog::Image("Reference", "Reference", reference, pixelScale, pixelBias) << TestLog::Image("ErrorMask", "Error mask", errorMask) << TestLog::EndImageSet; } else if (logMode == COMPARE_LOG_RESULT) { if (result.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8)) computePixelScaleBias(result, pixelScale, pixelBias); log << TestLog::ImageSet(imageSetName, imageSetDesc) << TestLog::Image("Result", "Result", result, pixelScale, pixelBias) << TestLog::EndImageSet; }*/ return compareOk; }; /** * tcuImageCompare.floatThresholdCompare * @param {string} imageSetName * @param {string} imageSetDesc * @param {tcuTexture.ConstPixelBufferAccess} reference * @param {tcuTexture.ConstPixelBufferAccess} result * @param {Array} threshold * @return {boolean} */ tcuImageCompare.floatThresholdCompare = function(imageSetName, imageSetDesc, reference, result, threshold) { /** @type {number} */ var width = reference.getWidth(); /** @type {number} */ var height = reference.getHeight(); /** @type {number} */ var depth = reference.getDepth(); /** @type {tcuSurface.Surface} */ var errorMask = new tcuSurface.Surface(width, height); /** @type {Array} */ var maxDiff = [0, 0, 0, 0]; // Vec4 // var pixelBias = [0, 0, 0, 0]; // Vec4 // var pixelScale = [1, 1, 1, 1]; // Vec4 assertMsgOptions(result.getWidth() == width && result.getHeight() == height && result.getDepth() == depth, 'Reference and result images have different dimensions', false, true); for (var z = 0; z < depth; z++) { for (var y = 0; y < height; y++) { for (var x = 0; x < width; x++) { var refPix = reference.getPixel(x, y, z); // Vec4 var cmpPix = result.getPixel(x, y, z); // Vec4 /** @type {Array} */ var diff = deMath.absDiff(refPix, cmpPix); // Vec4 /** @type {boolean} */ var isOk = deMath.boolAll(deMath.lessThanEqual(diff, threshold)); maxDiff = deMath.max(maxDiff, diff); errorMask.setPixel(x, y, isOk ? [0, 255, 0, 255] : [255, 0, 0, 255]); } } } /** @type {boolean} */ var compareOk = deMath.boolAll(deMath.lessThanEqual(maxDiff, threshold)); if (!compareOk) { debug('Image comparison failed: max difference = ' + maxDiff + ', threshold = ' + threshold); tcuImageCompare.displayImages(result, reference, errorMask.getAccess()); } /*if (!compareOk || logMode == COMPARE_LOG_EVERYTHING) { // All formats except normalized unsigned fixed point ones need remapping in order to fit into unorm channels in logged images. if (tcu::getTextureChannelClass(reference.getFormat().type) != tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT || tcu::getTextureChannelClass(result.getFormat().type) != tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT) { computeScaleAndBias(reference, result, pixelScale, pixelBias); log << TestLog::Message << "Result and reference images are normalized with formula p * " << pixelScale << " + " << pixelBias << TestLog::EndMessage; } if (!compareOk) log << TestLog::Message << "Image comparison failed: max difference = " << maxDiff << ", threshold = " << threshold << TestLog::EndMessage; log << TestLog::ImageSet(imageSetName, imageSetDesc) << TestLog::Image("Result", "Result", result, pixelScale, pixelBias) << TestLog::Image("Reference", "Reference", reference, pixelScale, pixelBias) << TestLog::Image("ErrorMask", "Error mask", errorMask) << TestLog::EndImageSet; } else if (logMode == COMPARE_LOG_RESULT) { if (result.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8)) computePixelScaleBias(result, pixelScale, pixelBias); log << TestLog::ImageSet(imageSetName, imageSetDesc) << TestLog::Image("Result", "Result", result, pixelScale, pixelBias) << TestLog::EndImageSet; }*/ return compareOk; }; /** * \brief Per-pixel threshold-based comparison * * This compare computes per-pixel differences between result and reference * image. Comparison fails if any pixels exceed the given threshold value. * * On failure error image is generated that shows where the failing pixels * are. * * @param {string} imageSetName Name for image set when logging results * @param {string} imageSetDesc Description for image set * @param {tcuSurface.Surface} reference Reference image * @param {tcuSurface.Surface} result Result image * @param {Array} threshold Maximum allowed difference * @param {tcuImageCompare.CompareLogMode=} logMode * @param {Array< Array >} skipPixels pixels that are skipped comparison * @return {boolean} true if comparison passes, false otherwise */ tcuImageCompare.pixelThresholdCompare = function(imageSetName, imageSetDesc, reference, result, threshold, logMode, skipPixels) { return tcuImageCompare.intThresholdCompare(imageSetName, imageSetDesc, reference.getAccess(), result.getAccess(), threshold, logMode, skipPixels); }; /** * @param {tcuTexture.PixelBufferAccess} errorMask * @param {tcuTexture.ConstPixelBufferAccess} reference * @param {tcuTexture.ConstPixelBufferAccess} result * @param {Array} threshold * @param {Array} maxPositionDeviation * @param {boolean} acceptOutOfBoundsAsAnyValue * @return {number} */ tcuImageCompare.findNumPositionDeviationFailingPixels = function(errorMask, reference, result, threshold, maxPositionDeviation, acceptOutOfBoundsAsAnyValue) { /** @type {number} */ var width = reference.getWidth(); /** @type {number} */ var height = reference.getHeight(); /** @type {number} */ var depth = reference.getDepth(); /** @type {number} */ var numFailingPixels = 0; checkMessage(result.getWidth() == width && result.getHeight() == height && result.getDepth() == depth, 'Surfaces have different dimensions'); for (var z = 0; z < depth; z++) { for (var y = 0; y < height; y++) { for (var x = 0; x < width; x++) { /** @type {Array} */ var refPix = reference.getPixelInt(x, y, z); /** @type {Array} */ var cmpPix = result.getPixelInt(x, y, z); // Exact match /** @type {Array} */ var diff = deMath.absDiff(refPix, cmpPix); /** @type {boolean} */ var isOk = deMath.boolAll(deMath.lessThanEqual(diff, threshold)); if (isOk) { errorMask.setPixel([0, 0xff, 0, 0xff], x, y, z); continue; } // Accept over the image bounds pixels since they could be anything if (acceptOutOfBoundsAsAnyValue && (x < maxPositionDeviation[0] || x + maxPositionDeviation[0] >= width || y < maxPositionDeviation[1] || y + maxPositionDeviation[1] >= height || z < maxPositionDeviation[2] || z + maxPositionDeviation[2] >= depth)) { errorMask.setPixel([0, 0xff, 0, 0xff], x, y, z); continue; } // Find matching pixels for both result and reference pixel var pixelFoundForReference = false; var pixelFoundForResult = false; // Find deviated result pixel for reference for (var sz = Math.max(0, z - maxPositionDeviation[2]); sz <= Math.min(depth - 1, z + maxPositionDeviation[2]) && !pixelFoundForReference; ++sz) for (var sy = Math.max(0, y - maxPositionDeviation[1]); sy <= Math.min(height - 1, y + maxPositionDeviation[1]) && !pixelFoundForReference; ++sy) for (var sx = Math.max(0, x - maxPositionDeviation[0]); sx <= Math.min(width - 1, x + maxPositionDeviation[0]) && !pixelFoundForReference; ++sx) { /** @type {Array} */ var deviatedCmpPix = result.getPixelInt(sx, sy, sz); diff = deMath.absDiff(refPix, deviatedCmpPix); isOk = deMath.boolAll(deMath.lessThanEqual(diff, threshold)); pixelFoundForReference |= isOk; } // Find deviated reference pixel for result for (var sz = Math.max(0, z - maxPositionDeviation[2]); sz <= Math.min(depth - 1, z + maxPositionDeviation[2]) && !pixelFoundForResult; ++sz) for (var sy = Math.max(0, y - maxPositionDeviation[1]); sy <= Math.min(height - 1, y + maxPositionDeviation[1]) && !pixelFoundForResult; ++sy) for (var sx = Math.max(0, x - maxPositionDeviation[0]); sx <= Math.min(width - 1, x + maxPositionDeviation[0]) && !pixelFoundForResult; ++sx) { /** @type {Array} */ var deviatedRefPix = reference.getPixelInt(sx, sy, sz); diff = deMath.absDiff(cmpPix, deviatedRefPix); isOk = deMath.boolAll(deMath.lessThanEqual(diff, threshold)); pixelFoundForResult |= isOk; } if (pixelFoundForReference && pixelFoundForResult) errorMask.setPixel([0, 0xff, 0, 0xff], x, y, z); else { errorMask.setPixel([0xff, 0, 0, 0xff], x, y, z); ++numFailingPixels; } } } } return numFailingPixels; }; /** * tcuImageCompare.fuzzyCompare * @param {string} imageSetName * @param {string} imageSetDesc * @param {tcuTexture.ConstPixelBufferAccess} reference * @param {tcuTexture.ConstPixelBufferAccess} result * @param {number} threshold * @param {tcuImageCompare.CompareLogMode=} logMode * @return {boolean} */ tcuImageCompare.fuzzyCompare = function(imageSetName, imageSetDesc, reference, result, threshold, logMode) { /** @type {tcuFuzzyImageCompare.FuzzyCompareParams} */ var params = new tcuFuzzyImageCompare.FuzzyCompareParams(); // Use defaults. /** @type {tcuTexture.TextureLevel} */ var errorMask = new tcuTexture.TextureLevel( new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.UNORM_INT8), reference.getWidth(), reference.getHeight() ); /** @type {number} */ var difference = tcuFuzzyImageCompare.fuzzyCompare( params, reference, result, tcuTexture.PixelBufferAccess.newFromTextureLevel(errorMask) ); /** @type {boolean} */ var isOk = difference <= threshold; /** @type {Array} */ var pixelBias = [0.0, 0.0, 0.0, 0.0]; /** @type {Array} */ var pixelScale = [1.0, 1.0, 1.0, 1.0]; if (!isOk) { debug('Fuzzy image comparison failed: difference = ' + difference + ', threshold = ' + threshold); tcuImageCompare.displayImages(result, reference, errorMask.getAccess()); } /* if (!isOk || logMode == COMPARE_LOG_EVERYTHING) { // Generate more accurate error mask. params.maxSampleSkip = 0; tcuImageCompare.fuzzyCompare(params, reference, result, errorMask.getAccess()); if (result.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8) && reference.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8)) computeScaleAndBias(reference, result, pixelScale, pixelBias); if (!isOk) log << TestLog::Message << "Image comparison failed: difference = " << difference << ", threshold = " << threshold << TestLog::EndMessage; log << TestLog::ImageSet(imageSetName, imageSetDesc) << TestLog::Image("Result", "Result", result, pixelScale, pixelBias) << TestLog::Image("Reference", "Reference", reference, pixelScale, pixelBias) << TestLog::Image("ErrorMask", "Error mask", errorMask) << TestLog::EndImageSet; } else if (logMode == COMPARE_LOG_RESULT) { if (result.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8)) computePixelScaleBias(result, pixelScale, pixelBias); log << TestLog::ImageSet(imageSetName, imageSetDesc) << TestLog::Image("Result", "Result", result, pixelScale, pixelBias) << TestLog::EndImageSet; } */ return isOk; }; tcuImageCompare.unitTest = function() { var width = 128; var height = 128; var weirdLevel = new tcuTexture.TextureLevel(new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RG, tcuTexture.ChannelType.SNORM_INT32), width, height); var access = weirdLevel.getAccess(); access.clear([0.1, 0.5, 0, 0]); access.clear([0.11, 0.52, 0, 0], [0, width], [0, height / 2]); access.clear([0.12, 0.52, 0, 0], [0, width], [height / 2, height / 2 + height / 8]); var limits = tcuTextureUtil.computePixelScaleBias(access); debug('Scale: ' + limits.scale); debug('Bias: ' + limits.bias); tcuLogImage.logImage('Weird', 'weird format without scaling', access); tcuLogImage.logImage('Weird', 'weird format', access, limits.scale, limits.bias); var srcLevel = new tcuTexture.TextureLevel(new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNORM_INT8), width, height); var dstLevel = new tcuTexture.TextureLevel(new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNORM_INT8), width, height); var src = srcLevel.getAccess(); var dst = dstLevel.getAccess(); src.clear(); dst.clear(); for (var i = 0; i < width - 1; i++) { for (var j = 0; j < height - 1; j++) { src.setPixelInt([i, j, 90, 255], i, j); dst.setPixelInt([i, j, 90, 255], i + 1, j + 1); } } debug('Src format: ' + src.getFormat()); debug('Destination: ' + dst); debug(src); tcuLogImage.logImage('Source', 'Source image', src); if (!tcuImageCompare.fuzzyCompare('compare', 'compare similar images', src, dst, 0.05)) throw new Error('Compare should return true'); src.clear(); dst.clear(); for (var i = 0; i < width - 2; i++) { for (var j = 0; j < height - 2; j++) { src.setPixelInt([i, j, 90, 255], i, j); dst.setPixelInt([i, j, 90, 255], i + 2, j + 2); } } if (tcuImageCompare.fuzzyCompare('compare', 'compare different images', src, dst, 0.05)) throw new Error('Compare should return false'); debug('Passed'); }; tcuImageCompare.unitTest2 = function() { var width = 128; var height = 128; var srcLevel = new tcuTexture.TextureLevel(new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNORM_INT8), width, height); var dstLevel = new tcuTexture.TextureLevel(new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNORM_INT8), width, height); var src = srcLevel.getAccess(); var dst = dstLevel.getAccess(); var threshold = tcuRGBA.newRGBAComponents(1, 1, 1, 1); debug('Threshold: ' + threshold); src.clear(); dst.clear(); for (var i = 0; i < width - 1; i++) { for (var j = 0; j < height - 1; j++) { src.setPixelInt([i, j, 90, 255], i, j); dst.setPixelInt([i, j, 90, 255], i, j); } } if (!tcuImageCompare.bilinearCompare('compare', 'compare similar images', src, dst, threshold)) throw new Error('Compare should return true'); debug('bilinear compare the same images passed'); src.clear(); dst.clear(); for (var i = 0; i < width - 1; i++) { for (var j = 0; j < height - 1; j++) { src.setPixelInt([i, j, 90, 255], i, j); dst.setPixelInt([i, j + 1, 90, 255], i, j + 1); } } if (!tcuImageCompare.bilinearCompare('compare', 'compare similar images', src, dst, threshold)) throw new Error('Compare should return true'); debug('bilinear compare very similar images passed'); src.clear(); dst.clear(); for (var i = 0; i < width - 2; i++) { for (var j = 0; j < height - 2; j++) { src.setPixelInt([i, j, 90, 255], i, j); // dst.setPixelInt([i, j, 90, 255], i + 2, j + 2); } } if (tcuImageCompare.bilinearCompare('compare', 'compare different images', src, dst, threshold)) throw new Error('Compare should return false'); debug('bilinear compare very different images passed'); }; /** * Bilinear image comparison * On failure error image is generated that shows where the failing pixels * are. * Currently supports only RGBA, UNORM_INT8 formats * * @param {string} imageSetName Name for image set when logging results * @param {string} imageSetDesc Description for image set * @param {tcuTexture.ConstPixelBufferAccess} reference Reference image * @param {tcuTexture.ConstPixelBufferAccess} result Result image * @param {tcuRGBA.RGBA} threshold Maximum local difference * @param {tcuImageCompare.CompareLogMode=} logMode Logging mode * @return {boolean} if comparison passes, false otherwise */ tcuImageCompare.bilinearCompare = function(imageSetName, imageSetDesc, reference, result, threshold, logMode) { /** @type {tcuTexture.TextureLevel} */ var errorMask = new tcuTexture.TextureLevel( new tcuTexture.TextureFormat( tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.UNORM_INT8), reference.getWidth(), reference.getHeight()); /** @type {boolean} */ var isOk = tcuBilinearImageCompare.bilinearCompare( reference, result, tcuTexture.PixelBufferAccess.newFromTextureLevel(errorMask), threshold); if (!isOk) { debug('Image comparison failed: threshold = ' + threshold); tcuImageCompare.displayImages(result, reference, errorMask.getAccess()); } // /* @type {Array} */ var pixelBias = [0.0, 0.0, 0.0, 0.0]; // /* @type {Array} */ var pixelScale = [1.0, 1.0, 1.0, 1.0]; // if (!isOk || logMode == COMPARE_LOG_EVERYTHING) // { // if (result.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8) && reference.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8)) // computeScaleAndBias(reference, result, pixelScale, pixelBias); // // if (!isOk) // log << TestLog::Message << "Image comparison failed, threshold = " << threshold << TestLog::EndMessage; // // log << TestLog::ImageSet(imageSetName, imageSetDesc) // << TestLog::Image("Result", "Result", result, pixelScale, pixelBias) // << TestLog::Image("Reference", "Reference", reference, pixelScale, pixelBias) // << TestLog::Image("ErrorMask", "Error mask", errorMask) // << TestLog::EndImageSet; // } // else if (logMode == COMPARE_LOG_RESULT) // { // if (result.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8)) // computePixelScaleBias(result, pixelScale, pixelBias); // // log << TestLog::ImageSet(imageSetName, imageSetDesc) // << TestLog::Image("Result", "Result", result, pixelScale, pixelBias) // << TestLog::EndImageSet; // } return isOk; }; });