1*35238bceSAndroid Build Coastguard Worker /*-------------------------------------------------------------------------
2*35238bceSAndroid Build Coastguard Worker * drawElements Quality Program Tester Core
3*35238bceSAndroid Build Coastguard Worker * ----------------------------------------
4*35238bceSAndroid Build Coastguard Worker *
5*35238bceSAndroid Build Coastguard Worker * Copyright 2014 The Android Open Source Project
6*35238bceSAndroid Build Coastguard Worker *
7*35238bceSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
8*35238bceSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
9*35238bceSAndroid Build Coastguard Worker * You may obtain a copy of the License at
10*35238bceSAndroid Build Coastguard Worker *
11*35238bceSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
12*35238bceSAndroid Build Coastguard Worker *
13*35238bceSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
14*35238bceSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
15*35238bceSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16*35238bceSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
17*35238bceSAndroid Build Coastguard Worker * limitations under the License.
18*35238bceSAndroid Build Coastguard Worker *
19*35238bceSAndroid Build Coastguard Worker *//*!
20*35238bceSAndroid Build Coastguard Worker * \file
21*35238bceSAndroid Build Coastguard Worker * \brief Fuzzy image comparison.
22*35238bceSAndroid Build Coastguard Worker *//*--------------------------------------------------------------------*/
23*35238bceSAndroid Build Coastguard Worker
24*35238bceSAndroid Build Coastguard Worker #include "tcuFuzzyImageCompare.hpp"
25*35238bceSAndroid Build Coastguard Worker #include "tcuTexture.hpp"
26*35238bceSAndroid Build Coastguard Worker #include "tcuTextureUtil.hpp"
27*35238bceSAndroid Build Coastguard Worker #include "deMath.h"
28*35238bceSAndroid Build Coastguard Worker #include "deRandom.hpp"
29*35238bceSAndroid Build Coastguard Worker
30*35238bceSAndroid Build Coastguard Worker #include <vector>
31*35238bceSAndroid Build Coastguard Worker
32*35238bceSAndroid Build Coastguard Worker namespace tcu
33*35238bceSAndroid Build Coastguard Worker {
34*35238bceSAndroid Build Coastguard Worker
35*35238bceSAndroid Build Coastguard Worker enum
36*35238bceSAndroid Build Coastguard Worker {
37*35238bceSAndroid Build Coastguard Worker MIN_ERR_THRESHOLD = 4 // Magic to make small differences go away
38*35238bceSAndroid Build Coastguard Worker };
39*35238bceSAndroid Build Coastguard Worker
40*35238bceSAndroid Build Coastguard Worker using std::vector;
41*35238bceSAndroid Build Coastguard Worker
42*35238bceSAndroid Build Coastguard Worker template <int Channel>
getChannel(uint32_t color)43*35238bceSAndroid Build Coastguard Worker static inline uint8_t getChannel(uint32_t color)
44*35238bceSAndroid Build Coastguard Worker {
45*35238bceSAndroid Build Coastguard Worker return (uint8_t)((color >> (Channel * 8)) & 0xff);
46*35238bceSAndroid Build Coastguard Worker }
47*35238bceSAndroid Build Coastguard Worker
getChannel(uint32_t color,int channel)48*35238bceSAndroid Build Coastguard Worker static inline uint8_t getChannel(uint32_t color, int channel)
49*35238bceSAndroid Build Coastguard Worker {
50*35238bceSAndroid Build Coastguard Worker return (uint8_t)((color >> (channel * 8)) & 0xff);
51*35238bceSAndroid Build Coastguard Worker }
52*35238bceSAndroid Build Coastguard Worker
setChannel(uint32_t color,int channel,uint8_t val)53*35238bceSAndroid Build Coastguard Worker static inline uint32_t setChannel(uint32_t color, int channel, uint8_t val)
54*35238bceSAndroid Build Coastguard Worker {
55*35238bceSAndroid Build Coastguard Worker return (color & ~(0xffu << (8 * channel))) | (val << (8 * channel));
56*35238bceSAndroid Build Coastguard Worker }
57*35238bceSAndroid Build Coastguard Worker
toFloatVec(uint32_t color)58*35238bceSAndroid Build Coastguard Worker static inline Vec4 toFloatVec(uint32_t color)
59*35238bceSAndroid Build Coastguard Worker {
60*35238bceSAndroid Build Coastguard Worker return Vec4((float)getChannel<0>(color), (float)getChannel<1>(color), (float)getChannel<2>(color),
61*35238bceSAndroid Build Coastguard Worker (float)getChannel<3>(color));
62*35238bceSAndroid Build Coastguard Worker }
63*35238bceSAndroid Build Coastguard Worker
roundToUint8Sat(float v)64*35238bceSAndroid Build Coastguard Worker static inline uint8_t roundToUint8Sat(float v)
65*35238bceSAndroid Build Coastguard Worker {
66*35238bceSAndroid Build Coastguard Worker return (uint8_t)de::clamp((int)(v + 0.5f), 0, 255);
67*35238bceSAndroid Build Coastguard Worker }
68*35238bceSAndroid Build Coastguard Worker
toColor(Vec4 v)69*35238bceSAndroid Build Coastguard Worker static inline uint32_t toColor(Vec4 v)
70*35238bceSAndroid Build Coastguard Worker {
71*35238bceSAndroid Build Coastguard Worker return roundToUint8Sat(v[0]) | (roundToUint8Sat(v[1]) << 8) | (roundToUint8Sat(v[2]) << 16) |
72*35238bceSAndroid Build Coastguard Worker (roundToUint8Sat(v[3]) << 24);
73*35238bceSAndroid Build Coastguard Worker }
74*35238bceSAndroid Build Coastguard Worker
75*35238bceSAndroid Build Coastguard Worker template <int NumChannels>
readUnorm8(const tcu::ConstPixelBufferAccess & src,int x,int y)76*35238bceSAndroid Build Coastguard Worker static inline uint32_t readUnorm8(const tcu::ConstPixelBufferAccess &src, int x, int y)
77*35238bceSAndroid Build Coastguard Worker {
78*35238bceSAndroid Build Coastguard Worker const uint8_t *ptr = (const uint8_t *)src.getDataPtr() + src.getRowPitch() * y + x * NumChannels;
79*35238bceSAndroid Build Coastguard Worker uint32_t v = 0;
80*35238bceSAndroid Build Coastguard Worker
81*35238bceSAndroid Build Coastguard Worker for (int c = 0; c < NumChannels; c++)
82*35238bceSAndroid Build Coastguard Worker v |= ptr[c] << (c * 8);
83*35238bceSAndroid Build Coastguard Worker
84*35238bceSAndroid Build Coastguard Worker if (NumChannels < 4)
85*35238bceSAndroid Build Coastguard Worker v |= 0xffu << 24;
86*35238bceSAndroid Build Coastguard Worker
87*35238bceSAndroid Build Coastguard Worker return v;
88*35238bceSAndroid Build Coastguard Worker }
89*35238bceSAndroid Build Coastguard Worker
90*35238bceSAndroid Build Coastguard Worker #if (DE_ENDIANNESS == DE_LITTLE_ENDIAN)
91*35238bceSAndroid Build Coastguard Worker template <>
readUnorm8(const tcu::ConstPixelBufferAccess & src,int x,int y)92*35238bceSAndroid Build Coastguard Worker inline uint32_t readUnorm8<4>(const tcu::ConstPixelBufferAccess &src, int x, int y)
93*35238bceSAndroid Build Coastguard Worker {
94*35238bceSAndroid Build Coastguard Worker return *(const uint32_t *)((const uint8_t *)src.getDataPtr() + src.getRowPitch() * y + x * 4);
95*35238bceSAndroid Build Coastguard Worker }
96*35238bceSAndroid Build Coastguard Worker #endif
97*35238bceSAndroid Build Coastguard Worker
98*35238bceSAndroid Build Coastguard Worker template <int NumChannels>
writeUnorm8(const tcu::PixelBufferAccess & dst,int x,int y,uint32_t val)99*35238bceSAndroid Build Coastguard Worker static inline void writeUnorm8(const tcu::PixelBufferAccess &dst, int x, int y, uint32_t val)
100*35238bceSAndroid Build Coastguard Worker {
101*35238bceSAndroid Build Coastguard Worker uint8_t *ptr = (uint8_t *)dst.getDataPtr() + dst.getRowPitch() * y + x * NumChannels;
102*35238bceSAndroid Build Coastguard Worker
103*35238bceSAndroid Build Coastguard Worker for (int c = 0; c < NumChannels; c++)
104*35238bceSAndroid Build Coastguard Worker ptr[c] = getChannel(val, c);
105*35238bceSAndroid Build Coastguard Worker }
106*35238bceSAndroid Build Coastguard Worker
107*35238bceSAndroid Build Coastguard Worker #if (DE_ENDIANNESS == DE_LITTLE_ENDIAN)
108*35238bceSAndroid Build Coastguard Worker template <>
writeUnorm8(const tcu::PixelBufferAccess & dst,int x,int y,uint32_t val)109*35238bceSAndroid Build Coastguard Worker inline void writeUnorm8<4>(const tcu::PixelBufferAccess &dst, int x, int y, uint32_t val)
110*35238bceSAndroid Build Coastguard Worker {
111*35238bceSAndroid Build Coastguard Worker *(uint32_t *)((uint8_t *)dst.getDataPtr() + dst.getRowPitch() * y + x * 4) = val;
112*35238bceSAndroid Build Coastguard Worker }
113*35238bceSAndroid Build Coastguard Worker #endif
114*35238bceSAndroid Build Coastguard Worker
colorDistSquared(uint32_t pa,uint32_t pb)115*35238bceSAndroid Build Coastguard Worker static inline uint32_t colorDistSquared(uint32_t pa, uint32_t pb)
116*35238bceSAndroid Build Coastguard Worker {
117*35238bceSAndroid Build Coastguard Worker const int r = de::max<int>(de::abs((int)getChannel<0>(pa) - (int)getChannel<0>(pb)) - MIN_ERR_THRESHOLD, 0);
118*35238bceSAndroid Build Coastguard Worker const int g = de::max<int>(de::abs((int)getChannel<1>(pa) - (int)getChannel<1>(pb)) - MIN_ERR_THRESHOLD, 0);
119*35238bceSAndroid Build Coastguard Worker const int b = de::max<int>(de::abs((int)getChannel<2>(pa) - (int)getChannel<2>(pb)) - MIN_ERR_THRESHOLD, 0);
120*35238bceSAndroid Build Coastguard Worker const int a = de::max<int>(de::abs((int)getChannel<3>(pa) - (int)getChannel<3>(pb)) - MIN_ERR_THRESHOLD, 0);
121*35238bceSAndroid Build Coastguard Worker
122*35238bceSAndroid Build Coastguard Worker return uint32_t(r * r + g * g + b * b + a * a);
123*35238bceSAndroid Build Coastguard Worker }
124*35238bceSAndroid Build Coastguard Worker
125*35238bceSAndroid Build Coastguard Worker template <int NumChannels>
bilinearSample(const ConstPixelBufferAccess & src,float u,float v)126*35238bceSAndroid Build Coastguard Worker inline uint32_t bilinearSample(const ConstPixelBufferAccess &src, float u, float v)
127*35238bceSAndroid Build Coastguard Worker {
128*35238bceSAndroid Build Coastguard Worker int w = src.getWidth();
129*35238bceSAndroid Build Coastguard Worker int h = src.getHeight();
130*35238bceSAndroid Build Coastguard Worker
131*35238bceSAndroid Build Coastguard Worker int x0 = deFloorFloatToInt32(u - 0.5f);
132*35238bceSAndroid Build Coastguard Worker int x1 = x0 + 1;
133*35238bceSAndroid Build Coastguard Worker int y0 = deFloorFloatToInt32(v - 0.5f);
134*35238bceSAndroid Build Coastguard Worker int y1 = y0 + 1;
135*35238bceSAndroid Build Coastguard Worker
136*35238bceSAndroid Build Coastguard Worker int i0 = de::clamp(x0, 0, w - 1);
137*35238bceSAndroid Build Coastguard Worker int i1 = de::clamp(x1, 0, w - 1);
138*35238bceSAndroid Build Coastguard Worker int j0 = de::clamp(y0, 0, h - 1);
139*35238bceSAndroid Build Coastguard Worker int j1 = de::clamp(y1, 0, h - 1);
140*35238bceSAndroid Build Coastguard Worker
141*35238bceSAndroid Build Coastguard Worker float a = deFloatFrac(u - 0.5f);
142*35238bceSAndroid Build Coastguard Worker float b = deFloatFrac(v - 0.5f);
143*35238bceSAndroid Build Coastguard Worker
144*35238bceSAndroid Build Coastguard Worker uint32_t p00 = readUnorm8<NumChannels>(src, i0, j0);
145*35238bceSAndroid Build Coastguard Worker uint32_t p10 = readUnorm8<NumChannels>(src, i1, j0);
146*35238bceSAndroid Build Coastguard Worker uint32_t p01 = readUnorm8<NumChannels>(src, i0, j1);
147*35238bceSAndroid Build Coastguard Worker uint32_t p11 = readUnorm8<NumChannels>(src, i1, j1);
148*35238bceSAndroid Build Coastguard Worker uint32_t dst = 0;
149*35238bceSAndroid Build Coastguard Worker
150*35238bceSAndroid Build Coastguard Worker // Interpolate.
151*35238bceSAndroid Build Coastguard Worker for (int c = 0; c < NumChannels; c++)
152*35238bceSAndroid Build Coastguard Worker {
153*35238bceSAndroid Build Coastguard Worker float f = (getChannel(p00, c) * (1.0f - a) * (1.0f - b)) + (getChannel(p10, c) * (a) * (1.0f - b)) +
154*35238bceSAndroid Build Coastguard Worker (getChannel(p01, c) * (1.0f - a) * (b)) + (getChannel(p11, c) * (a) * (b));
155*35238bceSAndroid Build Coastguard Worker dst = setChannel(dst, c, roundToUint8Sat(f));
156*35238bceSAndroid Build Coastguard Worker }
157*35238bceSAndroid Build Coastguard Worker
158*35238bceSAndroid Build Coastguard Worker return dst;
159*35238bceSAndroid Build Coastguard Worker }
160*35238bceSAndroid Build Coastguard Worker
161*35238bceSAndroid Build Coastguard Worker template <int DstChannels, int SrcChannels>
separableConvolve(const PixelBufferAccess & dst,const ConstPixelBufferAccess & src,int shiftX,int shiftY,const std::vector<float> & kernelX,const std::vector<float> & kernelY)162*35238bceSAndroid Build Coastguard Worker static void separableConvolve(const PixelBufferAccess &dst, const ConstPixelBufferAccess &src, int shiftX, int shiftY,
163*35238bceSAndroid Build Coastguard Worker const std::vector<float> &kernelX, const std::vector<float> &kernelY)
164*35238bceSAndroid Build Coastguard Worker {
165*35238bceSAndroid Build Coastguard Worker DE_ASSERT(dst.getWidth() == src.getWidth() && dst.getHeight() == src.getHeight());
166*35238bceSAndroid Build Coastguard Worker
167*35238bceSAndroid Build Coastguard Worker TextureLevel tmp(dst.getFormat(), dst.getHeight(), dst.getWidth());
168*35238bceSAndroid Build Coastguard Worker PixelBufferAccess tmpAccess = tmp.getAccess();
169*35238bceSAndroid Build Coastguard Worker
170*35238bceSAndroid Build Coastguard Worker int kw = (int)kernelX.size();
171*35238bceSAndroid Build Coastguard Worker int kh = (int)kernelY.size();
172*35238bceSAndroid Build Coastguard Worker
173*35238bceSAndroid Build Coastguard Worker // Horizontal pass
174*35238bceSAndroid Build Coastguard Worker // \note Temporary surface is written in column-wise order
175*35238bceSAndroid Build Coastguard Worker for (int j = 0; j < src.getHeight(); j++)
176*35238bceSAndroid Build Coastguard Worker {
177*35238bceSAndroid Build Coastguard Worker for (int i = 0; i < src.getWidth(); i++)
178*35238bceSAndroid Build Coastguard Worker {
179*35238bceSAndroid Build Coastguard Worker Vec4 sum(0);
180*35238bceSAndroid Build Coastguard Worker
181*35238bceSAndroid Build Coastguard Worker for (int kx = 0; kx < kw; kx++)
182*35238bceSAndroid Build Coastguard Worker {
183*35238bceSAndroid Build Coastguard Worker float f = kernelX[kw - kx - 1];
184*35238bceSAndroid Build Coastguard Worker uint32_t p = readUnorm8<SrcChannels>(src, de::clamp(i + kx - shiftX, 0, src.getWidth() - 1), j);
185*35238bceSAndroid Build Coastguard Worker
186*35238bceSAndroid Build Coastguard Worker sum += toFloatVec(p) * f;
187*35238bceSAndroid Build Coastguard Worker }
188*35238bceSAndroid Build Coastguard Worker
189*35238bceSAndroid Build Coastguard Worker writeUnorm8<DstChannels>(tmpAccess, j, i, toColor(sum));
190*35238bceSAndroid Build Coastguard Worker }
191*35238bceSAndroid Build Coastguard Worker }
192*35238bceSAndroid Build Coastguard Worker
193*35238bceSAndroid Build Coastguard Worker // Vertical pass
194*35238bceSAndroid Build Coastguard Worker for (int j = 0; j < src.getHeight(); j++)
195*35238bceSAndroid Build Coastguard Worker {
196*35238bceSAndroid Build Coastguard Worker for (int i = 0; i < src.getWidth(); i++)
197*35238bceSAndroid Build Coastguard Worker {
198*35238bceSAndroid Build Coastguard Worker Vec4 sum(0.0f);
199*35238bceSAndroid Build Coastguard Worker
200*35238bceSAndroid Build Coastguard Worker for (int ky = 0; ky < kh; ky++)
201*35238bceSAndroid Build Coastguard Worker {
202*35238bceSAndroid Build Coastguard Worker float f = kernelY[kh - ky - 1];
203*35238bceSAndroid Build Coastguard Worker uint32_t p = readUnorm8<DstChannels>(tmpAccess, de::clamp(j + ky - shiftY, 0, tmp.getWidth() - 1), i);
204*35238bceSAndroid Build Coastguard Worker
205*35238bceSAndroid Build Coastguard Worker sum += toFloatVec(p) * f;
206*35238bceSAndroid Build Coastguard Worker }
207*35238bceSAndroid Build Coastguard Worker
208*35238bceSAndroid Build Coastguard Worker writeUnorm8<DstChannels>(dst, i, j, toColor(sum));
209*35238bceSAndroid Build Coastguard Worker }
210*35238bceSAndroid Build Coastguard Worker }
211*35238bceSAndroid Build Coastguard Worker }
212*35238bceSAndroid Build Coastguard Worker
213*35238bceSAndroid Build Coastguard Worker template <int NumChannels>
distSquaredToNeighbor(de::Random & rnd,uint32_t pixel,const ConstPixelBufferAccess & surface,int x,int y)214*35238bceSAndroid Build Coastguard Worker static uint32_t distSquaredToNeighbor(de::Random &rnd, uint32_t pixel, const ConstPixelBufferAccess &surface, int x,
215*35238bceSAndroid Build Coastguard Worker int y)
216*35238bceSAndroid Build Coastguard Worker {
217*35238bceSAndroid Build Coastguard Worker // (x, y) + (0, 0)
218*35238bceSAndroid Build Coastguard Worker uint32_t minDist = colorDistSquared(pixel, readUnorm8<NumChannels>(surface, x, y));
219*35238bceSAndroid Build Coastguard Worker
220*35238bceSAndroid Build Coastguard Worker if (minDist == 0)
221*35238bceSAndroid Build Coastguard Worker return minDist;
222*35238bceSAndroid Build Coastguard Worker
223*35238bceSAndroid Build Coastguard Worker // Area around (x, y)
224*35238bceSAndroid Build Coastguard Worker static const int s_coords[8][2] = {{-1, -1}, {0, -1}, {+1, -1}, {-1, 0}, {+1, 0}, {-1, +1}, {0, +1}, {+1, +1}};
225*35238bceSAndroid Build Coastguard Worker
226*35238bceSAndroid Build Coastguard Worker for (int d = 0; d < (int)DE_LENGTH_OF_ARRAY(s_coords); d++)
227*35238bceSAndroid Build Coastguard Worker {
228*35238bceSAndroid Build Coastguard Worker int dx = x + s_coords[d][0];
229*35238bceSAndroid Build Coastguard Worker int dy = y + s_coords[d][1];
230*35238bceSAndroid Build Coastguard Worker
231*35238bceSAndroid Build Coastguard Worker if (!deInBounds32(dx, 0, surface.getWidth()) || !deInBounds32(dy, 0, surface.getHeight()))
232*35238bceSAndroid Build Coastguard Worker continue;
233*35238bceSAndroid Build Coastguard Worker
234*35238bceSAndroid Build Coastguard Worker minDist = de::min(minDist, colorDistSquared(pixel, readUnorm8<NumChannels>(surface, dx, dy)));
235*35238bceSAndroid Build Coastguard Worker if (minDist == 0)
236*35238bceSAndroid Build Coastguard Worker return minDist;
237*35238bceSAndroid Build Coastguard Worker }
238*35238bceSAndroid Build Coastguard Worker
239*35238bceSAndroid Build Coastguard Worker // Random bilinear-interpolated samples around (x, y)
240*35238bceSAndroid Build Coastguard Worker for (int s = 0; s < 32; s++)
241*35238bceSAndroid Build Coastguard Worker {
242*35238bceSAndroid Build Coastguard Worker float dx = (float)x + rnd.getFloat() * 2.0f - 0.5f;
243*35238bceSAndroid Build Coastguard Worker float dy = (float)y + rnd.getFloat() * 2.0f - 0.5f;
244*35238bceSAndroid Build Coastguard Worker
245*35238bceSAndroid Build Coastguard Worker uint32_t sample = bilinearSample<NumChannels>(surface, dx, dy);
246*35238bceSAndroid Build Coastguard Worker
247*35238bceSAndroid Build Coastguard Worker minDist = de::min(minDist, colorDistSquared(pixel, sample));
248*35238bceSAndroid Build Coastguard Worker if (minDist == 0)
249*35238bceSAndroid Build Coastguard Worker return minDist;
250*35238bceSAndroid Build Coastguard Worker }
251*35238bceSAndroid Build Coastguard Worker
252*35238bceSAndroid Build Coastguard Worker return minDist;
253*35238bceSAndroid Build Coastguard Worker }
254*35238bceSAndroid Build Coastguard Worker
toGrayscale(const Vec4 & c)255*35238bceSAndroid Build Coastguard Worker static inline float toGrayscale(const Vec4 &c)
256*35238bceSAndroid Build Coastguard Worker {
257*35238bceSAndroid Build Coastguard Worker return 0.2126f * c[0] + 0.7152f * c[1] + 0.0722f * c[2];
258*35238bceSAndroid Build Coastguard Worker }
259*35238bceSAndroid Build Coastguard Worker
isFormatSupported(const TextureFormat & format)260*35238bceSAndroid Build Coastguard Worker static bool isFormatSupported(const TextureFormat &format)
261*35238bceSAndroid Build Coastguard Worker {
262*35238bceSAndroid Build Coastguard Worker return format.type == TextureFormat::UNORM_INT8 &&
263*35238bceSAndroid Build Coastguard Worker (format.order == TextureFormat::RGB || format.order == TextureFormat::RGBA);
264*35238bceSAndroid Build Coastguard Worker }
265*35238bceSAndroid Build Coastguard Worker
fuzzyCompare(const FuzzyCompareParams & params,const ConstPixelBufferAccess & ref,const ConstPixelBufferAccess & cmp,const PixelBufferAccess & errorMask)266*35238bceSAndroid Build Coastguard Worker float fuzzyCompare(const FuzzyCompareParams ¶ms, const ConstPixelBufferAccess &ref,
267*35238bceSAndroid Build Coastguard Worker const ConstPixelBufferAccess &cmp, const PixelBufferAccess &errorMask)
268*35238bceSAndroid Build Coastguard Worker {
269*35238bceSAndroid Build Coastguard Worker DE_ASSERT(ref.getWidth() == cmp.getWidth() && ref.getHeight() == cmp.getHeight());
270*35238bceSAndroid Build Coastguard Worker DE_ASSERT(errorMask.getWidth() == ref.getWidth() && errorMask.getHeight() == ref.getHeight());
271*35238bceSAndroid Build Coastguard Worker
272*35238bceSAndroid Build Coastguard Worker if (!isFormatSupported(ref.getFormat()) || !isFormatSupported(cmp.getFormat()))
273*35238bceSAndroid Build Coastguard Worker throw InternalError("Unsupported format in fuzzy comparison", DE_NULL, __FILE__, __LINE__);
274*35238bceSAndroid Build Coastguard Worker
275*35238bceSAndroid Build Coastguard Worker int width = ref.getWidth();
276*35238bceSAndroid Build Coastguard Worker int height = ref.getHeight();
277*35238bceSAndroid Build Coastguard Worker de::Random rnd(667);
278*35238bceSAndroid Build Coastguard Worker
279*35238bceSAndroid Build Coastguard Worker // Filtered
280*35238bceSAndroid Build Coastguard Worker TextureLevel refFiltered(TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8), width, height);
281*35238bceSAndroid Build Coastguard Worker TextureLevel cmpFiltered(TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8), width, height);
282*35238bceSAndroid Build Coastguard Worker
283*35238bceSAndroid Build Coastguard Worker // Kernel = {0.1, 0.8, 0.1}
284*35238bceSAndroid Build Coastguard Worker vector<float> kernel(3);
285*35238bceSAndroid Build Coastguard Worker kernel[0] = kernel[2] = 0.1f;
286*35238bceSAndroid Build Coastguard Worker kernel[1] = 0.8f;
287*35238bceSAndroid Build Coastguard Worker int shift = (int)(kernel.size() - 1) / 2;
288*35238bceSAndroid Build Coastguard Worker
289*35238bceSAndroid Build Coastguard Worker switch (ref.getFormat().order)
290*35238bceSAndroid Build Coastguard Worker {
291*35238bceSAndroid Build Coastguard Worker case TextureFormat::RGBA:
292*35238bceSAndroid Build Coastguard Worker separableConvolve<4, 4>(refFiltered, ref, shift, shift, kernel, kernel);
293*35238bceSAndroid Build Coastguard Worker break;
294*35238bceSAndroid Build Coastguard Worker case TextureFormat::RGB:
295*35238bceSAndroid Build Coastguard Worker separableConvolve<4, 3>(refFiltered, ref, shift, shift, kernel, kernel);
296*35238bceSAndroid Build Coastguard Worker break;
297*35238bceSAndroid Build Coastguard Worker default:
298*35238bceSAndroid Build Coastguard Worker DE_ASSERT(false);
299*35238bceSAndroid Build Coastguard Worker }
300*35238bceSAndroid Build Coastguard Worker
301*35238bceSAndroid Build Coastguard Worker switch (cmp.getFormat().order)
302*35238bceSAndroid Build Coastguard Worker {
303*35238bceSAndroid Build Coastguard Worker case TextureFormat::RGBA:
304*35238bceSAndroid Build Coastguard Worker separableConvolve<4, 4>(cmpFiltered, cmp, shift, shift, kernel, kernel);
305*35238bceSAndroid Build Coastguard Worker break;
306*35238bceSAndroid Build Coastguard Worker case TextureFormat::RGB:
307*35238bceSAndroid Build Coastguard Worker separableConvolve<4, 3>(cmpFiltered, cmp, shift, shift, kernel, kernel);
308*35238bceSAndroid Build Coastguard Worker break;
309*35238bceSAndroid Build Coastguard Worker default:
310*35238bceSAndroid Build Coastguard Worker DE_ASSERT(false);
311*35238bceSAndroid Build Coastguard Worker }
312*35238bceSAndroid Build Coastguard Worker
313*35238bceSAndroid Build Coastguard Worker int numSamples = 0;
314*35238bceSAndroid Build Coastguard Worker uint64_t distSum4 = 0ull;
315*35238bceSAndroid Build Coastguard Worker
316*35238bceSAndroid Build Coastguard Worker // Clear error mask to green.
317*35238bceSAndroid Build Coastguard Worker clear(errorMask, Vec4(0.0f, 1.0f, 0.0f, 1.0f));
318*35238bceSAndroid Build Coastguard Worker
319*35238bceSAndroid Build Coastguard Worker ConstPixelBufferAccess refAccess = refFiltered.getAccess();
320*35238bceSAndroid Build Coastguard Worker ConstPixelBufferAccess cmpAccess = cmpFiltered.getAccess();
321*35238bceSAndroid Build Coastguard Worker
322*35238bceSAndroid Build Coastguard Worker for (int y = 1; y < height - 1; y++)
323*35238bceSAndroid Build Coastguard Worker {
324*35238bceSAndroid Build Coastguard Worker for (int x = 1; x<width - 1; x += params.maxSampleSkip> 0 ? (int)rnd.getInt(1, params.maxSampleSkip) : 1)
325*35238bceSAndroid Build Coastguard Worker {
326*35238bceSAndroid Build Coastguard Worker const uint32_t minDist2RefToCmp =
327*35238bceSAndroid Build Coastguard Worker distSquaredToNeighbor<4>(rnd, readUnorm8<4>(refAccess, x, y), cmpAccess, x, y);
328*35238bceSAndroid Build Coastguard Worker const uint32_t minDist2CmpToRef =
329*35238bceSAndroid Build Coastguard Worker distSquaredToNeighbor<4>(rnd, readUnorm8<4>(cmpAccess, x, y), refAccess, x, y);
330*35238bceSAndroid Build Coastguard Worker const uint32_t minDist2 = de::min(minDist2RefToCmp, minDist2CmpToRef);
331*35238bceSAndroid Build Coastguard Worker const uint64_t newSum4 = distSum4 + minDist2 * minDist2;
332*35238bceSAndroid Build Coastguard Worker
333*35238bceSAndroid Build Coastguard Worker distSum4 = (newSum4 >= distSum4) ? newSum4 : ~0ull; // In case of overflow
334*35238bceSAndroid Build Coastguard Worker numSamples += 1;
335*35238bceSAndroid Build Coastguard Worker
336*35238bceSAndroid Build Coastguard Worker // Build error image.
337*35238bceSAndroid Build Coastguard Worker {
338*35238bceSAndroid Build Coastguard Worker const int scale = 255 - MIN_ERR_THRESHOLD;
339*35238bceSAndroid Build Coastguard Worker const float err2 = float(minDist2) / float(scale * scale);
340*35238bceSAndroid Build Coastguard Worker const float err4 = err2 * err2;
341*35238bceSAndroid Build Coastguard Worker const float red = err4 * 500.0f;
342*35238bceSAndroid Build Coastguard Worker const float luma = toGrayscale(cmp.getPixel(x, y));
343*35238bceSAndroid Build Coastguard Worker const float rF = 0.7f + 0.3f * luma;
344*35238bceSAndroid Build Coastguard Worker
345*35238bceSAndroid Build Coastguard Worker errorMask.setPixel(Vec4(red * rF, (1.0f - red) * rF, 0.0f, 1.0f), x, y);
346*35238bceSAndroid Build Coastguard Worker }
347*35238bceSAndroid Build Coastguard Worker }
348*35238bceSAndroid Build Coastguard Worker }
349*35238bceSAndroid Build Coastguard Worker
350*35238bceSAndroid Build Coastguard Worker {
351*35238bceSAndroid Build Coastguard Worker // Scale error sum based on number of samples taken
352*35238bceSAndroid Build Coastguard Worker const double pSamples = double((width - 2) * (height - 2)) / double(numSamples);
353*35238bceSAndroid Build Coastguard Worker const uint64_t colScale = uint64_t(255 - MIN_ERR_THRESHOLD);
354*35238bceSAndroid Build Coastguard Worker const uint64_t colScale4 = colScale * colScale * colScale * colScale;
355*35238bceSAndroid Build Coastguard Worker
356*35238bceSAndroid Build Coastguard Worker return float(double(distSum4) / double(colScale4) * pSamples);
357*35238bceSAndroid Build Coastguard Worker }
358*35238bceSAndroid Build Coastguard Worker }
359*35238bceSAndroid Build Coastguard Worker
360*35238bceSAndroid Build Coastguard Worker } // namespace tcu
361