13c827367444ee418f129b2c238299f49d3264554Jarkko Poyry/*------------------------------------------------------------------------- 23c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * drawElements Quality Program Tester Core 33c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * ---------------------------------------- 43c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * 53c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * Copyright 2014 The Android Open Source Project 63c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * 73c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * Licensed under the Apache License, Version 2.0 (the "License"); 83c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * you may not use this file except in compliance with the License. 93c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * You may obtain a copy of the License at 103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * 113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * http://www.apache.org/licenses/LICENSE-2.0 123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * 133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * Unless required by applicable law or agreed to in writing, software 143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * distributed under the License is distributed on an "AS IS" BASIS, 153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * See the License for the specific language governing permissions and 173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * limitations under the License. 183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * 193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *//*! 203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * \file 213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * \brief Fuzzy image comparison. 223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *//*--------------------------------------------------------------------*/ 233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "tcuFuzzyImageCompare.hpp" 253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "tcuTexture.hpp" 263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "tcuTextureUtil.hpp" 273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "deMath.h" 283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "deRandom.hpp" 293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include <vector> 313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 323c827367444ee418f129b2c238299f49d3264554Jarkko Poyrynamespace tcu 333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{ 343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 35ec91da5e9ca1fb19d6853c9535332a0085df2922Pyry Haulosenum 36ec91da5e9ca1fb19d6853c9535332a0085df2922Pyry Haulos{ 37ec91da5e9ca1fb19d6853c9535332a0085df2922Pyry Haulos MIN_ERR_THRESHOLD = 4 // Magic to make small differences go away 38ec91da5e9ca1fb19d6853c9535332a0085df2922Pyry Haulos}; 39ec91da5e9ca1fb19d6853c9535332a0085df2922Pyry Haulos 403c827367444ee418f129b2c238299f49d3264554Jarkko Poyryusing std::vector; 413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 423c827367444ee418f129b2c238299f49d3264554Jarkko Poyrytemplate<int Channel> 433c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic inline deUint8 getChannel (deUint32 color) 443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{ 453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry return (deUint8)((color >> (Channel*8)) & 0xff); 463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry} 473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 483c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic inline deUint8 getChannel (deUint32 color, int channel) 493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{ 503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry return (deUint8)((color >> (channel*8)) & 0xff); 513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry} 523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 533c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic inline deUint32 setChannel (deUint32 color, int channel, deUint8 val) 543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{ 553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry return (color & ~(0xffu << (8*channel))) | (val << (8*channel)); 563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry} 573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 583c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic inline Vec4 toFloatVec (deUint32 color) 593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{ 603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry return Vec4((float)getChannel<0>(color), (float)getChannel<1>(color), (float)getChannel<2>(color), (float)getChannel<3>(color)); 613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry} 623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 633c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic inline deUint8 roundToUint8Sat (float v) 643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{ 653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry return (deUint8)de::clamp((int)(v + 0.5f), 0, 255); 663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry} 673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 683c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic inline deUint32 toColor (Vec4 v) 693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{ 703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry return roundToUint8Sat(v[0]) | (roundToUint8Sat(v[1]) << 8) | (roundToUint8Sat(v[2]) << 16) | (roundToUint8Sat(v[3]) << 24); 713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry} 723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 733c827367444ee418f129b2c238299f49d3264554Jarkko Poyrytemplate<int NumChannels> 743c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic inline deUint32 readUnorm8 (const tcu::ConstPixelBufferAccess& src, int x, int y) 753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{ 763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry const deUint8* ptr = (const deUint8*)src.getDataPtr() + src.getRowPitch()*y + x*NumChannels; 773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry deUint32 v = 0; 783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry for (int c = 0; c < NumChannels; c++) 803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry v |= ptr[c] << (c*8); 813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry if (NumChannels < 4) 833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry v |= 0xffu << 24; 843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry return v; 863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry} 873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 8874731a6adf5816339b00b854a513b1b950ad4357Pyry Haulos#if (DE_ENDIANNESS == DE_LITTLE_ENDIAN) 893c827367444ee418f129b2c238299f49d3264554Jarkko Poyrytemplate<> 903c827367444ee418f129b2c238299f49d3264554Jarkko Poyryinline deUint32 readUnorm8<4> (const tcu::ConstPixelBufferAccess& src, int x, int y) 913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{ 923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry return *(const deUint32*)((const deUint8*)src.getDataPtr() + src.getRowPitch()*y + x*4); 933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry} 9474731a6adf5816339b00b854a513b1b950ad4357Pyry Haulos#endif 953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 963c827367444ee418f129b2c238299f49d3264554Jarkko Poyrytemplate<int NumChannels> 973c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic inline void writeUnorm8 (const tcu::PixelBufferAccess& dst, int x, int y, deUint32 val) 983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{ 993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry deUint8* ptr = (deUint8*)dst.getDataPtr() + dst.getRowPitch()*y + x*NumChannels; 1003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 1013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry for (int c = 0; c < NumChannels; c++) 1023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry ptr[c] = getChannel(val, c); 1033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry} 1043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 10574731a6adf5816339b00b854a513b1b950ad4357Pyry Haulos#if (DE_ENDIANNESS == DE_LITTLE_ENDIAN) 1063c827367444ee418f129b2c238299f49d3264554Jarkko Poyrytemplate<> 1073c827367444ee418f129b2c238299f49d3264554Jarkko Poyryinline void writeUnorm8<4> (const tcu::PixelBufferAccess& dst, int x, int y, deUint32 val) 1083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{ 1093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *(deUint32*)((deUint8*)dst.getDataPtr() + dst.getRowPitch()*y + x*4) = val; 1103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry} 11174731a6adf5816339b00b854a513b1b950ad4357Pyry Haulos#endif 1123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 113ec91da5e9ca1fb19d6853c9535332a0085df2922Pyry Haulosstatic inline deUint32 colorDistSquared (deUint32 pa, deUint32 pb) 1143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{ 115ec91da5e9ca1fb19d6853c9535332a0085df2922Pyry Haulos const int r = de::max<int>(de::abs((int)getChannel<0>(pa) - (int)getChannel<0>(pb)) - MIN_ERR_THRESHOLD, 0); 116ec91da5e9ca1fb19d6853c9535332a0085df2922Pyry Haulos const int g = de::max<int>(de::abs((int)getChannel<1>(pa) - (int)getChannel<1>(pb)) - MIN_ERR_THRESHOLD, 0); 117ec91da5e9ca1fb19d6853c9535332a0085df2922Pyry Haulos const int b = de::max<int>(de::abs((int)getChannel<2>(pa) - (int)getChannel<2>(pb)) - MIN_ERR_THRESHOLD, 0); 118ec91da5e9ca1fb19d6853c9535332a0085df2922Pyry Haulos const int a = de::max<int>(de::abs((int)getChannel<3>(pa) - (int)getChannel<3>(pb)) - MIN_ERR_THRESHOLD, 0); 1193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 120ec91da5e9ca1fb19d6853c9535332a0085df2922Pyry Haulos return deUint32(r*r + g*g + b*b + a*a); 1213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry} 1223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 1233c827367444ee418f129b2c238299f49d3264554Jarkko Poyrytemplate<int NumChannels> 1243c827367444ee418f129b2c238299f49d3264554Jarkko Poyryinline deUint32 bilinearSample (const ConstPixelBufferAccess& src, float u, float v) 1253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{ 1263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry int w = src.getWidth(); 1273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry int h = src.getHeight(); 1283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 1293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry int x0 = deFloorFloatToInt32(u-0.5f); 1303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry int x1 = x0+1; 1313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry int y0 = deFloorFloatToInt32(v-0.5f); 1323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry int y1 = y0+1; 1333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 1343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry int i0 = de::clamp(x0, 0, w-1); 1353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry int i1 = de::clamp(x1, 0, w-1); 1363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry int j0 = de::clamp(y0, 0, h-1); 1373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry int j1 = de::clamp(y1, 0, h-1); 1383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 1393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry float a = deFloatFrac(u-0.5f); 1403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry float b = deFloatFrac(v-0.5f); 1413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 1423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry deUint32 p00 = readUnorm8<NumChannels>(src, i0, j0); 1433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry deUint32 p10 = readUnorm8<NumChannels>(src, i1, j0); 1443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry deUint32 p01 = readUnorm8<NumChannels>(src, i0, j1); 1453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry deUint32 p11 = readUnorm8<NumChannels>(src, i1, j1); 1463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry deUint32 dst = 0; 1473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 1483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry // Interpolate. 1493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry for (int c = 0; c < NumChannels; c++) 1503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry { 1513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry float f = (getChannel(p00, c)*(1.0f-a)*(1.0f-b)) + 1523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry (getChannel(p10, c)*( a)*(1.0f-b)) + 1533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry (getChannel(p01, c)*(1.0f-a)*( b)) + 1543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry (getChannel(p11, c)*( a)*( b)); 1553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry dst = setChannel(dst, c, roundToUint8Sat(f)); 1563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry } 1573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 1583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry return dst; 1593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry} 1603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 1613c827367444ee418f129b2c238299f49d3264554Jarkko Poyrytemplate<int DstChannels, int SrcChannels> 1623c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic void separableConvolve (const PixelBufferAccess& dst, const ConstPixelBufferAccess& src, int shiftX, int shiftY, const std::vector<float>& kernelX, const std::vector<float>& kernelY) 1633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{ 1643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry DE_ASSERT(dst.getWidth() == src.getWidth() && dst.getHeight() == src.getHeight()); 1653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 1663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry TextureLevel tmp (dst.getFormat(), dst.getHeight(), dst.getWidth()); 1673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry PixelBufferAccess tmpAccess = tmp.getAccess(); 1683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 1693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry int kw = (int)kernelX.size(); 1703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry int kh = (int)kernelY.size(); 1713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 1723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry // Horizontal pass 1733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry // \note Temporary surface is written in column-wise order 1743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry for (int j = 0; j < src.getHeight(); j++) 1753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry { 1763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry for (int i = 0; i < src.getWidth(); i++) 1773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry { 1783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry Vec4 sum(0); 1793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 1803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry for (int kx = 0; kx < kw; kx++) 1813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry { 1823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry float f = kernelX[kw-kx-1]; 1833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry deUint32 p = readUnorm8<SrcChannels>(src, de::clamp(i+kx-shiftX, 0, src.getWidth()-1), j); 1843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 1853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry sum += toFloatVec(p)*f; 1863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry } 1873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 1883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry writeUnorm8<DstChannels>(tmpAccess, j, i, toColor(sum)); 1893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry } 1903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry } 1913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 1923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry // Vertical pass 1933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry for (int j = 0; j < src.getHeight(); j++) 1943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry { 1953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry for (int i = 0; i < src.getWidth(); i++) 1963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry { 1973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry Vec4 sum(0.0f); 1983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 1993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry for (int ky = 0; ky < kh; ky++) 2003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry { 2013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry float f = kernelY[kh-ky-1]; 2023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry deUint32 p = readUnorm8<DstChannels>(tmpAccess, de::clamp(j+ky-shiftY, 0, tmp.getWidth()-1), i); 2033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 2043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry sum += toFloatVec(p)*f; 2053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry } 2063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 2073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry writeUnorm8<DstChannels>(dst, i, j, toColor(sum)); 2083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry } 2093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry } 2103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry} 2113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 2123c827367444ee418f129b2c238299f49d3264554Jarkko Poyrytemplate<int NumChannels> 213ec91da5e9ca1fb19d6853c9535332a0085df2922Pyry Haulosstatic deUint32 distSquaredToNeighbor (de::Random& rnd, deUint32 pixel, const ConstPixelBufferAccess& surface, int x, int y) 2143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{ 2153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry // (x, y) + (0, 0) 216ec91da5e9ca1fb19d6853c9535332a0085df2922Pyry Haulos deUint32 minDist = colorDistSquared(pixel, readUnorm8<NumChannels>(surface, x, y)); 217ec91da5e9ca1fb19d6853c9535332a0085df2922Pyry Haulos 218ec91da5e9ca1fb19d6853c9535332a0085df2922Pyry Haulos if (minDist == 0) 219ec91da5e9ca1fb19d6853c9535332a0085df2922Pyry Haulos return minDist; 2203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 2213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry // Area around (x, y) 2223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry static const int s_coords[][2] = 2233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry { 2243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry {-1, -1}, 2253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry { 0, -1}, 2263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry {+1, -1}, 2273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry {-1, 0}, 2283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry {+1, 0}, 2293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry {-1, +1}, 2303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry { 0, +1}, 2313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry {+1, +1} 2323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry }; 2333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 2343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry for (int d = 0; d < (int)DE_LENGTH_OF_ARRAY(s_coords); d++) 2353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry { 2363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry int dx = x + s_coords[d][0]; 2373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry int dy = y + s_coords[d][1]; 2383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 2393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry if (!deInBounds32(dx, 0, surface.getWidth()) || !deInBounds32(dy, 0, surface.getHeight())) 2403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry continue; 2413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 242ec91da5e9ca1fb19d6853c9535332a0085df2922Pyry Haulos minDist = de::min(minDist, colorDistSquared(pixel, readUnorm8<NumChannels>(surface, dx, dy))); 243ec91da5e9ca1fb19d6853c9535332a0085df2922Pyry Haulos if (minDist == 0) 244ec91da5e9ca1fb19d6853c9535332a0085df2922Pyry Haulos return minDist; 2453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry } 2463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 2473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry // Random bilinear-interpolated samples around (x, y) 2483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry for (int s = 0; s < 32; s++) 2493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry { 2503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry float dx = (float)x + rnd.getFloat()*2.0f - 0.5f; 2513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry float dy = (float)y + rnd.getFloat()*2.0f - 0.5f; 2523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 2533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry deUint32 sample = bilinearSample<NumChannels>(surface, dx, dy); 2543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 255ec91da5e9ca1fb19d6853c9535332a0085df2922Pyry Haulos minDist = de::min(minDist, colorDistSquared(pixel, sample)); 256ec91da5e9ca1fb19d6853c9535332a0085df2922Pyry Haulos if (minDist == 0) 257ec91da5e9ca1fb19d6853c9535332a0085df2922Pyry Haulos return minDist; 2583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry } 2593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 260ec91da5e9ca1fb19d6853c9535332a0085df2922Pyry Haulos return minDist; 2613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry} 2623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 2633c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic inline float toGrayscale (const Vec4& c) 2643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{ 2653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry return 0.2126f*c[0] + 0.7152f*c[1] + 0.0722f*c[2]; 2663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry} 2673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 2683c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic bool isFormatSupported (const TextureFormat& format) 2693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{ 2703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry return format.type == TextureFormat::UNORM_INT8 && (format.order == TextureFormat::RGB || format.order == TextureFormat::RGBA); 2713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry} 2723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 2733c827367444ee418f129b2c238299f49d3264554Jarkko Poyryfloat fuzzyCompare (const FuzzyCompareParams& params, const ConstPixelBufferAccess& ref, const ConstPixelBufferAccess& cmp, const PixelBufferAccess& errorMask) 2743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{ 2753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry DE_ASSERT(ref.getWidth() == cmp.getWidth() && ref.getHeight() == cmp.getHeight()); 2763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry DE_ASSERT(errorMask.getWidth() == ref.getWidth() && errorMask.getHeight() == ref.getHeight()); 2773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 2783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry if (!isFormatSupported(ref.getFormat()) || !isFormatSupported(cmp.getFormat())) 2793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry throw InternalError("Unsupported format in fuzzy comparison", DE_NULL, __FILE__, __LINE__); 2803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 2813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry int width = ref.getWidth(); 2823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry int height = ref.getHeight(); 2833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry de::Random rnd (667); 2843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 2853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry // Filtered 2863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry TextureLevel refFiltered(TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8), width, height); 2873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry TextureLevel cmpFiltered(TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8), width, height); 2883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 289ec91da5e9ca1fb19d6853c9535332a0085df2922Pyry Haulos // Kernel = {0.1, 0.8, 0.1} 2903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry vector<float> kernel(3); 2913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry kernel[0] = kernel[2] = 0.1f; kernel[1]= 0.8f; 2923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry int shift = (int)(kernel.size() - 1) / 2; 2933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 2943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry switch (ref.getFormat().order) 2953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry { 2963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry case TextureFormat::RGBA: separableConvolve<4, 4>(refFiltered, ref, shift, shift, kernel, kernel); break; 2973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry case TextureFormat::RGB: separableConvolve<4, 3>(refFiltered, ref, shift, shift, kernel, kernel); break; 2983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry default: 2993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry DE_ASSERT(DE_FALSE); 3003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry } 3013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 3023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry switch (cmp.getFormat().order) 3033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry { 3043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry case TextureFormat::RGBA: separableConvolve<4, 4>(cmpFiltered, cmp, shift, shift, kernel, kernel); break; 3053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry case TextureFormat::RGB: separableConvolve<4, 3>(cmpFiltered, cmp, shift, shift, kernel, kernel); break; 3063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry default: 3073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry DE_ASSERT(DE_FALSE); 3083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry } 3093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 310ec91da5e9ca1fb19d6853c9535332a0085df2922Pyry Haulos int numSamples = 0; 311ec91da5e9ca1fb19d6853c9535332a0085df2922Pyry Haulos deUint64 distSum4 = 0ull; 3123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 3133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry // Clear error mask to green. 3143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry clear(errorMask, Vec4(0.0f, 1.0f, 0.0f, 1.0f)); 3153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 3163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry ConstPixelBufferAccess refAccess = refFiltered.getAccess(); 3173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry ConstPixelBufferAccess cmpAccess = cmpFiltered.getAccess(); 3183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 3193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry for (int y = 1; y < height-1; y++) 3203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry { 3213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry for (int x = 1; x < width-1; x += params.maxSampleSkip > 0 ? (int)rnd.getInt(0, params.maxSampleSkip) : 1) 3223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry { 3231c3ae95bd7fefdffccc8afc5565897aa8400de83Pyry Haulos const deUint32 minDist2RefToCmp = distSquaredToNeighbor<4>(rnd, readUnorm8<4>(refAccess, x, y), cmpAccess, x, y); 3241c3ae95bd7fefdffccc8afc5565897aa8400de83Pyry Haulos const deUint32 minDist2CmpToRef = distSquaredToNeighbor<4>(rnd, readUnorm8<4>(cmpAccess, x, y), refAccess, x, y); 3251c3ae95bd7fefdffccc8afc5565897aa8400de83Pyry Haulos const deUint32 minDist2 = de::min(minDist2RefToCmp, minDist2CmpToRef); 3261c3ae95bd7fefdffccc8afc5565897aa8400de83Pyry Haulos const deUint64 newSum4 = distSum4 + minDist2*minDist2; 3273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 328ec91da5e9ca1fb19d6853c9535332a0085df2922Pyry Haulos distSum4 = (newSum4 >= distSum4) ? newSum4 : ~0ull; // In case of overflow 3293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry numSamples += 1; 3303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 3313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry // Build error image. 332ec91da5e9ca1fb19d6853c9535332a0085df2922Pyry Haulos { 333ec91da5e9ca1fb19d6853c9535332a0085df2922Pyry Haulos const int scale = 255-MIN_ERR_THRESHOLD; 334ec91da5e9ca1fb19d6853c9535332a0085df2922Pyry Haulos const float err2 = float(minDist2) / float(scale*scale); 335ec91da5e9ca1fb19d6853c9535332a0085df2922Pyry Haulos const float err4 = err2*err2; 336ec91da5e9ca1fb19d6853c9535332a0085df2922Pyry Haulos const float red = err4 * 500.0f; 337ec91da5e9ca1fb19d6853c9535332a0085df2922Pyry Haulos const float luma = toGrayscale(cmp.getPixel(x, y)); 338ec91da5e9ca1fb19d6853c9535332a0085df2922Pyry Haulos const float rF = 0.7f + 0.3f*luma; 339ec91da5e9ca1fb19d6853c9535332a0085df2922Pyry Haulos 340ec91da5e9ca1fb19d6853c9535332a0085df2922Pyry Haulos errorMask.setPixel(Vec4(red*rF, (1.0f-red)*rF, 0.0f, 1.0f), x, y); 341ec91da5e9ca1fb19d6853c9535332a0085df2922Pyry Haulos } 3423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry } 3433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry } 3443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 345ec91da5e9ca1fb19d6853c9535332a0085df2922Pyry Haulos { 346ec91da5e9ca1fb19d6853c9535332a0085df2922Pyry Haulos // Scale error sum based on number of samples taken 347ec91da5e9ca1fb19d6853c9535332a0085df2922Pyry Haulos const double pSamples = double((width-2) * (height-2)) / double(numSamples); 348ec91da5e9ca1fb19d6853c9535332a0085df2922Pyry Haulos const deUint64 colScale = deUint64(255-MIN_ERR_THRESHOLD); 349ec91da5e9ca1fb19d6853c9535332a0085df2922Pyry Haulos const deUint64 colScale4 = colScale*colScale*colScale*colScale; 3503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 351ec91da5e9ca1fb19d6853c9535332a0085df2922Pyry Haulos return float(double(distSum4) / double(colScale4) * pSamples); 352ec91da5e9ca1fb19d6853c9535332a0085df2922Pyry Haulos } 3533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry} 3543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 3553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry} // tcu 356