tcuBilinearImageCompare.js (11774B)
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.tcuBilinearImageCompare'); 23 goog.require('framework.common.tcuRGBA'); 24 goog.require('framework.common.tcuTexture'); 25 goog.require('framework.delibs.debase.deMath'); 26 27 goog.scope(function() { 28 29 var tcuBilinearImageCompare = framework.common.tcuBilinearImageCompare; 30 var deMath = framework.delibs.debase.deMath; 31 var tcuTexture = framework.common.tcuTexture; 32 var tcuRGBA = framework.common.tcuRGBA; 33 34 var DE_ASSERT = function(x) { 35 if (!x) 36 throw new Error('Assert failed'); 37 }; 38 39 // for bilinear interpolation 40 /** @const {number} */ tcuBilinearImageCompare.NUM_SUBPIXEL_BITS = 8; 41 42 // Algorithm assumes that colors are packed to 32-bit values as dictated by 43 // tcu::RGBA::*_SHIFT values. 44 45 function UintRGBA8_R(color) { 46 return (color >> 24) & 0xff; 47 } 48 function UintRGBA8_G(color) { 49 return (color >> 16) & 0xff; 50 } 51 function UintRGBA8_B(color) { 52 return (color >> 8) & 0xff; 53 } 54 function UintRGBA8_A(color) { 55 return color & 0xff; 56 } 57 58 /** 59 * @param {number} fx1 deUint32 60 * @param {number} fy1 deUint32 61 * @param {number} p00 deUint8 62 * @param {number} p01 deUint8 63 * @param {number} p10 deUint8 64 * @param {number} p11 deUint8 65 * @return {number} deUint8 66 */ 67 tcuBilinearImageCompare.interpolateChannel = function(fx1, fy1, p00, p01, p10, p11) { 68 /** @const {number} */ var fx0 = (1 << tcuBilinearImageCompare.NUM_SUBPIXEL_BITS) - fx1; 69 /** @const {number} */ var fy0 = (1 << tcuBilinearImageCompare.NUM_SUBPIXEL_BITS) - fy1; 70 /** @const {number} */ 71 var half = 1 << (tcuBilinearImageCompare.NUM_SUBPIXEL_BITS * 2 - 1); 72 /** @const {number} */ var sum = 73 (fx0 * fy0 * p00) + 74 (fx1 * fy0 * p10) + 75 (fx0 * fy1 * p01) + 76 (fx1 * fy1 * p11); 77 /** @const {number} */ 78 var rounded = (sum + half) >> (tcuBilinearImageCompare.NUM_SUBPIXEL_BITS * 2); 79 80 DE_ASSERT(deMath.deInRange32(rounded, 0, 0xff)); 81 return rounded; 82 }; 83 84 tcuBilinearImageCompare.compareUintRGBA8Threshold = function(a, b, thr) { 85 if (a == b) 86 return true; 87 88 return (Math.abs(UintRGBA8_R(a) - UintRGBA8_R(b)) <= thr.getRed() && 89 Math.abs(UintRGBA8_G(a) - UintRGBA8_G(b)) <= thr.getGreen() && 90 Math.abs(UintRGBA8_B(a) - UintRGBA8_B(b)) <= thr.getBlue() && 91 Math.abs(UintRGBA8_A(a) - UintRGBA8_A(b)) <= thr.getAlpha()); 92 }; 93 94 /** 95 * @param {tcuTexture.RGBA8View} view 96 * @param {number} u 97 * @param {number} v 98 * @return {number} 99 */ 100 tcuBilinearImageCompare.bilinearSampleUintRGBA8 = function(view, u, v) { 101 /** @type {number} */ var x0 = u >> tcuBilinearImageCompare.NUM_SUBPIXEL_BITS; 102 /** @type {number} */ var y0 = v >> tcuBilinearImageCompare.NUM_SUBPIXEL_BITS; 103 /** @type {number} */ var x1 = x0 + 1; 104 /** @type {number} */ var y1 = y0 + 1; 105 106 DE_ASSERT(x1 < view.getWidth()); 107 DE_ASSERT(y1 < view.getHeight()); 108 109 /** @type {number} */ var fx1 = u - (x0 << tcuBilinearImageCompare.NUM_SUBPIXEL_BITS); 110 /** @type {number} */ var fy1 = v - (y0 << tcuBilinearImageCompare.NUM_SUBPIXEL_BITS); 111 112 /** @type {Array<number>} */ var channelsP00 = view.readUintRGBA8(x0, y0); 113 /** @type {Array<number>} */ var channelsP10 = view.readUintRGBA8(x1, y0); 114 /** @type {Array<number>} */ var channelsP01 = view.readUintRGBA8(x0, y1); 115 /** @type {Array<number>} */ var channelsP11 = view.readUintRGBA8(x1, y1); 116 117 /** @type {number} */ var res = 0; 118 119 res = (tcuBilinearImageCompare.interpolateChannel(fx1, fy1, UintRGBA8_R(channelsP00), 120 UintRGBA8_R(channelsP01), UintRGBA8_R(channelsP10), UintRGBA8_R(channelsP11)) & 0xff) << 24; 121 res += (tcuBilinearImageCompare.interpolateChannel(fx1, fy1, UintRGBA8_G(channelsP00), 122 UintRGBA8_G(channelsP01), UintRGBA8_G(channelsP10), UintRGBA8_G(channelsP11)) & 0xff) << 16; 123 res += (tcuBilinearImageCompare.interpolateChannel(fx1, fy1, UintRGBA8_B(channelsP00), 124 UintRGBA8_B(channelsP01), UintRGBA8_B(channelsP10), UintRGBA8_B(channelsP11)) & 0xff) << 8; 125 res += tcuBilinearImageCompare.interpolateChannel(fx1, fy1, UintRGBA8_A(channelsP00), 126 UintRGBA8_A(channelsP01), UintRGBA8_A(channelsP10), UintRGBA8_A(channelsP11)) & 0xff; 127 128 return res; 129 }; 130 131 /** 132 * @param {tcuTexture.RGBA8View} reference 133 * @param {tcuTexture.RGBA8View} result 134 * @param {tcuRGBA.RGBA} threshold 135 * @param {number} x 136 * @param {number} y 137 * @return {boolean} 138 */ 139 tcuBilinearImageCompare.comparePixelRGBA8 = function(reference, result, threshold, x, y) { 140 /** @const {tcuRGBA.RGBA} */ var resPix = result.readUintRGBA8(x, y); 141 142 // Step 1: Compare result pixel to 3x3 neighborhood pixels in reference. 143 /** @const {number} */ var x0 = Math.max(x - 1, 0); 144 /** @const {number} */ var x1 = x; 145 /** @const {number} */ 146 var x2 = Math.min(x + 1, reference.getWidth() - 1); 147 /** @const {number} */ var y0 = Math.max(y - 1, 0); 148 /** @const {number} */ var y1 = y; 149 /** @const {number} */ 150 var y2 = Math.min(y + 1, reference.getHeight() - 1); 151 152 //tcuBilinearImageCompare.readRGBA8List (reference, x0, y0, x2, y2); 153 154 if (tcuBilinearImageCompare.compareUintRGBA8Threshold(resPix, reference.readUintRGBA8(x1, y1), threshold) || 155 tcuBilinearImageCompare.compareUintRGBA8Threshold(resPix, reference.readUintRGBA8(x0, y1), threshold) || 156 tcuBilinearImageCompare.compareUintRGBA8Threshold(resPix, reference.readUintRGBA8(x2, y1), threshold) || 157 tcuBilinearImageCompare.compareUintRGBA8Threshold(resPix, reference.readUintRGBA8(x0, y0), threshold) || 158 tcuBilinearImageCompare.compareUintRGBA8Threshold(resPix, reference.readUintRGBA8(x1, y0), threshold) || 159 tcuBilinearImageCompare.compareUintRGBA8Threshold(resPix, reference.readUintRGBA8(x2, y0), threshold) || 160 tcuBilinearImageCompare.compareUintRGBA8Threshold(resPix, reference.readUintRGBA8(x0, y2), threshold) || 161 tcuBilinearImageCompare.compareUintRGBA8Threshold(resPix, reference.readUintRGBA8(x1, y2), threshold) || 162 tcuBilinearImageCompare.compareUintRGBA8Threshold(resPix, reference.readUintRGBA8(x2, y2), threshold)) 163 return true; 164 165 // Step 2: Compare using bilinear sampling. 166 // \todo [pyry] Optimize sample positions! 167 /** @const {Array<Array<number>>} */ var s_offsets = [ 168 [226, 186], 169 [335, 235], 170 [279, 334], 171 [178, 272], 172 [112, 202], 173 [306, 117], 174 [396, 299], 175 [206, 382], 176 [146, 96], 177 [423, 155], 178 [361, 412], 179 [84, 339], 180 [48, 130], 181 [367, 43], 182 [455, 367], 183 [105, 439], 184 [83, 46], 185 [217, 24], 186 [461, 71], 187 [450, 459], 188 [239, 469], 189 [67, 267], 190 [459, 255], 191 [13, 416], 192 [10, 192], 193 [141, 502], 194 [503, 304], 195 [380, 506] 196 ]; 197 198 for (var sampleNdx = 0; sampleNdx < s_offsets.length; sampleNdx++) { 199 /** @const {number} */ 200 var u = ((x - 1) << tcuBilinearImageCompare.NUM_SUBPIXEL_BITS) + s_offsets[sampleNdx][0]; 201 /** @const {number} */ 202 var v = ((y - 1) << tcuBilinearImageCompare.NUM_SUBPIXEL_BITS) + s_offsets[sampleNdx][1]; 203 204 if (!deMath.deInBounds32(u, 0, (reference.getWidth() - 1) << tcuBilinearImageCompare.NUM_SUBPIXEL_BITS) || 205 !deMath.deInBounds32(v, 0, (reference.getHeight() - 1) << tcuBilinearImageCompare.NUM_SUBPIXEL_BITS)) 206 continue; 207 208 if (tcuBilinearImageCompare.compareUintRGBA8Threshold(resPix, tcuBilinearImageCompare.bilinearSampleUintRGBA8(reference, u, v), threshold)) 209 return true; 210 } 211 212 return false; 213 }; 214 215 /** 216 * @param {tcuTexture.RGBA8View} reference 217 * @param {tcuTexture.RGBA8View} result 218 * @param {tcuTexture.PixelBufferAccess} errorMask 219 * @param {tcuRGBA.RGBA} threshold 220 * @return {boolean} 221 */ 222 tcuBilinearImageCompare.bilinearCompareRGBA8 = function(reference, result, errorMask, threshold) { 223 DE_ASSERT(reference.getFormat().isEqual(new tcuTexture.TextureFormat( 224 tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNORM_INT8))); 225 DE_ASSERT(result.getFormat().isEqual(new tcuTexture.TextureFormat( 226 tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNORM_INT8))); 227 228 // Clear error mask first to green (faster this way). 229 errorMask.clear([0.0, 1.0, 0.0, 1.0]); 230 231 /** @type {boolean} */ var allOk = true; 232 233 for (var y = 0; y < reference.getHeight(); y++) { 234 for (var x = 0; x < reference.getWidth(); x++) { 235 if (!tcuBilinearImageCompare.comparePixelRGBA8(reference, result, threshold, x, y) && 236 !tcuBilinearImageCompare.comparePixelRGBA8(result, reference, threshold, x, y)) { 237 allOk = false; 238 errorMask.setPixel([1.0, 0.0, 0.0, 1.0], x, y); 239 } 240 } 241 } 242 243 return allOk; 244 }; 245 246 /** 247 * @param {tcuTexture.ConstPixelBufferAccess} reference 248 * @param {tcuTexture.ConstPixelBufferAccess} result 249 * @param {tcuTexture.PixelBufferAccess} errorMask 250 * @param {tcuRGBA.RGBA} threshold 251 * @return {boolean} 252 */ 253 tcuBilinearImageCompare.bilinearCompare = function(reference, result, errorMask, threshold) { 254 assertMsgOptions(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight() && result.getDepth() == reference.getDepth(), 255 'Reference and result images have different dimensions', false, true); 256 257 assertMsgOptions(errorMask.getWidth() == reference.getWidth() && errorMask.getHeight() == reference.getHeight() && errorMask.getDepth() == reference.getDepth(), 258 'Reference and error mask images have different dimensions', false, true); 259 260 /** @type {boolean} */ var isEqual = reference.getFormat().isEqual( 261 new tcuTexture.TextureFormat( 262 tcuTexture.ChannelOrder.RGBA, 263 tcuTexture.ChannelType.UNORM_INT8)); 264 if (isEqual) { 265 /** @type {tcuTexture.RGBA8View} */ var refView = new tcuTexture.RGBA8View(reference); 266 /** @type {tcuTexture.RGBA8View} */ var resView = new tcuTexture.RGBA8View(result); 267 return tcuBilinearImageCompare.bilinearCompareRGBA8(refView, resView, errorMask, threshold); 268 } else 269 throw new Error('Unsupported format for bilinear comparison'); 270 }; 271 272 });