diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuImageCompare.js | |
parent | Initial commit. (diff) | |
download | firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuImageCompare.js')
-rw-r--r-- | dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuImageCompare.js | 757 |
1 files changed, 757 insertions, 0 deletions
diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuImageCompare.js b/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuImageCompare.js new file mode 100644 index 0000000000..3a8138ef23 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuImageCompare.js @@ -0,0 +1,757 @@ +/*------------------------------------------------------------------------- + * 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<number>, bias: Array<number>}} + */ +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<number>} threshold Maximum allowed difference + * @param {tcuImageCompare.CompareLogMode=} logMode + * @param {Array< Array<number> >} 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<number>} threshold Maximum allowed difference + * @param {Array<number>} 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<number>} */ var pixelBias = [0.0, 0.0, 0.0, 0.0]; + /** @type {Array<number>} */ 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<number>} 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<number>} */ 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<number>} */ var refPix = reference.getPixel(x, y, z); // getPixel returns a Vec4 pixel color + + /** @type {Array<number>} */ 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<number>} */ 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<number>} 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<number>} */ 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<number>} */ 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<number>} threshold Maximum allowed difference + * @param {tcuImageCompare.CompareLogMode=} logMode + * @param {Array< Array<number> >} 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<number>} threshold + * @param {Array<number>} 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<number>} */ var refPix = reference.getPixelInt(x, y, z); + /** @type {Array<number>} */ var cmpPix = result.getPixelInt(x, y, z); + + // Exact match + /** @type {Array<number>} */ 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<number>} */ 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<number>} */ 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<number>} */ var pixelBias = [0.0, 0.0, 0.0, 0.0]; + /** @type {Array<number>} */ 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<number>} */ var pixelBias = [0.0, 0.0, 0.0, 0.0]; + // /* @type {Array<number>} */ 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; +}; + +}); |