Bug 1945965 – remove new tab April Fools logo. r=home-newtab-reviewers,reemhamz
[gecko.git] / dom / canvas / test / webgl-conf / checkout / deqp / framework / common / tcuFuzzyImageCompare.js
blob828d8301006675569fa51300e3b512ae1b773ef6
1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES Utilities
3 * ------------------------------------------------
5 * Copyright 2014 The Android Open Source Project
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 'use strict';
22 goog.provide('framework.common.tcuFuzzyImageCompare');
23 goog.require('framework.common.tcuTexture');
24 goog.require('framework.common.tcuTextureUtil');
25 goog.require('framework.delibs.debase.deMath');
26 goog.require('framework.delibs.debase.deRandom');
28 goog.scope(function() {
30 var tcuFuzzyImageCompare = framework.common.tcuFuzzyImageCompare;
31 var deMath = framework.delibs.debase.deMath;
32 var deRandom = framework.delibs.debase.deRandom;
33 var tcuTexture = framework.common.tcuTexture;
34 var tcuTextureUtil = framework.common.tcuTextureUtil;
36 var DE_ASSERT = function(x) {
37 if (!x)
38 throw new Error('Assert failed');
41 /**
42 * tcuFuzzyImageCompare.FuzzyCompareParams struct
43 * @constructor
44 * @param {number=} maxSampleSkip_
45 * @param {number=} minErrThreshold_
46 * @param {number=} errExp_
48 tcuFuzzyImageCompare.FuzzyCompareParams = function(maxSampleSkip_, minErrThreshold_, errExp_) {
49 /** @type {number} */ this.maxSampleSkip = maxSampleSkip_ === undefined ? 8 : maxSampleSkip_;
50 /** @type {number} */ this.minErrThreshold = minErrThreshold_ === undefined ? 4 : minErrThreshold_;
51 /** @type {number} */ this.errExp = errExp_ === undefined ? 4.0 : errExp_;
54 /**
55 * @param {Array<number>} v
56 * @return {Array<number>}
58 tcuFuzzyImageCompare.roundArray4ToUint8Sat = function(v) {
59 return [
60 deMath.clamp(Math.trunc(v[0] + 0.5), 0, 255),
61 deMath.clamp(Math.trunc(v[1] + 0.5), 0, 255),
62 deMath.clamp(Math.trunc(v[2] + 0.5), 0, 255),
63 deMath.clamp(Math.trunc(v[3] + 0.5), 0, 255)
67 /**
68 * @param {Array<number>} pa
69 * @param {Array<number>} pb
70 * @param {number} minErrThreshold
71 * @return {number}
73 tcuFuzzyImageCompare.compareColors = function(pa, pb, minErrThreshold) {
74 /** @type {number}*/ var r = Math.max(Math.abs(pa[0] - pb[0]) - minErrThreshold, 0);
75 /** @type {number}*/ var g = Math.max(Math.abs(pa[1] - pb[1]) - minErrThreshold, 0);
76 /** @type {number}*/ var b = Math.max(Math.abs(pa[2] - pb[2]) - minErrThreshold, 0);
77 /** @type {number}*/ var a = Math.max(Math.abs(pa[3] - pb[3]) - minErrThreshold, 0);
79 /** @type {number}*/ var scale = 1.0 / (255 - minErrThreshold);
80 /** @type {number}*/ var sqSum = (r * r + g * g + b * b + a * a) * (scale * scale);
82 return Math.sqrt(sqSum);
85 /**
86 * @param {tcuTexture.RGBA8View} src
87 * @param {number} u
88 * @param {number} v
89 * @param {number} NumChannels
90 * @return {Array<number>}
92 tcuFuzzyImageCompare.bilinearSample = function(src, u, v, NumChannels) {
93 /** @type {number}*/ var w = src.width;
94 /** @type {number}*/ var h = src.height;
96 /** @type {number}*/ var x0 = Math.floor(u - 0.5);
97 /** @type {number}*/ var x1 = x0 + 1;
98 /** @type {number}*/ var y0 = Math.floor(v - 0.5);
99 /** @type {number}*/ var y1 = y0 + 1;
101 /** @type {number}*/ var i0 = deMath.clamp(x0, 0, w - 1);
102 /** @type {number}*/ var i1 = deMath.clamp(x1, 0, w - 1);
103 /** @type {number}*/ var j0 = deMath.clamp(y0, 0, h - 1);
104 /** @type {number}*/ var j1 = deMath.clamp(y1, 0, h - 1);
106 /** @type {number}*/ var a = (u - 0.5) - Math.floor(u - 0.5);
107 /** @type {number}*/ var b = (v - 0.5) - Math.floor(v - 0.5);
109 /** @type {Array<number>} */ var p00 = src.read(i0, j0, NumChannels);
110 /** @type {Array<number>} */ var p10 = src.read(i1, j0, NumChannels);
111 /** @type {Array<number>} */ var p01 = src.read(i0, j1, NumChannels);
112 /** @type {Array<number>} */ var p11 = src.read(i1, j1, NumChannels);
113 /** @type {number} */ var dst = 0;
115 // Interpolate.
116 /** @type {Array<number>}*/ var f = [];
117 for (var c = 0; c < NumChannels; c++) {
118 f[c] = p00[c] * (1.0 - a) * (1.0 - b) +
119 (p10[c] * a * (1.0 - b)) +
120 (p01[c] * (1.0 - a) * b) +
121 (p11[c] * a * b);
124 return tcuFuzzyImageCompare.roundArray4ToUint8Sat(f);
128 * @param {tcuTexture.RGBA8View} dst
129 * @param {tcuTexture.RGBA8View} src
130 * @param {number} shiftX
131 * @param {number} shiftY
132 * @param {Array<number>} kernelX
133 * @param {Array<number>} kernelY
134 * @param {number} DstChannels
135 * @param {number} SrcChannels
137 tcuFuzzyImageCompare.separableConvolve = function(dst, src, shiftX, shiftY, kernelX, kernelY, DstChannels, SrcChannels) {
138 DE_ASSERT(dst.width == src.width && dst.height == src.height);
140 /** @type {tcuTexture.TextureLevel} */ var tmp = new tcuTexture.TextureLevel(dst.getFormat(), dst.height, dst.width);
141 var tmpView = new tcuTexture.RGBA8View(tmp.getAccess());
143 /** @type {number} */ var kw = kernelX.length;
144 /** @type {number} */ var kh = kernelY.length;
146 /** @type {Array<number>} */ var sum = [];
147 /** @type {number} */ var f;
148 /** @type {Array<number>} */ var p;
150 // Horizontal pass
151 // \note Temporary surface is written in column-wise order
152 for (var j = 0; j < src.height; j++) {
153 for (var i = 0; i < src.width; i++) {
154 sum[0] = sum[1] = sum[2] = sum[3] = 0;
155 for (var kx = 0; kx < kw; kx++) {
156 f = kernelX[kw - kx - 1];
157 p = src.read(deMath.clamp(i + kx - shiftX, 0, src.width - 1), j, SrcChannels);
158 sum = deMath.add(sum, deMath.scale(p, f));
161 sum = tcuFuzzyImageCompare.roundArray4ToUint8Sat(sum);
162 tmpView.write(j, i, sum, DstChannels);
166 // Vertical pass
167 for (var j = 0; j < src.height; j++) {
168 for (var i = 0; i < src.width; i++) {
169 sum[0] = sum[1] = sum[2] = sum[3] = 0;
170 for (var ky = 0; ky < kh; ky++) {
171 f = kernelY[kh - ky - 1];
172 p = tmpView.read(deMath.clamp(j + ky - shiftY, 0, tmpView.width - 1), i, DstChannels);
173 sum = deMath.add(sum, deMath.scale(p, f));
176 sum = tcuFuzzyImageCompare.roundArray4ToUint8Sat(sum);
177 dst.write(i, j, sum, DstChannels);
183 * @param {tcuFuzzyImageCompare.FuzzyCompareParams} params
184 * @param {deRandom.Random} rnd
185 * @param {Array<number>} pixel
186 * @param {tcuTexture.RGBA8View} surface
187 * @param {number} x
188 * @param {number} y
189 * @param {number} NumChannels
190 * @return {number}
192 tcuFuzzyImageCompare.compareToNeighbor = function(params, rnd, pixel, surface, x, y, NumChannels) {
193 /** @type {number} */ var minErr = 100;
195 // (x, y) + (0, 0)
196 minErr = Math.min(minErr, tcuFuzzyImageCompare.compareColors(pixel, surface.read(x, y, NumChannels), params.minErrThreshold));
197 if (minErr == 0.0)
198 return minErr;
200 // Area around (x, y)
201 /** @type {Array<Array.<number>>} */ var s_coords =
203 [-1, -1],
204 [0, -1],
205 [1, -1],
206 [-1, 0],
207 [1, 0],
208 [-1, 1],
209 [0, 1],
210 [1, 1]
213 /** @type {number} */ var dx;
214 /** @type {number} */ var dy;
216 for (var d = 0; d < s_coords.length; d++) {
217 dx = x + s_coords[d][0];
218 dy = y + s_coords[d][1];
220 if (!deMath.deInBounds32(dx, 0, surface.width) || !deMath.deInBounds32(dy, 0, surface.height))
221 continue;
223 minErr = Math.min(minErr, tcuFuzzyImageCompare.compareColors(pixel, surface.read(dx, dy, NumChannels), params.minErrThreshold));
224 if (minErr == 0.0)
225 return minErr;
228 // Random bilinear-interpolated samples around (x, y)
229 for (var s = 0; s < 32; s++) {
230 dx = x + rnd.getFloat() * 2.0 - 0.5;
231 dy = y + rnd.getFloat() * 2.0 - 0.5;
233 /** @type {Array<number>} */ var sample = tcuFuzzyImageCompare.bilinearSample(surface, dx, dy, NumChannels);
235 minErr = Math.min(minErr, tcuFuzzyImageCompare.compareColors(pixel, sample, params.minErrThreshold));
236 if (minErr == 0.0)
237 return minErr;
240 return minErr;
244 * @param {Array<number>} c
245 * @return {number}
247 tcuFuzzyImageCompare.toGrayscale = function(c) {
248 return 0.2126 * c[0] + 0.7152 * c[1] + 0.0722 * c[2];
252 * @param {tcuTexture.TextureFormat} format
253 * @return {boolean}
255 tcuFuzzyImageCompare.isFormatSupported = function(format) {
256 return format.type == tcuTexture.ChannelType.UNORM_INT8 && (format.order == tcuTexture.ChannelOrder.RGB || format.order == tcuTexture.ChannelOrder.RGBA);
260 * @param {tcuFuzzyImageCompare.FuzzyCompareParams} params
261 * @param {tcuTexture.ConstPixelBufferAccess} ref
262 * @param {tcuTexture.ConstPixelBufferAccess} cmp
263 * @param {tcuTexture.PixelBufferAccess} errorMask
264 * @return {number}
266 tcuFuzzyImageCompare.fuzzyCompare = function(params, ref, cmp, errorMask) {
267 assertMsgOptions(ref.getWidth() == cmp.getWidth() && ref.getHeight() == cmp.getHeight(),
268 'Reference and result images have different dimensions', false, true);
270 assertMsgOptions(ref.getWidth() == errorMask.getWidth() && ref.getHeight() == errorMask.getHeight(),
271 'Reference and error mask images have different dimensions', false, true);
273 if (!tcuFuzzyImageCompare.isFormatSupported(ref.getFormat()) || !tcuFuzzyImageCompare.isFormatSupported(cmp.getFormat()))
274 throw new Error('Unsupported format in fuzzy comparison');
276 /** @type {number} */ var width = ref.getWidth();
277 /** @type {number} */ var height = ref.getHeight();
278 /** @type {deRandom.Random} */ var rnd = new deRandom.Random(667);
280 // Filtered
281 /** @type {tcuTexture.TextureLevel} */ var refFiltered = new tcuTexture.TextureLevel(new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNORM_INT8), width, height);
282 /** @type {tcuTexture.TextureLevel} */ var cmpFiltered = new tcuTexture.TextureLevel(new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNORM_INT8), width, height);
284 var refView = new tcuTexture.RGBA8View(ref);
285 var cmpView = new tcuTexture.RGBA8View(cmp);
286 var refFilteredView = new tcuTexture.RGBA8View(tcuTexture.PixelBufferAccess.newFromTextureLevel(refFiltered));
287 var cmpFilteredView = new tcuTexture.RGBA8View(tcuTexture.PixelBufferAccess.newFromTextureLevel(cmpFiltered));
289 // Kernel = {0.15, 0.7, 0.15}
290 /** @type {Array<number>} */ var kernel = [0.1, 0.8, 0.1];
291 /** @type {number} */ var shift = Math.floor((kernel.length - 1) / 2);
293 switch (ref.getFormat().order) {
294 case tcuTexture.ChannelOrder.RGBA: tcuFuzzyImageCompare.separableConvolve(refFilteredView, refView, shift, shift, kernel, kernel, 4, 4); break;
295 case tcuTexture.ChannelOrder.RGB: tcuFuzzyImageCompare.separableConvolve(refFilteredView, refView, shift, shift, kernel, kernel, 4, 3); break;
296 default:
297 throw new Error('tcuFuzzyImageCompare.fuzzyCompare - Invalid ChannelOrder');
300 switch (cmp.getFormat().order) {
301 case tcuTexture.ChannelOrder.RGBA: tcuFuzzyImageCompare.separableConvolve(cmpFilteredView, cmpView, shift, shift, kernel, kernel, 4, 4); break;
302 case tcuTexture.ChannelOrder.RGB: tcuFuzzyImageCompare.separableConvolve(cmpFilteredView, cmpView, shift, shift, kernel, kernel, 4, 3); break;
303 default:
304 throw new Error('tcuFuzzyImageCompare.fuzzyCompare - Invalid ChannelOrder');
307 /** @type {number} */ var numSamples = 0;
308 /** @type {number} */ var errSum = 0.0;
310 // Clear error mask to green.
311 errorMask.clear([0.0, 1.0, 0.0, 1.0]);
313 for (var y = 1; y < height - 1; y++) {
314 for (var x = 1; x < width - 1; x += params.maxSampleSkip > 0 ? rnd.getInt(0, params.maxSampleSkip) : 1) {
315 /** @type {number} */ var err = Math.min(tcuFuzzyImageCompare.compareToNeighbor(params, rnd, refFilteredView.read(x, y, 4), cmpFilteredView, x, y, 4),
316 tcuFuzzyImageCompare.compareToNeighbor(params, rnd, cmpFilteredView.read(x, y, 4), refFilteredView, x, y, 4));
318 err = Math.pow(err, params.errExp);
320 errSum += err;
321 numSamples += 1;
323 // Build error image.
324 /** @type {number} */ var red = err * 500.0;
325 /** @type {number} */ var luma = tcuFuzzyImageCompare.toGrayscale(cmp.getPixel(x, y));
326 /** @type {number} */ var rF = 0.7 + 0.3 * luma;
327 errorMask.setPixel([red * rF, (1.0 - red) * rF, 0.0, 1.0], x, y);
332 // Scale error sum based on number of samples taken
333 errSum *= ((width - 2) * (height - 2)) / numSamples;
335 return errSum;