glsTextureTestUtil.cpp revision 23da2952459e6df3511da00f2a6c548a1b442c92
1/*------------------------------------------------------------------------- 2 * drawElements Quality Program OpenGL (ES) Module 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 * \file 21 * \brief Texture test utilities. 22 *//*--------------------------------------------------------------------*/ 23 24#include "glsTextureTestUtil.hpp" 25#include "gluDefs.hpp" 26#include "gluDrawUtil.hpp" 27#include "gluRenderContext.hpp" 28#include "deRandom.hpp" 29#include "tcuTestLog.hpp" 30#include "tcuVectorUtil.hpp" 31#include "tcuTextureUtil.hpp" 32#include "tcuImageCompare.hpp" 33#include "tcuStringTemplate.hpp" 34#include "tcuTexLookupVerifier.hpp" 35#include "tcuTexCompareVerifier.hpp" 36#include "glwEnums.hpp" 37#include "glwFunctions.hpp" 38#include "qpWatchDog.h" 39#include "deStringUtil.hpp" 40 41using tcu::TestLog; 42using std::vector; 43using std::string; 44using std::map; 45 46namespace deqp 47{ 48namespace gls 49{ 50namespace TextureTestUtil 51{ 52 53enum 54{ 55 MIN_SUBPIXEL_BITS = 4 56}; 57 58SamplerType getSamplerType (tcu::TextureFormat format) 59{ 60 using tcu::TextureFormat; 61 62 switch (format.type) 63 { 64 case TextureFormat::SIGNED_INT8: 65 case TextureFormat::SIGNED_INT16: 66 case TextureFormat::SIGNED_INT32: 67 return SAMPLERTYPE_INT; 68 69 case TextureFormat::UNSIGNED_INT8: 70 case TextureFormat::UNSIGNED_INT32: 71 case TextureFormat::UNSIGNED_INT_1010102_REV: 72 return SAMPLERTYPE_UINT; 73 74 // Texture formats used in depth/stencil textures. 75 case TextureFormat::UNSIGNED_INT16: 76 case TextureFormat::UNSIGNED_INT_24_8: 77 return (format.order == TextureFormat::D || format.order == TextureFormat::DS) ? SAMPLERTYPE_FLOAT : SAMPLERTYPE_UINT; 78 79 default: 80 return SAMPLERTYPE_FLOAT; 81 } 82} 83 84SamplerType getFetchSamplerType (tcu::TextureFormat format) 85{ 86 using tcu::TextureFormat; 87 88 switch (format.type) 89 { 90 case TextureFormat::SIGNED_INT8: 91 case TextureFormat::SIGNED_INT16: 92 case TextureFormat::SIGNED_INT32: 93 return SAMPLERTYPE_FETCH_INT; 94 95 case TextureFormat::UNSIGNED_INT8: 96 case TextureFormat::UNSIGNED_INT32: 97 case TextureFormat::UNSIGNED_INT_1010102_REV: 98 return SAMPLERTYPE_FETCH_UINT; 99 100 // Texture formats used in depth/stencil textures. 101 case TextureFormat::UNSIGNED_INT16: 102 case TextureFormat::UNSIGNED_INT_24_8: 103 return (format.order == TextureFormat::D || format.order == TextureFormat::DS) ? SAMPLERTYPE_FETCH_FLOAT : SAMPLERTYPE_FETCH_UINT; 104 105 default: 106 return SAMPLERTYPE_FETCH_FLOAT; 107 } 108} 109 110static tcu::Texture1DView getSubView (const tcu::Texture1DView& view, int baseLevel, int maxLevel) 111{ 112 const int clampedBase = de::clamp(baseLevel, 0, view.getNumLevels()-1); 113 const int clampedMax = de::clamp(maxLevel, clampedBase, view.getNumLevels()-1); 114 const int numLevels = clampedMax-clampedBase+1; 115 return tcu::Texture1DView(numLevels, view.getLevels()+clampedBase); 116} 117 118static tcu::Texture2DView getSubView (const tcu::Texture2DView& view, int baseLevel, int maxLevel) 119{ 120 const int clampedBase = de::clamp(baseLevel, 0, view.getNumLevels()-1); 121 const int clampedMax = de::clamp(maxLevel, clampedBase, view.getNumLevels()-1); 122 const int numLevels = clampedMax-clampedBase+1; 123 return tcu::Texture2DView(numLevels, view.getLevels()+clampedBase); 124} 125 126static tcu::TextureCubeView getSubView (const tcu::TextureCubeView& view, int baseLevel, int maxLevel) 127{ 128 const int clampedBase = de::clamp(baseLevel, 0, view.getNumLevels()-1); 129 const int clampedMax = de::clamp(maxLevel, clampedBase, view.getNumLevels()-1); 130 const int numLevels = clampedMax-clampedBase+1; 131 const tcu::ConstPixelBufferAccess* levels[tcu::CUBEFACE_LAST]; 132 133 for (int face = 0; face < tcu::CUBEFACE_LAST; face++) 134 levels[face] = view.getFaceLevels((tcu::CubeFace)face) + clampedBase; 135 136 return tcu::TextureCubeView(numLevels, levels); 137} 138 139static tcu::Texture3DView getSubView (const tcu::Texture3DView& view, int baseLevel, int maxLevel) 140{ 141 const int clampedBase = de::clamp(baseLevel, 0, view.getNumLevels()-1); 142 const int clampedMax = de::clamp(maxLevel, clampedBase, view.getNumLevels()-1); 143 const int numLevels = clampedMax-clampedBase+1; 144 return tcu::Texture3DView(numLevels, view.getLevels()+clampedBase); 145} 146 147static tcu::TextureCubeArrayView getSubView (const tcu::TextureCubeArrayView& view, int baseLevel, int maxLevel) 148{ 149 const int clampedBase = de::clamp(baseLevel, 0, view.getNumLevels()-1); 150 const int clampedMax = de::clamp(maxLevel, clampedBase, view.getNumLevels()-1); 151 const int numLevels = clampedMax-clampedBase+1; 152 return tcu::TextureCubeArrayView(numLevels, view.getLevels()+clampedBase); 153} 154 155template <typename ViewType> 156ViewType getEffectiveView (const ViewType& src, std::vector<tcu::ConstPixelBufferAccess>& storage, const tcu::Sampler& sampler) 157{ 158 storage.resize(src.getNumLevels()); 159 160 ViewType view = ViewType(src.getNumLevels(), &storage[0]); 161 162 for (int levelNdx = 0; levelNdx < src.getNumLevels(); ++levelNdx) 163 storage[levelNdx] = tcu::getEffectiveDepthStencilAccess(src.getLevel(levelNdx), sampler.depthStencilMode); 164 165 return view; 166} 167 168template <> 169tcu::TextureCubeView getEffectiveView (const tcu::TextureCubeView& src, std::vector<tcu::ConstPixelBufferAccess>& storage, const tcu::Sampler& sampler) 170{ 171 storage.resize(tcu::CUBEFACE_LAST * src.getNumLevels()); 172 173 const tcu::ConstPixelBufferAccess* storagePtrs[tcu::CUBEFACE_LAST] = 174 { 175 &storage[0 * src.getNumLevels()], 176 &storage[1 * src.getNumLevels()], 177 &storage[2 * src.getNumLevels()], 178 &storage[3 * src.getNumLevels()], 179 &storage[4 * src.getNumLevels()], 180 &storage[5 * src.getNumLevels()], 181 }; 182 183 tcu::TextureCubeView view = tcu::TextureCubeView(src.getNumLevels(), storagePtrs); 184 185 for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; ++faceNdx) 186 for (int levelNdx = 0; levelNdx < src.getNumLevels(); ++levelNdx) 187 storage[faceNdx * src.getNumLevels() + levelNdx] = tcu::getEffectiveDepthStencilAccess(src.getLevelFace(levelNdx, (tcu::CubeFace)faceNdx), sampler.depthStencilMode); 188 189 return view; 190} 191 192inline float linearInterpolate (float t, float minVal, float maxVal) 193{ 194 return minVal + (maxVal - minVal) * t; 195} 196 197inline tcu::Vec4 linearInterpolate (float t, const tcu::Vec4& a, const tcu::Vec4& b) 198{ 199 return a + (b - a) * t; 200} 201 202inline float bilinearInterpolate (float x, float y, const tcu::Vec4& quad) 203{ 204 float w00 = (1.0f-x)*(1.0f-y); 205 float w01 = (1.0f-x)*y; 206 float w10 = x*(1.0f-y); 207 float w11 = x*y; 208 return quad.x()*w00 + quad.y()*w10 + quad.z()*w01 + quad.w()*w11; 209} 210 211inline float triangleInterpolate (float v0, float v1, float v2, float x, float y) 212{ 213 return v0 + (v2-v0)*x + (v1-v0)*y; 214} 215 216inline float triangleInterpolate (const tcu::Vec3& v, float x, float y) 217{ 218 return triangleInterpolate(v.x(), v.y(), v.z(), x, y); 219} 220 221SurfaceAccess::SurfaceAccess (tcu::Surface& surface, const tcu::PixelFormat& colorFmt, int x, int y, int width, int height) 222 : m_surface (&surface) 223 , m_colorMask (getColorMask(colorFmt)) 224 , m_x (x) 225 , m_y (y) 226 , m_width (width) 227 , m_height (height) 228{ 229} 230 231SurfaceAccess::SurfaceAccess (tcu::Surface& surface, const tcu::PixelFormat& colorFmt) 232 : m_surface (&surface) 233 , m_colorMask (getColorMask(colorFmt)) 234 , m_x (0) 235 , m_y (0) 236 , m_width (surface.getWidth()) 237 , m_height (surface.getHeight()) 238{ 239} 240 241SurfaceAccess::SurfaceAccess (const SurfaceAccess& parent, int x, int y, int width, int height) 242 : m_surface (parent.m_surface) 243 , m_colorMask (parent.m_colorMask) 244 , m_x (parent.m_x + x) 245 , m_y (parent.m_y + y) 246 , m_width (width) 247 , m_height (height) 248{ 249} 250 251// 1D lookup LOD computation. 252 253inline float computeLodFromDerivates (LodMode mode, float dudx, float dudy) 254{ 255 float p = 0.0f; 256 switch (mode) 257 { 258 // \note [mika] Min and max bounds equal to exact with 1D textures 259 case LODMODE_EXACT: 260 case LODMODE_MIN_BOUND: 261 case LODMODE_MAX_BOUND: 262 p = de::max(deFloatAbs(dudx), deFloatAbs(dudy)); 263 break; 264 265 default: 266 DE_ASSERT(DE_FALSE); 267 } 268 269 return deFloatLog2(p); 270} 271 272static float computeNonProjectedTriLod (LodMode mode, const tcu::IVec2& dstSize, deInt32 srcSize, const tcu::Vec3& sq) 273{ 274 float dux = (sq.z() - sq.x()) * (float)srcSize; 275 float duy = (sq.y() - sq.x()) * (float)srcSize; 276 float dx = (float)dstSize.x(); 277 float dy = (float)dstSize.y(); 278 279 return computeLodFromDerivates(mode, dux/dx, duy/dy); 280} 281 282// 2D lookup LOD computation. 283 284inline float computeLodFromDerivates (LodMode mode, float dudx, float dvdx, float dudy, float dvdy) 285{ 286 float p = 0.0f; 287 switch (mode) 288 { 289 case LODMODE_EXACT: 290 p = de::max(deFloatSqrt(dudx*dudx + dvdx*dvdx), deFloatSqrt(dudy*dudy + dvdy*dvdy)); 291 break; 292 293 case LODMODE_MIN_BOUND: 294 case LODMODE_MAX_BOUND: 295 { 296 float mu = de::max(deFloatAbs(dudx), deFloatAbs(dudy)); 297 float mv = de::max(deFloatAbs(dvdx), deFloatAbs(dvdy)); 298 299 p = mode == LODMODE_MIN_BOUND ? de::max(mu, mv) : mu + mv; 300 break; 301 } 302 303 default: 304 DE_ASSERT(DE_FALSE); 305 } 306 307 return deFloatLog2(p); 308} 309 310static float computeNonProjectedTriLod (LodMode mode, const tcu::IVec2& dstSize, const tcu::IVec2& srcSize, const tcu::Vec3& sq, const tcu::Vec3& tq) 311{ 312 float dux = (sq.z() - sq.x()) * (float)srcSize.x(); 313 float duy = (sq.y() - sq.x()) * (float)srcSize.x(); 314 float dvx = (tq.z() - tq.x()) * (float)srcSize.y(); 315 float dvy = (tq.y() - tq.x()) * (float)srcSize.y(); 316 float dx = (float)dstSize.x(); 317 float dy = (float)dstSize.y(); 318 319 return computeLodFromDerivates(mode, dux/dx, dvx/dx, duy/dy, dvy/dy); 320} 321 322// 3D lookup LOD computation. 323 324inline float computeLodFromDerivates (LodMode mode, float dudx, float dvdx, float dwdx, float dudy, float dvdy, float dwdy) 325{ 326 float p = 0.0f; 327 switch (mode) 328 { 329 case LODMODE_EXACT: 330 p = de::max(deFloatSqrt(dudx*dudx + dvdx*dvdx + dwdx*dwdx), deFloatSqrt(dudy*dudy + dvdy*dvdy + dwdy*dwdy)); 331 break; 332 333 case LODMODE_MIN_BOUND: 334 case LODMODE_MAX_BOUND: 335 { 336 float mu = de::max(deFloatAbs(dudx), deFloatAbs(dudy)); 337 float mv = de::max(deFloatAbs(dvdx), deFloatAbs(dvdy)); 338 float mw = de::max(deFloatAbs(dwdx), deFloatAbs(dwdy)); 339 340 p = mode == LODMODE_MIN_BOUND ? de::max(de::max(mu, mv), mw) : (mu + mv + mw); 341 break; 342 } 343 344 default: 345 DE_ASSERT(DE_FALSE); 346 } 347 348 return deFloatLog2(p); 349} 350 351static float computeNonProjectedTriLod (LodMode mode, const tcu::IVec2& dstSize, const tcu::IVec3& srcSize, const tcu::Vec3& sq, const tcu::Vec3& tq, const tcu::Vec3& rq) 352{ 353 float dux = (sq.z() - sq.x()) * (float)srcSize.x(); 354 float duy = (sq.y() - sq.x()) * (float)srcSize.x(); 355 float dvx = (tq.z() - tq.x()) * (float)srcSize.y(); 356 float dvy = (tq.y() - tq.x()) * (float)srcSize.y(); 357 float dwx = (rq.z() - rq.x()) * (float)srcSize.z(); 358 float dwy = (rq.y() - rq.x()) * (float)srcSize.z(); 359 float dx = (float)dstSize.x(); 360 float dy = (float)dstSize.y(); 361 362 return computeLodFromDerivates(mode, dux/dx, dvx/dx, dwx/dx, duy/dy, dvy/dy, dwy/dy); 363} 364 365static inline float projectedTriInterpolate (const tcu::Vec3& s, const tcu::Vec3& w, float nx, float ny) 366{ 367 return (s[0]*(1.0f-nx-ny)/w[0] + s[1]*ny/w[1] + s[2]*nx/w[2]) / ((1.0f-nx-ny)/w[0] + ny/w[1] + nx/w[2]); 368} 369 370static inline float triDerivateX (const tcu::Vec3& s, const tcu::Vec3& w, float wx, float width, float ny) 371{ 372 float d = w[1]*w[2]*(width*(ny - 1.0f) + wx) - w[0]*(w[2]*width*ny + w[1]*wx); 373 return (w[0]*w[1]*w[2]*width * (w[1]*(s[0] - s[2])*(ny - 1.0f) + ny*(w[2]*(s[1] - s[0]) + w[0]*(s[2] - s[1])))) / (d*d); 374} 375 376static inline float triDerivateY (const tcu::Vec3& s, const tcu::Vec3& w, float wy, float height, float nx) 377{ 378 float d = w[1]*w[2]*(height*(nx - 1.0f) + wy) - w[0]*(w[1]*height*nx + w[2]*wy); 379 return (w[0]*w[1]*w[2]*height * (w[2]*(s[0] - s[1])*(nx - 1.0f) + nx*(w[0]*(s[1] - s[2]) + w[1]*(s[2] - s[0])))) / (d*d); 380} 381 382// 1D lookup LOD. 383static float computeProjectedTriLod (LodMode mode, const tcu::Vec3& u, const tcu::Vec3& projection, float wx, float wy, float width, float height) 384{ 385 // Exact derivatives. 386 float dudx = triDerivateX(u, projection, wx, width, wy/height); 387 float dudy = triDerivateY(u, projection, wy, height, wx/width); 388 389 return computeLodFromDerivates(mode, dudx, dudy); 390} 391 392// 2D lookup LOD. 393static float computeProjectedTriLod (LodMode mode, const tcu::Vec3& u, const tcu::Vec3& v, const tcu::Vec3& projection, float wx, float wy, float width, float height) 394{ 395 // Exact derivatives. 396 float dudx = triDerivateX(u, projection, wx, width, wy/height); 397 float dvdx = triDerivateX(v, projection, wx, width, wy/height); 398 float dudy = triDerivateY(u, projection, wy, height, wx/width); 399 float dvdy = triDerivateY(v, projection, wy, height, wx/width); 400 401 return computeLodFromDerivates(mode, dudx, dvdx, dudy, dvdy); 402} 403 404// 3D lookup LOD. 405static float computeProjectedTriLod (LodMode mode, const tcu::Vec3& u, const tcu::Vec3& v, const tcu::Vec3& w, const tcu::Vec3& projection, float wx, float wy, float width, float height) 406{ 407 // Exact derivatives. 408 float dudx = triDerivateX(u, projection, wx, width, wy/height); 409 float dvdx = triDerivateX(v, projection, wx, width, wy/height); 410 float dwdx = triDerivateX(w, projection, wx, width, wy/height); 411 float dudy = triDerivateY(u, projection, wy, height, wx/width); 412 float dvdy = triDerivateY(v, projection, wy, height, wx/width); 413 float dwdy = triDerivateY(w, projection, wy, height, wx/width); 414 415 return computeLodFromDerivates(mode, dudx, dvdx, dwdx, dudy, dvdy, dwdy); 416} 417 418static inline tcu::Vec4 execSample (const tcu::Texture1DView& src, const ReferenceParams& params, float s, float lod) 419{ 420 if (params.samplerType == SAMPLERTYPE_SHADOW) 421 return tcu::Vec4(src.sampleCompare(params.sampler, params.ref, s, lod), 0.0, 0.0, 1.0f); 422 else 423 return src.sample(params.sampler, s, lod); 424} 425 426static inline tcu::Vec4 execSample (const tcu::Texture2DView& src, const ReferenceParams& params, float s, float t, float lod) 427{ 428 if (params.samplerType == SAMPLERTYPE_SHADOW) 429 return tcu::Vec4(src.sampleCompare(params.sampler, params.ref, s, t, lod), 0.0, 0.0, 1.0f); 430 else 431 return src.sample(params.sampler, s, t, lod); 432} 433 434static inline tcu::Vec4 execSample (const tcu::TextureCubeView& src, const ReferenceParams& params, float s, float t, float r, float lod) 435{ 436 if (params.samplerType == SAMPLERTYPE_SHADOW) 437 return tcu::Vec4(src.sampleCompare(params.sampler, params.ref, s, t, r, lod), 0.0, 0.0, 1.0f); 438 else 439 return src.sample(params.sampler, s, t, r, lod); 440} 441 442static inline tcu::Vec4 execSample (const tcu::Texture2DArrayView& src, const ReferenceParams& params, float s, float t, float r, float lod) 443{ 444 if (params.samplerType == SAMPLERTYPE_SHADOW) 445 return tcu::Vec4(src.sampleCompare(params.sampler, params.ref, s, t, r, lod), 0.0, 0.0, 1.0f); 446 else 447 return src.sample(params.sampler, s, t, r, lod); 448} 449 450static inline tcu::Vec4 execSample (const tcu::TextureCubeArrayView& src, const ReferenceParams& params, float s, float t, float r, float q, float lod) 451{ 452 if (params.samplerType == SAMPLERTYPE_SHADOW) 453 return tcu::Vec4(src.sampleCompare(params.sampler, params.ref, s, t, r, q, lod), 0.0, 0.0, 1.0f); 454 else 455 return src.sample(params.sampler, s, t, r, q, lod); 456} 457 458static inline tcu::Vec4 execSample (const tcu::Texture1DArrayView& src, const ReferenceParams& params, float s, float t, float lod) 459{ 460 if (params.samplerType == SAMPLERTYPE_SHADOW) 461 return tcu::Vec4(src.sampleCompare(params.sampler, params.ref, s, t, lod), 0.0, 0.0, 1.0f); 462 else 463 return src.sample(params.sampler, s, t, lod); 464} 465 466static void sampleTextureNonProjected (const SurfaceAccess& dst, const tcu::Texture1DView& rawSrc, const tcu::Vec4& sq, const ReferenceParams& params) 467{ 468 // Separate combined DS formats 469 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage; 470 const tcu::Texture1DView src = getEffectiveView(rawSrc, srcLevelStorage, params.sampler); 471 472 float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f; 473 474 tcu::IVec2 dstSize = tcu::IVec2(dst.getWidth(), dst.getHeight()); 475 int srcSize = src.getWidth(); 476 477 // Coordinates and lod per triangle. 478 tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) }; 479 float triLod[2] = { de::clamp(computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[0]) + lodBias, params.minLod, params.maxLod), 480 de::clamp(computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[1]) + lodBias, params.minLod, params.maxLod) }; 481 482 for (int y = 0; y < dst.getHeight(); y++) 483 { 484 for (int x = 0; x < dst.getWidth(); x++) 485 { 486 float yf = ((float)y + 0.5f) / (float)dst.getHeight(); 487 float xf = ((float)x + 0.5f) / (float)dst.getWidth(); 488 489 int triNdx = xf + yf >= 1.0f ? 1 : 0; // Top left fill rule. 490 float triX = triNdx ? 1.0f-xf : xf; 491 float triY = triNdx ? 1.0f-yf : yf; 492 493 float s = triangleInterpolate(triS[triNdx].x(), triS[triNdx].y(), triS[triNdx].z(), triX, triY); 494 float lod = triLod[triNdx]; 495 496 dst.setPixel(execSample(src, params, s, lod) * params.colorScale + params.colorBias, x, y); 497 } 498 } 499} 500 501static void sampleTextureNonProjected (const SurfaceAccess& dst, const tcu::Texture2DView& rawSrc, const tcu::Vec4& sq, const tcu::Vec4& tq, const ReferenceParams& params) 502{ 503 // Separate combined DS formats 504 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage; 505 const tcu::Texture2DView src = getEffectiveView(rawSrc, srcLevelStorage, params.sampler); 506 507 float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f; 508 509 tcu::IVec2 dstSize = tcu::IVec2(dst.getWidth(), dst.getHeight()); 510 tcu::IVec2 srcSize = tcu::IVec2(src.getWidth(), src.getHeight()); 511 512 // Coordinates and lod per triangle. 513 tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) }; 514 tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) }; 515 float triLod[2] = { de::clamp(computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[0], triT[0]) + lodBias, params.minLod, params.maxLod), 516 de::clamp(computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[1], triT[1]) + lodBias, params.minLod, params.maxLod) }; 517 518 for (int y = 0; y < dst.getHeight(); y++) 519 { 520 for (int x = 0; x < dst.getWidth(); x++) 521 { 522 float yf = ((float)y + 0.5f) / (float)dst.getHeight(); 523 float xf = ((float)x + 0.5f) / (float)dst.getWidth(); 524 525 int triNdx = xf + yf >= 1.0f ? 1 : 0; // Top left fill rule. 526 float triX = triNdx ? 1.0f-xf : xf; 527 float triY = triNdx ? 1.0f-yf : yf; 528 529 float s = triangleInterpolate(triS[triNdx].x(), triS[triNdx].y(), triS[triNdx].z(), triX, triY); 530 float t = triangleInterpolate(triT[triNdx].x(), triT[triNdx].y(), triT[triNdx].z(), triX, triY); 531 float lod = triLod[triNdx]; 532 533 dst.setPixel(execSample(src, params, s, t, lod) * params.colorScale + params.colorBias, x, y); 534 } 535 } 536} 537 538static void sampleTextureProjected (const SurfaceAccess& dst, const tcu::Texture1DView& rawSrc, const tcu::Vec4& sq, const ReferenceParams& params) 539{ 540 // Separate combined DS formats 541 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage; 542 const tcu::Texture1DView src = getEffectiveView(rawSrc, srcLevelStorage, params.sampler); 543 544 float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f; 545 float dstW = (float)dst.getWidth(); 546 float dstH = (float)dst.getHeight(); 547 548 tcu::Vec4 uq = sq * (float)src.getWidth(); 549 550 tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) }; 551 tcu::Vec3 triU[2] = { uq.swizzle(0, 1, 2), uq.swizzle(3, 2, 1) }; 552 tcu::Vec3 triW[2] = { params.w.swizzle(0, 1, 2), params.w.swizzle(3, 2, 1) }; 553 554 for (int py = 0; py < dst.getHeight(); py++) 555 { 556 for (int px = 0; px < dst.getWidth(); px++) 557 { 558 float wx = (float)px + 0.5f; 559 float wy = (float)py + 0.5f; 560 float nx = wx / dstW; 561 float ny = wy / dstH; 562 563 int triNdx = nx + ny >= 1.0f ? 1 : 0; 564 float triWx = triNdx ? dstW - wx : wx; 565 float triWy = triNdx ? dstH - wy : wy; 566 float triNx = triNdx ? 1.0f - nx : nx; 567 float triNy = triNdx ? 1.0f - ny : ny; 568 569 float s = projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy); 570 float lod = computeProjectedTriLod(params.lodMode, triU[triNdx], triW[triNdx], triWx, triWy, (float)dst.getWidth(), (float)dst.getHeight()) 571 + lodBias; 572 573 dst.setPixel(execSample(src, params, s, lod) * params.colorScale + params.colorBias, px, py); 574 } 575 } 576} 577 578static void sampleTextureProjected (const SurfaceAccess& dst, const tcu::Texture2DView& rawSrc, const tcu::Vec4& sq, const tcu::Vec4& tq, const ReferenceParams& params) 579{ 580 // Separate combined DS formats 581 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage; 582 const tcu::Texture2DView src = getEffectiveView(rawSrc, srcLevelStorage, params.sampler); 583 584 float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f; 585 float dstW = (float)dst.getWidth(); 586 float dstH = (float)dst.getHeight(); 587 588 tcu::Vec4 uq = sq * (float)src.getWidth(); 589 tcu::Vec4 vq = tq * (float)src.getHeight(); 590 591 tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) }; 592 tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) }; 593 tcu::Vec3 triU[2] = { uq.swizzle(0, 1, 2), uq.swizzle(3, 2, 1) }; 594 tcu::Vec3 triV[2] = { vq.swizzle(0, 1, 2), vq.swizzle(3, 2, 1) }; 595 tcu::Vec3 triW[2] = { params.w.swizzle(0, 1, 2), params.w.swizzle(3, 2, 1) }; 596 597 for (int py = 0; py < dst.getHeight(); py++) 598 { 599 for (int px = 0; px < dst.getWidth(); px++) 600 { 601 float wx = (float)px + 0.5f; 602 float wy = (float)py + 0.5f; 603 float nx = wx / dstW; 604 float ny = wy / dstH; 605 606 int triNdx = nx + ny >= 1.0f ? 1 : 0; 607 float triWx = triNdx ? dstW - wx : wx; 608 float triWy = triNdx ? dstH - wy : wy; 609 float triNx = triNdx ? 1.0f - nx : nx; 610 float triNy = triNdx ? 1.0f - ny : ny; 611 612 float s = projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy); 613 float t = projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy); 614 float lod = computeProjectedTriLod(params.lodMode, triU[triNdx], triV[triNdx], triW[triNdx], triWx, triWy, (float)dst.getWidth(), (float)dst.getHeight()) 615 + lodBias; 616 617 dst.setPixel(execSample(src, params, s, t, lod) * params.colorScale + params.colorBias, px, py); 618 } 619 } 620} 621 622void sampleTexture (const SurfaceAccess& dst, const tcu::Texture2DView& src, const float* texCoord, const ReferenceParams& params) 623{ 624 const tcu::Texture2DView view = getSubView(src, params.baseLevel, params.maxLevel); 625 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[2+0], texCoord[4+0], texCoord[6+0]); 626 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[2+1], texCoord[4+1], texCoord[6+1]); 627 628 if (params.flags & ReferenceParams::PROJECTED) 629 sampleTextureProjected(dst, view, sq, tq, params); 630 else 631 sampleTextureNonProjected(dst, view, sq, tq, params); 632} 633 634void sampleTexture (const SurfaceAccess& dst, const tcu::Texture1DView& src, const float* texCoord, const ReferenceParams& params) 635{ 636 const tcu::Texture1DView view = getSubView(src, params.baseLevel, params.maxLevel); 637 const tcu::Vec4 sq = tcu::Vec4(texCoord[0], texCoord[1], texCoord[2], texCoord[3]); 638 639 if (params.flags & ReferenceParams::PROJECTED) 640 sampleTextureProjected(dst, view, sq, params); 641 else 642 sampleTextureNonProjected(dst, view, sq, params); 643} 644 645static float computeCubeLodFromDerivates (LodMode lodMode, const tcu::Vec3& coord, const tcu::Vec3& coordDx, const tcu::Vec3& coordDy, const int faceSize) 646{ 647 const tcu::CubeFace face = tcu::selectCubeFace(coord); 648 int maNdx = 0; 649 int sNdx = 0; 650 int tNdx = 0; 651 652 // \note Derivate signs don't matter when computing lod 653 switch (face) 654 { 655 case tcu::CUBEFACE_NEGATIVE_X: 656 case tcu::CUBEFACE_POSITIVE_X: maNdx = 0; sNdx = 2; tNdx = 1; break; 657 case tcu::CUBEFACE_NEGATIVE_Y: 658 case tcu::CUBEFACE_POSITIVE_Y: maNdx = 1; sNdx = 0; tNdx = 2; break; 659 case tcu::CUBEFACE_NEGATIVE_Z: 660 case tcu::CUBEFACE_POSITIVE_Z: maNdx = 2; sNdx = 0; tNdx = 1; break; 661 default: 662 DE_ASSERT(DE_FALSE); 663 } 664 665 { 666 const float sc = coord[sNdx]; 667 const float tc = coord[tNdx]; 668 const float ma = de::abs(coord[maNdx]); 669 const float scdx = coordDx[sNdx]; 670 const float tcdx = coordDx[tNdx]; 671 const float madx = de::abs(coordDx[maNdx]); 672 const float scdy = coordDy[sNdx]; 673 const float tcdy = coordDy[tNdx]; 674 const float mady = de::abs(coordDy[maNdx]); 675 const float dudx = float(faceSize) * 0.5f * (scdx*ma - sc*madx) / (ma*ma); 676 const float dvdx = float(faceSize) * 0.5f * (tcdx*ma - tc*madx) / (ma*ma); 677 const float dudy = float(faceSize) * 0.5f * (scdy*ma - sc*mady) / (ma*ma); 678 const float dvdy = float(faceSize) * 0.5f * (tcdy*ma - tc*mady) / (ma*ma); 679 680 return computeLodFromDerivates(lodMode, dudx, dvdx, dudy, dvdy); 681 } 682} 683 684static void sampleTextureCube (const SurfaceAccess& dst, const tcu::TextureCubeView& rawSrc, const tcu::Vec4& sq, const tcu::Vec4& tq, const tcu::Vec4& rq, const ReferenceParams& params) 685{ 686 // Separate combined DS formats 687 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage; 688 const tcu::TextureCubeView src = getEffectiveView(rawSrc, srcLevelStorage, params.sampler); 689 690 const tcu::IVec2 dstSize = tcu::IVec2(dst.getWidth(), dst.getHeight()); 691 const float dstW = float(dstSize.x()); 692 const float dstH = float(dstSize.y()); 693 const int srcSize = src.getSize(); 694 695 // Coordinates per triangle. 696 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) }; 697 const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) }; 698 const tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) }; 699 const tcu::Vec3 triW[2] = { params.w.swizzle(0, 1, 2), params.w.swizzle(3, 2, 1) }; 700 701 const float lodBias ((params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f); 702 703 for (int py = 0; py < dst.getHeight(); py++) 704 { 705 for (int px = 0; px < dst.getWidth(); px++) 706 { 707 const float wx = (float)px + 0.5f; 708 const float wy = (float)py + 0.5f; 709 const float nx = wx / dstW; 710 const float ny = wy / dstH; 711 712 const int triNdx = nx + ny >= 1.0f ? 1 : 0; 713 const float triNx = triNdx ? 1.0f - nx : nx; 714 const float triNy = triNdx ? 1.0f - ny : ny; 715 716 const tcu::Vec3 coord (triangleInterpolate(triS[triNdx], triNx, triNy), 717 triangleInterpolate(triT[triNdx], triNx, triNy), 718 triangleInterpolate(triR[triNdx], triNx, triNy)); 719 const tcu::Vec3 coordDx (triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy), 720 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy), 721 triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy)); 722 const tcu::Vec3 coordDy (triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx), 723 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx), 724 triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx)); 725 726 const float lod = de::clamp(computeCubeLodFromDerivates(params.lodMode, coord, coordDx, coordDy, srcSize) + lodBias, params.minLod, params.maxLod); 727 728 dst.setPixel(execSample(src, params, coord.x(), coord.y(), coord.z(), lod) * params.colorScale + params.colorBias, px, py); 729 } 730 } 731} 732 733void sampleTexture (const SurfaceAccess& dst, const tcu::TextureCubeView& src, const float* texCoord, const ReferenceParams& params) 734{ 735 const tcu::TextureCubeView view = getSubView(src, params.baseLevel, params.maxLevel); 736 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]); 737 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]); 738 const tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]); 739 740 return sampleTextureCube(dst, view, sq, tq, rq, params); 741} 742 743static void sampleTextureNonProjected (const SurfaceAccess& dst, const tcu::Texture2DArrayView& rawSrc, const tcu::Vec4& sq, const tcu::Vec4& tq, const tcu::Vec4& rq, const ReferenceParams& params) 744{ 745 // Separate combined DS formats 746 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage; 747 const tcu::Texture2DArrayView src = getEffectiveView(rawSrc, srcLevelStorage, params.sampler); 748 749 float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f; 750 751 tcu::IVec2 dstSize = tcu::IVec2(dst.getWidth(), dst.getHeight()); 752 tcu::IVec2 srcSize = tcu::IVec2(src.getWidth(), src.getHeight()); 753 754 // Coordinates and lod per triangle. 755 tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) }; 756 tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) }; 757 tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) }; 758 float triLod[2] = { computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[0], triT[0]) + lodBias, 759 computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[1], triT[1]) + lodBias}; 760 761 for (int y = 0; y < dst.getHeight(); y++) 762 { 763 for (int x = 0; x < dst.getWidth(); x++) 764 { 765 float yf = ((float)y + 0.5f) / (float)dst.getHeight(); 766 float xf = ((float)x + 0.5f) / (float)dst.getWidth(); 767 768 int triNdx = xf + yf >= 1.0f ? 1 : 0; // Top left fill rule. 769 float triX = triNdx ? 1.0f-xf : xf; 770 float triY = triNdx ? 1.0f-yf : yf; 771 772 float s = triangleInterpolate(triS[triNdx].x(), triS[triNdx].y(), triS[triNdx].z(), triX, triY); 773 float t = triangleInterpolate(triT[triNdx].x(), triT[triNdx].y(), triT[triNdx].z(), triX, triY); 774 float r = triangleInterpolate(triR[triNdx].x(), triR[triNdx].y(), triR[triNdx].z(), triX, triY); 775 float lod = triLod[triNdx]; 776 777 dst.setPixel(execSample(src, params, s, t, r, lod) * params.colorScale + params.colorBias, x, y); 778 } 779 } 780} 781 782void sampleTexture (const SurfaceAccess& dst, const tcu::Texture2DArrayView& src, const float* texCoord, const ReferenceParams& params) 783{ 784 tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]); 785 tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]); 786 tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]); 787 788 DE_ASSERT(!(params.flags & ReferenceParams::PROJECTED)); // \todo [2012-02-17 pyry] Support projected lookups. 789 sampleTextureNonProjected(dst, src, sq, tq, rq, params); 790} 791 792static void sampleTextureNonProjected (const SurfaceAccess& dst, const tcu::Texture1DArrayView& rawSrc, const tcu::Vec4& sq, const tcu::Vec4& tq, const ReferenceParams& params) 793{ 794 // Separate combined DS formats 795 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage; 796 const tcu::Texture1DArrayView src = getEffectiveView(rawSrc, srcLevelStorage, params.sampler); 797 798 float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f; 799 800 tcu::IVec2 dstSize = tcu::IVec2(dst.getWidth(), dst.getHeight()); 801 deInt32 srcSize = src.getWidth(); 802 803 // Coordinates and lod per triangle. 804 tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) }; 805 tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) }; 806 float triLod[2] = { computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[0]) + lodBias, 807 computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[1]) + lodBias}; 808 809 for (int y = 0; y < dst.getHeight(); y++) 810 { 811 for (int x = 0; x < dst.getWidth(); x++) 812 { 813 float yf = ((float)y + 0.5f) / (float)dst.getHeight(); 814 float xf = ((float)x + 0.5f) / (float)dst.getWidth(); 815 816 int triNdx = xf + yf >= 1.0f ? 1 : 0; // Top left fill rule. 817 float triX = triNdx ? 1.0f-xf : xf; 818 float triY = triNdx ? 1.0f-yf : yf; 819 820 float s = triangleInterpolate(triS[triNdx].x(), triS[triNdx].y(), triS[triNdx].z(), triX, triY); 821 float t = triangleInterpolate(triT[triNdx].x(), triT[triNdx].y(), triT[triNdx].z(), triX, triY); 822 float lod = triLod[triNdx]; 823 824 dst.setPixel(execSample(src, params, s, t, lod) * params.colorScale + params.colorBias, x, y); 825 } 826 } 827} 828 829void sampleTexture (const SurfaceAccess& dst, const tcu::Texture1DArrayView& src, const float* texCoord, const ReferenceParams& params) 830{ 831 tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[2+0], texCoord[4+0], texCoord[6+0]); 832 tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[2+1], texCoord[4+1], texCoord[6+1]); 833 834 DE_ASSERT(!(params.flags & ReferenceParams::PROJECTED)); // \todo [2014-06-09 mika] Support projected lookups. 835 sampleTextureNonProjected(dst, src, sq, tq, params); 836} 837 838static void sampleTextureNonProjected (const SurfaceAccess& dst, const tcu::Texture3DView& rawSrc, const tcu::Vec4& sq, const tcu::Vec4& tq, const tcu::Vec4& rq, const ReferenceParams& params) 839{ 840 // Separate combined DS formats 841 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage; 842 const tcu::Texture3DView src = getEffectiveView(rawSrc, srcLevelStorage, params.sampler); 843 844 float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f; 845 846 tcu::IVec2 dstSize = tcu::IVec2(dst.getWidth(), dst.getHeight()); 847 tcu::IVec3 srcSize = tcu::IVec3(src.getWidth(), src.getHeight(), src.getDepth()); 848 849 // Coordinates and lod per triangle. 850 tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) }; 851 tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) }; 852 tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) }; 853 float triLod[2] = { de::clamp(computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[0], triT[0], triR[0]) + lodBias, params.minLod, params.maxLod), 854 de::clamp(computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[1], triT[1], triR[1]) + lodBias, params.minLod, params.maxLod) }; 855 856 for (int y = 0; y < dst.getHeight(); y++) 857 { 858 for (int x = 0; x < dst.getWidth(); x++) 859 { 860 float yf = ((float)y + 0.5f) / (float)dst.getHeight(); 861 float xf = ((float)x + 0.5f) / (float)dst.getWidth(); 862 863 int triNdx = xf + yf >= 1.0f ? 1 : 0; // Top left fill rule. 864 float triX = triNdx ? 1.0f-xf : xf; 865 float triY = triNdx ? 1.0f-yf : yf; 866 867 float s = triangleInterpolate(triS[triNdx].x(), triS[triNdx].y(), triS[triNdx].z(), triX, triY); 868 float t = triangleInterpolate(triT[triNdx].x(), triT[triNdx].y(), triT[triNdx].z(), triX, triY); 869 float r = triangleInterpolate(triR[triNdx].x(), triR[triNdx].y(), triR[triNdx].z(), triX, triY); 870 float lod = triLod[triNdx]; 871 872 dst.setPixel(src.sample(params.sampler, s, t, r, lod) * params.colorScale + params.colorBias, x, y); 873 } 874 } 875} 876 877static void sampleTextureProjected (const SurfaceAccess& dst, const tcu::Texture3DView& rawSrc, const tcu::Vec4& sq, const tcu::Vec4& tq, const tcu::Vec4& rq, const ReferenceParams& params) 878{ 879 // Separate combined DS formats 880 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage; 881 const tcu::Texture3DView src = getEffectiveView(rawSrc, srcLevelStorage, params.sampler); 882 883 float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f; 884 float dstW = (float)dst.getWidth(); 885 float dstH = (float)dst.getHeight(); 886 887 tcu::Vec4 uq = sq * (float)src.getWidth(); 888 tcu::Vec4 vq = tq * (float)src.getHeight(); 889 tcu::Vec4 wq = rq * (float)src.getDepth(); 890 891 tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) }; 892 tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) }; 893 tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) }; 894 tcu::Vec3 triU[2] = { uq.swizzle(0, 1, 2), uq.swizzle(3, 2, 1) }; 895 tcu::Vec3 triV[2] = { vq.swizzle(0, 1, 2), vq.swizzle(3, 2, 1) }; 896 tcu::Vec3 triW[2] = { wq.swizzle(0, 1, 2), wq.swizzle(3, 2, 1) }; 897 tcu::Vec3 triP[2] = { params.w.swizzle(0, 1, 2), params.w.swizzle(3, 2, 1) }; 898 899 for (int py = 0; py < dst.getHeight(); py++) 900 { 901 for (int px = 0; px < dst.getWidth(); px++) 902 { 903 float wx = (float)px + 0.5f; 904 float wy = (float)py + 0.5f; 905 float nx = wx / dstW; 906 float ny = wy / dstH; 907 908 int triNdx = nx + ny >= 1.0f ? 1 : 0; 909 float triWx = triNdx ? dstW - wx : wx; 910 float triWy = triNdx ? dstH - wy : wy; 911 float triNx = triNdx ? 1.0f - nx : nx; 912 float triNy = triNdx ? 1.0f - ny : ny; 913 914 float s = projectedTriInterpolate(triS[triNdx], triP[triNdx], triNx, triNy); 915 float t = projectedTriInterpolate(triT[triNdx], triP[triNdx], triNx, triNy); 916 float r = projectedTriInterpolate(triR[triNdx], triP[triNdx], triNx, triNy); 917 float lod = computeProjectedTriLod(params.lodMode, triU[triNdx], triV[triNdx], triW[triNdx], triP[triNdx], triWx, triWy, (float)dst.getWidth(), (float)dst.getHeight()) 918 + lodBias; 919 920 dst.setPixel(src.sample(params.sampler, s, t, r, lod) * params.colorScale + params.colorBias, px, py); 921 } 922 } 923} 924 925void sampleTexture (const SurfaceAccess& dst, const tcu::Texture3DView& src, const float* texCoord, const ReferenceParams& params) 926{ 927 const tcu::Texture3DView view = getSubView(src, params.baseLevel, params.maxLevel); 928 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]); 929 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]); 930 const tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]); 931 932 if (params.flags & ReferenceParams::PROJECTED) 933 sampleTextureProjected(dst, view, sq, tq, rq, params); 934 else 935 sampleTextureNonProjected(dst, view, sq, tq, rq, params); 936} 937 938static void sampleTextureCubeArray (const SurfaceAccess& dst, const tcu::TextureCubeArrayView& rawSrc, const tcu::Vec4& sq, const tcu::Vec4& tq, const tcu::Vec4& rq, const tcu::Vec4& qq, const ReferenceParams& params) 939{ 940 // Separate combined DS formats 941 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage; 942 const tcu::TextureCubeArrayView src = getEffectiveView(rawSrc, srcLevelStorage, params.sampler); 943 944 const float dstW = (float)dst.getWidth(); 945 const float dstH = (float)dst.getHeight(); 946 947 // Coordinates per triangle. 948 tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) }; 949 tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) }; 950 tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) }; 951 tcu::Vec3 triQ[2] = { qq.swizzle(0, 1, 2), qq.swizzle(3, 2, 1) }; 952 const tcu::Vec3 triW[2] = { params.w.swizzle(0, 1, 2), params.w.swizzle(3, 2, 1) }; 953 954 const float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f; 955 956 for (int py = 0; py < dst.getHeight(); py++) 957 { 958 for (int px = 0; px < dst.getWidth(); px++) 959 { 960 const float wx = (float)px + 0.5f; 961 const float wy = (float)py + 0.5f; 962 const float nx = wx / dstW; 963 const float ny = wy / dstH; 964 965 const int triNdx = nx + ny >= 1.0f ? 1 : 0; 966 const float triNx = triNdx ? 1.0f - nx : nx; 967 const float triNy = triNdx ? 1.0f - ny : ny; 968 969 const tcu::Vec3 coord (triangleInterpolate(triS[triNdx], triNx, triNy), 970 triangleInterpolate(triT[triNdx], triNx, triNy), 971 triangleInterpolate(triR[triNdx], triNx, triNy)); 972 973 const float coordQ = triangleInterpolate(triQ[triNdx], triNx, triNy); 974 975 const tcu::Vec3 coordDx (triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy), 976 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy), 977 triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy)); 978 const tcu::Vec3 coordDy (triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx), 979 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx), 980 triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx)); 981 982 const float lod = de::clamp(computeCubeLodFromDerivates(params.lodMode, coord, coordDx, coordDy, src.getSize()) + lodBias, params.minLod, params.maxLod); 983 984 dst.setPixel(execSample(src, params, coord.x(), coord.y(), coord.z(), coordQ, lod) * params.colorScale + params.colorBias, px, py); 985 } 986 } 987} 988 989void sampleTexture (const SurfaceAccess& dst, const tcu::TextureCubeArrayView& src, const float* texCoord, const ReferenceParams& params) 990{ 991 tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[4+0], texCoord[8+0], texCoord[12+0]); 992 tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[4+1], texCoord[8+1], texCoord[12+1]); 993 tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[4+2], texCoord[8+2], texCoord[12+2]); 994 tcu::Vec4 qq = tcu::Vec4(texCoord[0+3], texCoord[4+3], texCoord[8+3], texCoord[12+3]); 995 996 sampleTextureCubeArray(dst, src, sq, tq, rq, qq, params); 997} 998 999void fetchTexture (const SurfaceAccess& dst, const tcu::ConstPixelBufferAccess& src, const float* texCoord, const tcu::Vec4& colorScale, const tcu::Vec4& colorBias) 1000{ 1001 const tcu::Vec4 sq = tcu::Vec4(texCoord[0], texCoord[1], texCoord[2], texCoord[3]); 1002 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) }; 1003 1004 for (int y = 0; y < dst.getHeight(); y++) 1005 { 1006 for (int x = 0; x < dst.getWidth(); x++) 1007 { 1008 const float yf = ((float)y + 0.5f) / (float)dst.getHeight(); 1009 const float xf = ((float)x + 0.5f) / (float)dst.getWidth(); 1010 1011 const int triNdx = xf + yf >= 1.0f ? 1 : 0; // Top left fill rule. 1012 const float triX = triNdx ? 1.0f-xf : xf; 1013 const float triY = triNdx ? 1.0f-yf : yf; 1014 1015 const float s = triangleInterpolate(triS[triNdx].x(), triS[triNdx].y(), triS[triNdx].z(), triX, triY); 1016 1017 dst.setPixel(src.getPixel((int)s, 0) * colorScale + colorBias, x, y); 1018 } 1019 } 1020} 1021 1022void clear (const SurfaceAccess& dst, const tcu::Vec4& color) 1023{ 1024 for (int y = 0; y < dst.getHeight(); y++) 1025 for (int x = 0; x < dst.getWidth(); x++) 1026 dst.setPixel(color, x, y); 1027} 1028 1029bool compareImages (TestLog& log, const tcu::Surface& reference, const tcu::Surface& rendered, tcu::RGBA threshold) 1030{ 1031 return tcu::pixelThresholdCompare(log, "Result", "Image comparison result", reference, rendered, threshold, tcu::COMPARE_LOG_RESULT); 1032} 1033 1034bool compareImages (TestLog& log, const char* name, const char* desc, const tcu::Surface& reference, const tcu::Surface& rendered, tcu::RGBA threshold) 1035{ 1036 return tcu::pixelThresholdCompare(log, name, desc, reference, rendered, threshold, tcu::COMPARE_LOG_RESULT); 1037} 1038 1039int measureAccuracy (tcu::TestLog& log, const tcu::Surface& reference, const tcu::Surface& rendered, int bestScoreDiff, int worstScoreDiff) 1040{ 1041 return tcu::measurePixelDiffAccuracy(log, "Result", "Image comparison result", reference, rendered, bestScoreDiff, worstScoreDiff, tcu::COMPARE_LOG_EVERYTHING); 1042} 1043 1044inline int rangeDiff (int x, int a, int b) 1045{ 1046 if (x < a) 1047 return a-x; 1048 else if (x > b) 1049 return x-b; 1050 else 1051 return 0; 1052} 1053 1054inline tcu::RGBA rangeDiff (tcu::RGBA p, tcu::RGBA a, tcu::RGBA b) 1055{ 1056 int rMin = de::min(a.getRed(), b.getRed()); 1057 int rMax = de::max(a.getRed(), b.getRed()); 1058 int gMin = de::min(a.getGreen(), b.getGreen()); 1059 int gMax = de::max(a.getGreen(), b.getGreen()); 1060 int bMin = de::min(a.getBlue(), b.getBlue()); 1061 int bMax = de::max(a.getBlue(), b.getBlue()); 1062 int aMin = de::min(a.getAlpha(), b.getAlpha()); 1063 int aMax = de::max(a.getAlpha(), b.getAlpha()); 1064 1065 return tcu::RGBA(rangeDiff(p.getRed(), rMin, rMax), 1066 rangeDiff(p.getGreen(), gMin, gMax), 1067 rangeDiff(p.getBlue(), bMin, bMax), 1068 rangeDiff(p.getAlpha(), aMin, aMax)); 1069} 1070 1071inline bool rangeCompare (tcu::RGBA p, tcu::RGBA a, tcu::RGBA b, tcu::RGBA threshold) 1072{ 1073 tcu::RGBA diff = rangeDiff(p, a, b); 1074 return diff.getRed() <= threshold.getRed() && 1075 diff.getGreen() <= threshold.getGreen() && 1076 diff.getBlue() <= threshold.getBlue() && 1077 diff.getAlpha() <= threshold.getAlpha(); 1078} 1079 1080RandomViewport::RandomViewport (const tcu::RenderTarget& renderTarget, int preferredWidth, int preferredHeight, deUint32 seed) 1081 : x (0) 1082 , y (0) 1083 , width (deMin32(preferredWidth, renderTarget.getWidth())) 1084 , height (deMin32(preferredHeight, renderTarget.getHeight())) 1085{ 1086 de::Random rnd(seed); 1087 x = rnd.getInt(0, renderTarget.getWidth() - width); 1088 y = rnd.getInt(0, renderTarget.getHeight() - height); 1089} 1090 1091ProgramLibrary::ProgramLibrary (const glu::RenderContext& context, tcu::TestLog& log, glu::GLSLVersion glslVersion, glu::Precision texCoordPrecision) 1092 : m_context (context) 1093 , m_log (log) 1094 , m_glslVersion (glslVersion) 1095 , m_texCoordPrecision (texCoordPrecision) 1096{ 1097} 1098 1099ProgramLibrary::~ProgramLibrary (void) 1100{ 1101 clear(); 1102} 1103 1104void ProgramLibrary::clear (void) 1105{ 1106 for (map<Program, glu::ShaderProgram*>::iterator i = m_programs.begin(); i != m_programs.end(); i++) 1107 { 1108 delete i->second; 1109 i->second = DE_NULL; 1110 } 1111 m_programs.clear(); 1112} 1113 1114glu::ShaderProgram* ProgramLibrary::getProgram (Program program) 1115{ 1116 if (m_programs.find(program) != m_programs.end()) 1117 return m_programs[program]; // Return from cache. 1118 1119 static const char* vertShaderTemplate = 1120 "${VTX_HEADER}" 1121 "${VTX_IN} highp vec4 a_position;\n" 1122 "${VTX_IN} ${PRECISION} ${TEXCOORD_TYPE} a_texCoord;\n" 1123 "${VTX_OUT} ${PRECISION} ${TEXCOORD_TYPE} v_texCoord;\n" 1124 "\n" 1125 "void main (void)\n" 1126 "{\n" 1127 " gl_Position = a_position;\n" 1128 " v_texCoord = a_texCoord;\n" 1129 "}\n"; 1130 static const char* fragShaderTemplate = 1131 "${FRAG_HEADER}" 1132 "${FRAG_IN} ${PRECISION} ${TEXCOORD_TYPE} v_texCoord;\n" 1133 "uniform ${PRECISION} float u_bias;\n" 1134 "uniform ${PRECISION} float u_ref;\n" 1135 "uniform ${PRECISION} vec4 u_colorScale;\n" 1136 "uniform ${PRECISION} vec4 u_colorBias;\n" 1137 "uniform ${PRECISION} ${SAMPLER_TYPE} u_sampler;\n" 1138 "\n" 1139 "void main (void)\n" 1140 "{\n" 1141 " ${FRAG_COLOR} = ${LOOKUP} * u_colorScale + u_colorBias;\n" 1142 "}\n"; 1143 1144 map<string, string> params; 1145 1146 bool isCube = de::inRange<int>(program, PROGRAM_CUBE_FLOAT, PROGRAM_CUBE_SHADOW_BIAS); 1147 bool isArray = de::inRange<int>(program, PROGRAM_2D_ARRAY_FLOAT, PROGRAM_2D_ARRAY_SHADOW) 1148 || de::inRange<int>(program, PROGRAM_1D_ARRAY_FLOAT, PROGRAM_1D_ARRAY_SHADOW); 1149 1150 bool is1D = de::inRange<int>(program, PROGRAM_1D_FLOAT, PROGRAM_1D_UINT_BIAS) 1151 || de::inRange<int>(program, PROGRAM_1D_ARRAY_FLOAT, PROGRAM_1D_ARRAY_SHADOW) 1152 || de::inRange<int>(program, PROGRAM_BUFFER_FLOAT, PROGRAM_BUFFER_UINT); 1153 1154 bool is2D = de::inRange<int>(program, PROGRAM_2D_FLOAT, PROGRAM_2D_UINT_BIAS) 1155 || de::inRange<int>(program, PROGRAM_2D_ARRAY_FLOAT, PROGRAM_2D_ARRAY_SHADOW); 1156 1157 bool is3D = de::inRange<int>(program, PROGRAM_3D_FLOAT, PROGRAM_3D_UINT_BIAS); 1158 bool isCubeArray = de::inRange<int>(program, PROGRAM_CUBE_ARRAY_FLOAT, PROGRAM_CUBE_ARRAY_SHADOW); 1159 bool isBuffer = de::inRange<int>(program, PROGRAM_BUFFER_FLOAT, PROGRAM_BUFFER_UINT); 1160 1161 if (m_glslVersion == glu::GLSL_VERSION_100_ES) 1162 { 1163 params["FRAG_HEADER"] = ""; 1164 params["VTX_HEADER"] = ""; 1165 params["VTX_IN"] = "attribute"; 1166 params["VTX_OUT"] = "varying"; 1167 params["FRAG_IN"] = "varying"; 1168 params["FRAG_COLOR"] = "gl_FragColor"; 1169 } 1170 else if (m_glslVersion == glu::GLSL_VERSION_300_ES || m_glslVersion == glu::GLSL_VERSION_310_ES || m_glslVersion == glu::GLSL_VERSION_330) 1171 { 1172 const string version = glu::getGLSLVersionDeclaration(m_glslVersion); 1173 const char* ext = DE_NULL; 1174 1175 if (isCubeArray && glu::glslVersionIsES(m_glslVersion)) 1176 ext = "GL_EXT_texture_cube_map_array"; 1177 else if (isBuffer && glu::glslVersionIsES(m_glslVersion)) 1178 ext = "GL_EXT_texture_buffer"; 1179 1180 params["FRAG_HEADER"] = version + (ext ? string("\n#extension ") + ext + " : require" : string()) + "\nlayout(location = 0) out mediump vec4 dEQP_FragColor;\n"; 1181 params["VTX_HEADER"] = version + "\n"; 1182 params["VTX_IN"] = "in"; 1183 params["VTX_OUT"] = "out"; 1184 params["FRAG_IN"] = "in"; 1185 params["FRAG_COLOR"] = "dEQP_FragColor"; 1186 } 1187 else 1188 DE_ASSERT(!"Unsupported version"); 1189 1190 params["PRECISION"] = glu::getPrecisionName(m_texCoordPrecision); 1191 1192 if (isCubeArray) 1193 params["TEXCOORD_TYPE"] = "vec4"; 1194 else if (isCube || (is2D && isArray) || is3D) 1195 params["TEXCOORD_TYPE"] = "vec3"; 1196 else if ((is1D && isArray) || is2D) 1197 params["TEXCOORD_TYPE"] = "vec2"; 1198 else if (is1D) 1199 params["TEXCOORD_TYPE"] = "float"; 1200 else 1201 DE_ASSERT(DE_FALSE); 1202 1203 const char* sampler = DE_NULL; 1204 const char* lookup = DE_NULL; 1205 1206 if (m_glslVersion == glu::GLSL_VERSION_300_ES || m_glslVersion == glu::GLSL_VERSION_310_ES || m_glslVersion == glu::GLSL_VERSION_330) 1207 { 1208 switch (program) 1209 { 1210 case PROGRAM_2D_FLOAT: sampler = "sampler2D"; lookup = "texture(u_sampler, v_texCoord)"; break; 1211 case PROGRAM_2D_INT: sampler = "isampler2D"; lookup = "vec4(texture(u_sampler, v_texCoord))"; break; 1212 case PROGRAM_2D_UINT: sampler = "usampler2D"; lookup = "vec4(texture(u_sampler, v_texCoord))"; break; 1213 case PROGRAM_2D_SHADOW: sampler = "sampler2DShadow"; lookup = "vec4(texture(u_sampler, vec3(v_texCoord, u_ref)), 0.0, 0.0, 1.0)"; break; 1214 case PROGRAM_2D_FLOAT_BIAS: sampler = "sampler2D"; lookup = "texture(u_sampler, v_texCoord, u_bias)"; break; 1215 case PROGRAM_2D_INT_BIAS: sampler = "isampler2D"; lookup = "vec4(texture(u_sampler, v_texCoord, u_bias))"; break; 1216 case PROGRAM_2D_UINT_BIAS: sampler = "usampler2D"; lookup = "vec4(texture(u_sampler, v_texCoord, u_bias))"; break; 1217 case PROGRAM_2D_SHADOW_BIAS: sampler = "sampler2DShadow"; lookup = "vec4(texture(u_sampler, vec3(v_texCoord, u_ref), u_bias), 0.0, 0.0, 1.0)"; break; 1218 case PROGRAM_1D_FLOAT: sampler = "sampler1D"; lookup = "texture(u_sampler, v_texCoord)"; break; 1219 case PROGRAM_1D_INT: sampler = "isampler1D"; lookup = "vec4(texture(u_sampler, v_texCoord))"; break; 1220 case PROGRAM_1D_UINT: sampler = "usampler1D"; lookup = "vec4(texture(u_sampler, v_texCoord))"; break; 1221 case PROGRAM_1D_SHADOW: sampler = "sampler1DShadow"; lookup = "vec4(texture(u_sampler, vec3(v_texCoord, u_ref)), 0.0, 0.0, 1.0)"; break; 1222 case PROGRAM_1D_FLOAT_BIAS: sampler = "sampler1D"; lookup = "texture(u_sampler, v_texCoord, u_bias)"; break; 1223 case PROGRAM_1D_INT_BIAS: sampler = "isampler1D"; lookup = "vec4(texture(u_sampler, v_texCoord, u_bias))"; break; 1224 case PROGRAM_1D_UINT_BIAS: sampler = "usampler1D"; lookup = "vec4(texture(u_sampler, v_texCoord, u_bias))"; break; 1225 case PROGRAM_1D_SHADOW_BIAS: sampler = "sampler1DShadow"; lookup = "vec4(texture(u_sampler, vec3(v_texCoord, u_ref), u_bias), 0.0, 0.0, 1.0)"; break; 1226 case PROGRAM_CUBE_FLOAT: sampler = "samplerCube"; lookup = "texture(u_sampler, v_texCoord)"; break; 1227 case PROGRAM_CUBE_INT: sampler = "isamplerCube"; lookup = "vec4(texture(u_sampler, v_texCoord))"; break; 1228 case PROGRAM_CUBE_UINT: sampler = "usamplerCube"; lookup = "vec4(texture(u_sampler, v_texCoord))"; break; 1229 case PROGRAM_CUBE_SHADOW: sampler = "samplerCubeShadow"; lookup = "vec4(texture(u_sampler, vec4(v_texCoord, u_ref)), 0.0, 0.0, 1.0)"; break; 1230 case PROGRAM_CUBE_FLOAT_BIAS: sampler = "samplerCube"; lookup = "texture(u_sampler, v_texCoord, u_bias)"; break; 1231 case PROGRAM_CUBE_INT_BIAS: sampler = "isamplerCube"; lookup = "vec4(texture(u_sampler, v_texCoord, u_bias))"; break; 1232 case PROGRAM_CUBE_UINT_BIAS: sampler = "usamplerCube"; lookup = "vec4(texture(u_sampler, v_texCoord, u_bias))"; break; 1233 case PROGRAM_CUBE_SHADOW_BIAS: sampler = "samplerCubeShadow"; lookup = "vec4(texture(u_sampler, vec4(v_texCoord, u_ref), u_bias), 0.0, 0.0, 1.0)"; break; 1234 case PROGRAM_2D_ARRAY_FLOAT: sampler = "sampler2DArray"; lookup = "texture(u_sampler, v_texCoord)"; break; 1235 case PROGRAM_2D_ARRAY_INT: sampler = "isampler2DArray"; lookup = "vec4(texture(u_sampler, v_texCoord))"; break; 1236 case PROGRAM_2D_ARRAY_UINT: sampler = "usampler2DArray"; lookup = "vec4(texture(u_sampler, v_texCoord))"; break; 1237 case PROGRAM_2D_ARRAY_SHADOW: sampler = "sampler2DArrayShadow"; lookup = "vec4(texture(u_sampler, vec4(v_texCoord, u_ref)), 0.0, 0.0, 1.0)"; break; 1238 case PROGRAM_3D_FLOAT: sampler = "sampler3D"; lookup = "texture(u_sampler, v_texCoord)"; break; 1239 case PROGRAM_3D_INT: sampler = "isampler3D"; lookup = "vec4(texture(u_sampler, v_texCoord))"; break; 1240 case PROGRAM_3D_UINT: sampler = "usampler3D"; lookup = "vec4(texture(u_sampler, v_texCoord))"; break; 1241 case PROGRAM_3D_FLOAT_BIAS: sampler = "sampler3D"; lookup = "texture(u_sampler, v_texCoord, u_bias)"; break; 1242 case PROGRAM_3D_INT_BIAS: sampler = "isampler3D"; lookup = "vec4(texture(u_sampler, v_texCoord, u_bias))"; break; 1243 case PROGRAM_3D_UINT_BIAS: sampler = "usampler3D"; lookup = "vec4(texture(u_sampler, v_texCoord, u_bias))"; break; 1244 case PROGRAM_CUBE_ARRAY_FLOAT: sampler = "samplerCubeArray"; lookup = "texture(u_sampler, v_texCoord)"; break; 1245 case PROGRAM_CUBE_ARRAY_INT: sampler = "isamplerCubeArray"; lookup = "vec4(texture(u_sampler, v_texCoord))"; break; 1246 case PROGRAM_CUBE_ARRAY_UINT: sampler = "usamplerCubeArray"; lookup = "vec4(texture(u_sampler, v_texCoord))"; break; 1247 case PROGRAM_CUBE_ARRAY_SHADOW: sampler = "samplerCubeArrayShadow"; lookup = "vec4(texture(u_sampler, vec4(v_texCoord, u_ref)), 0.0, 0.0, 1.0)"; break; 1248 case PROGRAM_1D_ARRAY_FLOAT: sampler = "sampler1DArray"; lookup = "texture(u_sampler, v_texCoord)"; break; 1249 case PROGRAM_1D_ARRAY_INT: sampler = "isampler1DArray"; lookup = "vec4(texture(u_sampler, v_texCoord))"; break; 1250 case PROGRAM_1D_ARRAY_UINT: sampler = "usampler1DArray"; lookup = "vec4(texture(u_sampler, v_texCoord))"; break; 1251 case PROGRAM_1D_ARRAY_SHADOW: sampler = "sampler1DArrayShadow"; lookup = "vec4(texture(u_sampler, vec4(v_texCoord, u_ref)), 0.0, 0.0, 1.0)"; break; 1252 case PROGRAM_BUFFER_FLOAT: sampler = "samplerBuffer"; lookup = "texelFetch(u_sampler, int(v_texCoord))"; break; 1253 case PROGRAM_BUFFER_INT: sampler = "isamplerBuffer"; lookup = "vec4(texelFetch(u_sampler, int(v_texCoord)))"; break; 1254 case PROGRAM_BUFFER_UINT: sampler = "usamplerBuffer"; lookup = "vec4(texelFetch(u_sampler, int(v_texCoord)))"; break; 1255 default: 1256 DE_ASSERT(false); 1257 } 1258 } 1259 else if (m_glslVersion == glu::GLSL_VERSION_100_ES) 1260 { 1261 sampler = isCube ? "samplerCube" : "sampler2D"; 1262 1263 switch (program) 1264 { 1265 case PROGRAM_2D_FLOAT: lookup = "texture2D(u_sampler, v_texCoord)"; break; 1266 case PROGRAM_2D_FLOAT_BIAS: lookup = "texture2D(u_sampler, v_texCoord, u_bias)"; break; 1267 case PROGRAM_CUBE_FLOAT: lookup = "textureCube(u_sampler, v_texCoord)"; break; 1268 case PROGRAM_CUBE_FLOAT_BIAS: lookup = "textureCube(u_sampler, v_texCoord, u_bias)"; break; 1269 default: 1270 DE_ASSERT(false); 1271 } 1272 } 1273 else 1274 DE_ASSERT(!"Unsupported version"); 1275 1276 params["SAMPLER_TYPE"] = sampler; 1277 params["LOOKUP"] = lookup; 1278 1279 std::string vertSrc = tcu::StringTemplate(vertShaderTemplate).specialize(params); 1280 std::string fragSrc = tcu::StringTemplate(fragShaderTemplate).specialize(params); 1281 1282 glu::ShaderProgram* progObj = new glu::ShaderProgram(m_context, glu::makeVtxFragSources(vertSrc, fragSrc)); 1283 if (!progObj->isOk()) 1284 { 1285 m_log << *progObj; 1286 delete progObj; 1287 TCU_FAIL("Failed to compile shader program"); 1288 } 1289 1290 try 1291 { 1292 m_programs[program] = progObj; 1293 } 1294 catch (...) 1295 { 1296 delete progObj; 1297 throw; 1298 } 1299 1300 return progObj; 1301} 1302 1303TextureRenderer::TextureRenderer (const glu::RenderContext& context, tcu::TestLog& log, glu::GLSLVersion glslVersion, glu::Precision texCoordPrecision) 1304 : m_renderCtx (context) 1305 , m_log (log) 1306 , m_programLibrary (context, log, glslVersion, texCoordPrecision) 1307{ 1308} 1309 1310TextureRenderer::~TextureRenderer (void) 1311{ 1312 clear(); 1313} 1314 1315void TextureRenderer::clear (void) 1316{ 1317 m_programLibrary.clear(); 1318} 1319 1320void TextureRenderer::renderQuad (int texUnit, const float* texCoord, TextureType texType) 1321{ 1322 renderQuad(texUnit, texCoord, RenderParams(texType)); 1323} 1324 1325void TextureRenderer::renderQuad (int texUnit, const float* texCoord, const RenderParams& params) 1326{ 1327 const glw::Functions& gl = m_renderCtx.getFunctions(); 1328 tcu::Vec4 wCoord = params.flags & RenderParams::PROJECTED ? params.w : tcu::Vec4(1.0f); 1329 bool useBias = !!(params.flags & RenderParams::USE_BIAS); 1330 bool logUniforms = !!(params.flags & RenderParams::LOG_UNIFORMS); 1331 1332 // Render quad with texture. 1333 float position[] = 1334 { 1335 -1.0f*wCoord.x(), -1.0f*wCoord.x(), 0.0f, wCoord.x(), 1336 -1.0f*wCoord.y(), +1.0f*wCoord.y(), 0.0f, wCoord.y(), 1337 +1.0f*wCoord.z(), -1.0f*wCoord.z(), 0.0f, wCoord.z(), 1338 +1.0f*wCoord.w(), +1.0f*wCoord.w(), 0.0f, wCoord.w() 1339 }; 1340 static const deUint16 indices[] = { 0, 1, 2, 2, 1, 3 }; 1341 1342 Program progSpec = PROGRAM_LAST; 1343 int numComps = 0; 1344 if (params.texType == TEXTURETYPE_2D) 1345 { 1346 numComps = 2; 1347 1348 switch (params.samplerType) 1349 { 1350 case SAMPLERTYPE_FLOAT: progSpec = useBias ? PROGRAM_2D_FLOAT_BIAS : PROGRAM_2D_FLOAT; break; 1351 case SAMPLERTYPE_INT: progSpec = useBias ? PROGRAM_2D_INT_BIAS : PROGRAM_2D_INT; break; 1352 case SAMPLERTYPE_UINT: progSpec = useBias ? PROGRAM_2D_UINT_BIAS : PROGRAM_2D_UINT; break; 1353 case SAMPLERTYPE_SHADOW: progSpec = useBias ? PROGRAM_2D_SHADOW_BIAS : PROGRAM_2D_SHADOW; break; 1354 default: DE_ASSERT(false); 1355 } 1356 } 1357 else if (params.texType == TEXTURETYPE_1D) 1358 { 1359 numComps = 1; 1360 1361 switch (params.samplerType) 1362 { 1363 case SAMPLERTYPE_FLOAT: progSpec = useBias ? PROGRAM_1D_FLOAT_BIAS : PROGRAM_1D_FLOAT; break; 1364 case SAMPLERTYPE_INT: progSpec = useBias ? PROGRAM_1D_INT_BIAS : PROGRAM_1D_INT; break; 1365 case SAMPLERTYPE_UINT: progSpec = useBias ? PROGRAM_1D_UINT_BIAS : PROGRAM_1D_UINT; break; 1366 case SAMPLERTYPE_SHADOW: progSpec = useBias ? PROGRAM_1D_SHADOW_BIAS : PROGRAM_1D_SHADOW; break; 1367 default: DE_ASSERT(false); 1368 } 1369 } 1370 else if (params.texType == TEXTURETYPE_CUBE) 1371 { 1372 numComps = 3; 1373 1374 switch (params.samplerType) 1375 { 1376 case SAMPLERTYPE_FLOAT: progSpec = useBias ? PROGRAM_CUBE_FLOAT_BIAS : PROGRAM_CUBE_FLOAT; break; 1377 case SAMPLERTYPE_INT: progSpec = useBias ? PROGRAM_CUBE_INT_BIAS : PROGRAM_CUBE_INT; break; 1378 case SAMPLERTYPE_UINT: progSpec = useBias ? PROGRAM_CUBE_UINT_BIAS : PROGRAM_CUBE_UINT; break; 1379 case SAMPLERTYPE_SHADOW: progSpec = useBias ? PROGRAM_CUBE_SHADOW_BIAS : PROGRAM_CUBE_SHADOW; break; 1380 default: DE_ASSERT(false); 1381 } 1382 } 1383 else if (params.texType == TEXTURETYPE_3D) 1384 { 1385 numComps = 3; 1386 1387 switch (params.samplerType) 1388 { 1389 case SAMPLERTYPE_FLOAT: progSpec = useBias ? PROGRAM_3D_FLOAT_BIAS : PROGRAM_3D_FLOAT; break; 1390 case SAMPLERTYPE_INT: progSpec = useBias ? PROGRAM_3D_INT_BIAS : PROGRAM_3D_INT; break; 1391 case SAMPLERTYPE_UINT: progSpec = useBias ? PROGRAM_3D_UINT_BIAS : PROGRAM_3D_UINT; break; 1392 default: DE_ASSERT(false); 1393 } 1394 } 1395 else if (params.texType == TEXTURETYPE_2D_ARRAY) 1396 { 1397 DE_ASSERT(!useBias); // \todo [2012-02-17 pyry] Support bias. 1398 1399 numComps = 3; 1400 1401 switch (params.samplerType) 1402 { 1403 case SAMPLERTYPE_FLOAT: progSpec = PROGRAM_2D_ARRAY_FLOAT; break; 1404 case SAMPLERTYPE_INT: progSpec = PROGRAM_2D_ARRAY_INT; break; 1405 case SAMPLERTYPE_UINT: progSpec = PROGRAM_2D_ARRAY_UINT; break; 1406 case SAMPLERTYPE_SHADOW: progSpec = PROGRAM_2D_ARRAY_SHADOW; break; 1407 default: DE_ASSERT(false); 1408 } 1409 } 1410 else if (params.texType == TEXTURETYPE_CUBE_ARRAY) 1411 { 1412 DE_ASSERT(!useBias); 1413 1414 numComps = 4; 1415 1416 switch (params.samplerType) 1417 { 1418 case SAMPLERTYPE_FLOAT: progSpec = PROGRAM_CUBE_ARRAY_FLOAT; break; 1419 case SAMPLERTYPE_INT: progSpec = PROGRAM_CUBE_ARRAY_INT; break; 1420 case SAMPLERTYPE_UINT: progSpec = PROGRAM_CUBE_ARRAY_UINT; break; 1421 case SAMPLERTYPE_SHADOW: progSpec = PROGRAM_CUBE_ARRAY_SHADOW; break; 1422 default: DE_ASSERT(false); 1423 } 1424 } 1425 else if (params.texType == TEXTURETYPE_1D_ARRAY) 1426 { 1427 DE_ASSERT(!useBias); // \todo [2012-02-17 pyry] Support bias. 1428 1429 numComps = 2; 1430 1431 switch (params.samplerType) 1432 { 1433 case SAMPLERTYPE_FLOAT: progSpec = PROGRAM_1D_ARRAY_FLOAT; break; 1434 case SAMPLERTYPE_INT: progSpec = PROGRAM_1D_ARRAY_INT; break; 1435 case SAMPLERTYPE_UINT: progSpec = PROGRAM_1D_ARRAY_UINT; break; 1436 case SAMPLERTYPE_SHADOW: progSpec = PROGRAM_1D_ARRAY_SHADOW; break; 1437 default: DE_ASSERT(false); 1438 } 1439 } 1440 else if (params.texType == TEXTURETYPE_BUFFER) 1441 { 1442 numComps = 1; 1443 1444 switch (params.samplerType) 1445 { 1446 case SAMPLERTYPE_FETCH_FLOAT: progSpec = PROGRAM_BUFFER_FLOAT; break; 1447 case SAMPLERTYPE_FETCH_INT: progSpec = PROGRAM_BUFFER_INT; break; 1448 case SAMPLERTYPE_FETCH_UINT: progSpec = PROGRAM_BUFFER_UINT; break; 1449 default: DE_ASSERT(false); 1450 } 1451 } 1452 else 1453 DE_ASSERT(DE_FALSE); 1454 1455 glu::ShaderProgram* program = m_programLibrary.getProgram(progSpec); 1456 1457 // \todo [2012-09-26 pyry] Move to ProgramLibrary and log unique programs only(?) 1458 if (params.flags & RenderParams::LOG_PROGRAMS) 1459 m_log << *program; 1460 1461 GLU_EXPECT_NO_ERROR(gl.getError(), "Set vertex attributes"); 1462 1463 // Program and uniforms. 1464 deUint32 prog = program->getProgram(); 1465 gl.useProgram(prog); 1466 1467 gl.uniform1i(gl.getUniformLocation(prog, "u_sampler"), texUnit); 1468 if (logUniforms) 1469 m_log << TestLog::Message << "u_sampler = " << texUnit << TestLog::EndMessage; 1470 1471 if (useBias) 1472 { 1473 gl.uniform1f(gl.getUniformLocation(prog, "u_bias"), params.bias); 1474 if (logUniforms) 1475 m_log << TestLog::Message << "u_bias = " << params.bias << TestLog::EndMessage; 1476 } 1477 1478 if (params.samplerType == SAMPLERTYPE_SHADOW) 1479 { 1480 gl.uniform1f(gl.getUniformLocation(prog, "u_ref"), params.ref); 1481 if (logUniforms) 1482 m_log << TestLog::Message << "u_ref = " << params.ref << TestLog::EndMessage; 1483 } 1484 1485 gl.uniform4fv(gl.getUniformLocation(prog, "u_colorScale"), 1, params.colorScale.getPtr()); 1486 gl.uniform4fv(gl.getUniformLocation(prog, "u_colorBias"), 1, params.colorBias.getPtr()); 1487 1488 if (logUniforms) 1489 { 1490 m_log << TestLog::Message << "u_colorScale = " << params.colorScale << TestLog::EndMessage; 1491 m_log << TestLog::Message << "u_colorBias = " << params.colorBias << TestLog::EndMessage; 1492 } 1493 1494 GLU_EXPECT_NO_ERROR(gl.getError(), "Set program state"); 1495 1496 { 1497 const glu::VertexArrayBinding vertexArrays[] = 1498 { 1499 glu::va::Float("a_position", 4, 4, 0, &position[0]), 1500 glu::va::Float("a_texCoord", numComps, 4, 0, texCoord) 1501 }; 1502 glu::draw(m_renderCtx, prog, DE_LENGTH_OF_ARRAY(vertexArrays), &vertexArrays[0], 1503 glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indices), &indices[0])); 1504 } 1505} 1506 1507void computeQuadTexCoord1D (std::vector<float>& dst, float left, float right) 1508{ 1509 dst.resize(4); 1510 1511 dst[0] = left; 1512 dst[1] = left; 1513 dst[2] = right; 1514 dst[3] = right; 1515} 1516 1517void computeQuadTexCoord1DArray (std::vector<float>& dst, int layerNdx, float left, float right) 1518{ 1519 dst.resize(4*2); 1520 1521 dst[0] = left; dst[1] = (float)layerNdx; 1522 dst[2] = left; dst[3] = (float)layerNdx; 1523 dst[4] = right; dst[5] = (float)layerNdx; 1524 dst[6] = right; dst[7] = (float)layerNdx; 1525} 1526 1527void computeQuadTexCoord2D (std::vector<float>& dst, const tcu::Vec2& bottomLeft, const tcu::Vec2& topRight) 1528{ 1529 dst.resize(4*2); 1530 1531 dst[0] = bottomLeft.x(); dst[1] = bottomLeft.y(); 1532 dst[2] = bottomLeft.x(); dst[3] = topRight.y(); 1533 dst[4] = topRight.x(); dst[5] = bottomLeft.y(); 1534 dst[6] = topRight.x(); dst[7] = topRight.y(); 1535} 1536 1537void computeQuadTexCoord2DArray (std::vector<float>& dst, int layerNdx, const tcu::Vec2& bottomLeft, const tcu::Vec2& topRight) 1538{ 1539 dst.resize(4*3); 1540 1541 dst[0] = bottomLeft.x(); dst[ 1] = bottomLeft.y(); dst[ 2] = (float)layerNdx; 1542 dst[3] = bottomLeft.x(); dst[ 4] = topRight.y(); dst[ 5] = (float)layerNdx; 1543 dst[6] = topRight.x(); dst[ 7] = bottomLeft.y(); dst[ 8] = (float)layerNdx; 1544 dst[9] = topRight.x(); dst[10] = topRight.y(); dst[11] = (float)layerNdx; 1545} 1546 1547void computeQuadTexCoord3D (std::vector<float>& dst, const tcu::Vec3& p0, const tcu::Vec3& p1, const tcu::IVec3& dirSwz) 1548{ 1549 tcu::Vec3 f0 = tcu::Vec3(0.0f, 0.0f, 0.0f).swizzle(dirSwz[0], dirSwz[1], dirSwz[2]); 1550 tcu::Vec3 f1 = tcu::Vec3(0.0f, 1.0f, 0.0f).swizzle(dirSwz[0], dirSwz[1], dirSwz[2]); 1551 tcu::Vec3 f2 = tcu::Vec3(1.0f, 0.0f, 0.0f).swizzle(dirSwz[0], dirSwz[1], dirSwz[2]); 1552 tcu::Vec3 f3 = tcu::Vec3(1.0f, 1.0f, 0.0f).swizzle(dirSwz[0], dirSwz[1], dirSwz[2]); 1553 1554 tcu::Vec3 v0 = p0 + (p1-p0)*f0; 1555 tcu::Vec3 v1 = p0 + (p1-p0)*f1; 1556 tcu::Vec3 v2 = p0 + (p1-p0)*f2; 1557 tcu::Vec3 v3 = p0 + (p1-p0)*f3; 1558 1559 dst.resize(4*3); 1560 1561 dst[0] = v0.x(); dst[ 1] = v0.y(); dst[ 2] = v0.z(); 1562 dst[3] = v1.x(); dst[ 4] = v1.y(); dst[ 5] = v1.z(); 1563 dst[6] = v2.x(); dst[ 7] = v2.y(); dst[ 8] = v2.z(); 1564 dst[9] = v3.x(); dst[10] = v3.y(); dst[11] = v3.z(); 1565} 1566 1567void computeQuadTexCoordCube (std::vector<float>& dst, tcu::CubeFace face) 1568{ 1569 static const float texCoordNegX[] = 1570 { 1571 -1.0f, 1.0f, -1.0f, 1572 -1.0f, -1.0f, -1.0f, 1573 -1.0f, 1.0f, 1.0f, 1574 -1.0f, -1.0f, 1.0f 1575 }; 1576 static const float texCoordPosX[] = 1577 { 1578 +1.0f, 1.0f, 1.0f, 1579 +1.0f, -1.0f, 1.0f, 1580 +1.0f, 1.0f, -1.0f, 1581 +1.0f, -1.0f, -1.0f 1582 }; 1583 static const float texCoordNegY[] = 1584 { 1585 -1.0f, -1.0f, 1.0f, 1586 -1.0f, -1.0f, -1.0f, 1587 1.0f, -1.0f, 1.0f, 1588 1.0f, -1.0f, -1.0f 1589 }; 1590 static const float texCoordPosY[] = 1591 { 1592 -1.0f, +1.0f, -1.0f, 1593 -1.0f, +1.0f, 1.0f, 1594 1.0f, +1.0f, -1.0f, 1595 1.0f, +1.0f, 1.0f 1596 }; 1597 static const float texCoordNegZ[] = 1598 { 1599 1.0f, 1.0f, -1.0f, 1600 1.0f, -1.0f, -1.0f, 1601 -1.0f, 1.0f, -1.0f, 1602 -1.0f, -1.0f, -1.0f 1603 }; 1604 static const float texCoordPosZ[] = 1605 { 1606 -1.0f, 1.0f, +1.0f, 1607 -1.0f, -1.0f, +1.0f, 1608 1.0f, 1.0f, +1.0f, 1609 1.0f, -1.0f, +1.0f 1610 }; 1611 1612 const float* texCoord = DE_NULL; 1613 int texCoordSize = DE_LENGTH_OF_ARRAY(texCoordNegX); 1614 1615 switch (face) 1616 { 1617 case tcu::CUBEFACE_NEGATIVE_X: texCoord = texCoordNegX; break; 1618 case tcu::CUBEFACE_POSITIVE_X: texCoord = texCoordPosX; break; 1619 case tcu::CUBEFACE_NEGATIVE_Y: texCoord = texCoordNegY; break; 1620 case tcu::CUBEFACE_POSITIVE_Y: texCoord = texCoordPosY; break; 1621 case tcu::CUBEFACE_NEGATIVE_Z: texCoord = texCoordNegZ; break; 1622 case tcu::CUBEFACE_POSITIVE_Z: texCoord = texCoordPosZ; break; 1623 default: 1624 DE_ASSERT(DE_FALSE); 1625 return; 1626 } 1627 1628 dst.resize(texCoordSize); 1629 std::copy(texCoord, texCoord+texCoordSize, dst.begin()); 1630} 1631 1632void computeQuadTexCoordCube (std::vector<float>& dst, tcu::CubeFace face, const tcu::Vec2& bottomLeft, const tcu::Vec2& topRight) 1633{ 1634 int sRow = 0; 1635 int tRow = 0; 1636 int mRow = 0; 1637 float sSign = 1.0f; 1638 float tSign = 1.0f; 1639 float mSign = 1.0f; 1640 1641 switch (face) 1642 { 1643 case tcu::CUBEFACE_NEGATIVE_X: mRow = 0; sRow = 2; tRow = 1; mSign = -1.0f; tSign = -1.0f; break; 1644 case tcu::CUBEFACE_POSITIVE_X: mRow = 0; sRow = 2; tRow = 1; sSign = -1.0f; tSign = -1.0f; break; 1645 case tcu::CUBEFACE_NEGATIVE_Y: mRow = 1; sRow = 0; tRow = 2; mSign = -1.0f; tSign = -1.0f; break; 1646 case tcu::CUBEFACE_POSITIVE_Y: mRow = 1; sRow = 0; tRow = 2; break; 1647 case tcu::CUBEFACE_NEGATIVE_Z: mRow = 2; sRow = 0; tRow = 1; mSign = -1.0f; sSign = -1.0f; tSign = -1.0f; break; 1648 case tcu::CUBEFACE_POSITIVE_Z: mRow = 2; sRow = 0; tRow = 1; tSign = -1.0f; break; 1649 default: 1650 DE_ASSERT(DE_FALSE); 1651 return; 1652 } 1653 1654 dst.resize(3*4); 1655 1656 dst[0+mRow] = mSign; 1657 dst[3+mRow] = mSign; 1658 dst[6+mRow] = mSign; 1659 dst[9+mRow] = mSign; 1660 1661 dst[0+sRow] = sSign * bottomLeft.x(); 1662 dst[3+sRow] = sSign * bottomLeft.x(); 1663 dst[6+sRow] = sSign * topRight.x(); 1664 dst[9+sRow] = sSign * topRight.x(); 1665 1666 dst[0+tRow] = tSign * bottomLeft.y(); 1667 dst[3+tRow] = tSign * topRight.y(); 1668 dst[6+tRow] = tSign * bottomLeft.y(); 1669 dst[9+tRow] = tSign * topRight.y(); 1670} 1671 1672void computeQuadTexCoordCubeArray (std::vector<float>& dst, tcu::CubeFace face, const tcu::Vec2& bottomLeft, const tcu::Vec2& topRight, const tcu::Vec2& layerRange) 1673{ 1674 int sRow = 0; 1675 int tRow = 0; 1676 int mRow = 0; 1677 const int qRow = 3; 1678 float sSign = 1.0f; 1679 float tSign = 1.0f; 1680 float mSign = 1.0f; 1681 const float l0 = layerRange.x(); 1682 const float l1 = layerRange.y(); 1683 1684 switch (face) 1685 { 1686 case tcu::CUBEFACE_NEGATIVE_X: mRow = 0; sRow = 2; tRow = 1; mSign = -1.0f; tSign = -1.0f; break; 1687 case tcu::CUBEFACE_POSITIVE_X: mRow = 0; sRow = 2; tRow = 1; sSign = -1.0f; tSign = -1.0f; break; 1688 case tcu::CUBEFACE_NEGATIVE_Y: mRow = 1; sRow = 0; tRow = 2; mSign = -1.0f; tSign = -1.0f; break; 1689 case tcu::CUBEFACE_POSITIVE_Y: mRow = 1; sRow = 0; tRow = 2; break; 1690 case tcu::CUBEFACE_NEGATIVE_Z: mRow = 2; sRow = 0; tRow = 1; mSign = -1.0f; sSign = -1.0f; tSign = -1.0f; break; 1691 case tcu::CUBEFACE_POSITIVE_Z: mRow = 2; sRow = 0; tRow = 1; tSign = -1.0f; break; 1692 default: 1693 DE_ASSERT(DE_FALSE); 1694 return; 1695 } 1696 1697 dst.resize(4*4); 1698 1699 dst[ 0+mRow] = mSign; 1700 dst[ 4+mRow] = mSign; 1701 dst[ 8+mRow] = mSign; 1702 dst[12+mRow] = mSign; 1703 1704 dst[ 0+sRow] = sSign * bottomLeft.x(); 1705 dst[ 4+sRow] = sSign * bottomLeft.x(); 1706 dst[ 8+sRow] = sSign * topRight.x(); 1707 dst[12+sRow] = sSign * topRight.x(); 1708 1709 dst[ 0+tRow] = tSign * bottomLeft.y(); 1710 dst[ 4+tRow] = tSign * topRight.y(); 1711 dst[ 8+tRow] = tSign * bottomLeft.y(); 1712 dst[12+tRow] = tSign * topRight.y(); 1713 1714 if (l0 != l1) 1715 { 1716 dst[ 0+qRow] = l0; 1717 dst[ 4+qRow] = l0*0.5f + l1*0.5f; 1718 dst[ 8+qRow] = l0*0.5f + l1*0.5f; 1719 dst[12+qRow] = l1; 1720 } 1721 else 1722 { 1723 dst[ 0+qRow] = l0; 1724 dst[ 4+qRow] = l0; 1725 dst[ 8+qRow] = l0; 1726 dst[12+qRow] = l0; 1727 } 1728} 1729 1730// Texture result verification 1731 1732//! Verifies texture lookup results and returns number of failed pixels. 1733int computeTextureLookupDiff (const tcu::ConstPixelBufferAccess& result, 1734 const tcu::ConstPixelBufferAccess& reference, 1735 const tcu::PixelBufferAccess& errorMask, 1736 const tcu::Texture1DView& baseView, 1737 const float* texCoord, 1738 const ReferenceParams& sampleParams, 1739 const tcu::LookupPrecision& lookupPrec, 1740 const tcu::LodPrecision& lodPrec, 1741 qpWatchDog* watchDog) 1742{ 1743 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight()); 1744 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight()); 1745 1746 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage; 1747 const tcu::Texture1DView src = getEffectiveView(getSubView(baseView, sampleParams.baseLevel, sampleParams.maxLevel), srcLevelStorage, sampleParams.sampler); 1748 1749 const tcu::Vec4 sq = tcu::Vec4(texCoord[0], texCoord[1], texCoord[2], texCoord[3]); 1750 1751 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight()); 1752 const float dstW = float(dstSize.x()); 1753 const float dstH = float(dstSize.y()); 1754 const int srcSize = src.getWidth(); 1755 1756 // Coordinates and lod per triangle. 1757 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) }; 1758 const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) }; 1759 1760 const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f); 1761 1762 int numFailed = 0; 1763 1764 const tcu::Vec2 lodOffsets[] = 1765 { 1766 tcu::Vec2(-1, 0), 1767 tcu::Vec2(+1, 0), 1768 tcu::Vec2( 0, -1), 1769 tcu::Vec2( 0, +1), 1770 }; 1771 1772 tcu::clear(errorMask, tcu::RGBA::green.toVec()); 1773 1774 for (int py = 0; py < result.getHeight(); py++) 1775 { 1776 // Ugly hack, validation can take way too long at the moment. 1777 if (watchDog) 1778 qpWatchDog_touch(watchDog); 1779 1780 for (int px = 0; px < result.getWidth(); px++) 1781 { 1782 const tcu::Vec4 resPix = (result.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale; 1783 const tcu::Vec4 refPix = (reference.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale; 1784 1785 // Try comparison to ideal reference first, and if that fails use slower verificator. 1786 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold))) 1787 { 1788 const float wx = (float)px + 0.5f; 1789 const float wy = (float)py + 0.5f; 1790 const float nx = wx / dstW; 1791 const float ny = wy / dstH; 1792 1793 const int triNdx = nx + ny >= 1.0f ? 1 : 0; 1794 const float triWx = triNdx ? dstW - wx : wx; 1795 const float triWy = triNdx ? dstH - wy : wy; 1796 const float triNx = triNdx ? 1.0f - nx : nx; 1797 const float triNy = triNdx ? 1.0f - ny : ny; 1798 1799 const float coord = projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy); 1800 const float coordDx = triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy) * float(srcSize); 1801 const float coordDy = triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx) * float(srcSize); 1802 1803 tcu::Vec2 lodBounds = tcu::computeLodBoundsFromDerivates(coordDx, coordDy, lodPrec); 1804 1805 // Compute lod bounds across lodOffsets range. 1806 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++) 1807 { 1808 const float wxo = triWx + lodOffsets[lodOffsNdx].x(); 1809 const float wyo = triWy + lodOffsets[lodOffsNdx].y(); 1810 const float nxo = wxo/dstW; 1811 const float nyo = wyo/dstH; 1812 1813 const float coordDxo = triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo) * float(srcSize); 1814 const float coordDyo = triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo) * float(srcSize); 1815 const tcu::Vec2 lodO = tcu::computeLodBoundsFromDerivates(coordDxo, coordDyo, lodPrec); 1816 1817 lodBounds.x() = de::min(lodBounds.x(), lodO.x()); 1818 lodBounds.y() = de::max(lodBounds.y(), lodO.y()); 1819 } 1820 1821 const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec); 1822 const bool isOk = tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix); 1823 1824 if (!isOk) 1825 { 1826 errorMask.setPixel(tcu::RGBA::red.toVec(), px, py); 1827 numFailed += 1; 1828 } 1829 } 1830 } 1831 } 1832 1833 return numFailed; 1834} 1835 1836int computeTextureLookupDiff (const tcu::ConstPixelBufferAccess& result, 1837 const tcu::ConstPixelBufferAccess& reference, 1838 const tcu::PixelBufferAccess& errorMask, 1839 const tcu::Texture2DView& baseView, 1840 const float* texCoord, 1841 const ReferenceParams& sampleParams, 1842 const tcu::LookupPrecision& lookupPrec, 1843 const tcu::LodPrecision& lodPrec, 1844 qpWatchDog* watchDog) 1845{ 1846 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight()); 1847 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight()); 1848 1849 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage; 1850 const tcu::Texture2DView src = getEffectiveView(getSubView(baseView, sampleParams.baseLevel, sampleParams.maxLevel), srcLevelStorage, sampleParams.sampler); 1851 1852 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[2+0], texCoord[4+0], texCoord[6+0]); 1853 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[2+1], texCoord[4+1], texCoord[6+1]); 1854 1855 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight()); 1856 const float dstW = float(dstSize.x()); 1857 const float dstH = float(dstSize.y()); 1858 const tcu::IVec2 srcSize = tcu::IVec2(src.getWidth(), src.getHeight()); 1859 1860 // Coordinates and lod per triangle. 1861 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) }; 1862 const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) }; 1863 const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) }; 1864 1865 const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f); 1866 1867 int numFailed = 0; 1868 1869 const tcu::Vec2 lodOffsets[] = 1870 { 1871 tcu::Vec2(-1, 0), 1872 tcu::Vec2(+1, 0), 1873 tcu::Vec2( 0, -1), 1874 tcu::Vec2( 0, +1), 1875 }; 1876 1877 tcu::clear(errorMask, tcu::RGBA::green.toVec()); 1878 1879 for (int py = 0; py < result.getHeight(); py++) 1880 { 1881 // Ugly hack, validation can take way too long at the moment. 1882 if (watchDog) 1883 qpWatchDog_touch(watchDog); 1884 1885 for (int px = 0; px < result.getWidth(); px++) 1886 { 1887 const tcu::Vec4 resPix = (result.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale; 1888 const tcu::Vec4 refPix = (reference.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale; 1889 1890 // Try comparison to ideal reference first, and if that fails use slower verificator. 1891 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold))) 1892 { 1893 const float wx = (float)px + 0.5f; 1894 const float wy = (float)py + 0.5f; 1895 const float nx = wx / dstW; 1896 const float ny = wy / dstH; 1897 1898 const int triNdx = nx + ny >= 1.0f ? 1 : 0; 1899 const float triWx = triNdx ? dstW - wx : wx; 1900 const float triWy = triNdx ? dstH - wy : wy; 1901 const float triNx = triNdx ? 1.0f - nx : nx; 1902 const float triNy = triNdx ? 1.0f - ny : ny; 1903 1904 const tcu::Vec2 coord (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy), 1905 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy)); 1906 const tcu::Vec2 coordDx = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy), 1907 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy)) * srcSize.asFloat(); 1908 const tcu::Vec2 coordDy = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx), 1909 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx)) * srcSize.asFloat(); 1910 1911 tcu::Vec2 lodBounds = tcu::computeLodBoundsFromDerivates(coordDx.x(), coordDx.y(), coordDy.x(), coordDy.y(), lodPrec); 1912 1913 // Compute lod bounds across lodOffsets range. 1914 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++) 1915 { 1916 const float wxo = triWx + lodOffsets[lodOffsNdx].x(); 1917 const float wyo = triWy + lodOffsets[lodOffsNdx].y(); 1918 const float nxo = wxo/dstW; 1919 const float nyo = wyo/dstH; 1920 1921 const tcu::Vec2 coordDxo = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo), 1922 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo)) * srcSize.asFloat(); 1923 const tcu::Vec2 coordDyo = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo), 1924 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo)) * srcSize.asFloat(); 1925 const tcu::Vec2 lodO = tcu::computeLodBoundsFromDerivates(coordDxo.x(), coordDxo.y(), coordDyo.x(), coordDyo.y(), lodPrec); 1926 1927 lodBounds.x() = de::min(lodBounds.x(), lodO.x()); 1928 lodBounds.y() = de::max(lodBounds.y(), lodO.y()); 1929 } 1930 1931 const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec); 1932 const bool isOk = tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix); 1933 1934 if (!isOk) 1935 { 1936 errorMask.setPixel(tcu::RGBA::red.toVec(), px, py); 1937 numFailed += 1; 1938 } 1939 } 1940 } 1941 } 1942 1943 return numFailed; 1944} 1945 1946bool verifyTextureResult (tcu::TestContext& testCtx, 1947 const tcu::ConstPixelBufferAccess& result, 1948 const tcu::Texture1DView& src, 1949 const float* texCoord, 1950 const ReferenceParams& sampleParams, 1951 const tcu::LookupPrecision& lookupPrec, 1952 const tcu::LodPrecision& lodPrec, 1953 const tcu::PixelFormat& pixelFormat) 1954{ 1955 tcu::TestLog& log = testCtx.getLog(); 1956 tcu::Surface reference (result.getWidth(), result.getHeight()); 1957 tcu::Surface errorMask (result.getWidth(), result.getHeight()); 1958 int numFailedPixels; 1959 1960 DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask); 1961 1962 sampleTexture(SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams); 1963 numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog()); 1964 1965 if (numFailedPixels > 0) 1966 log << TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage; 1967 1968 log << TestLog::ImageSet("VerifyResult", "Verification result") 1969 << TestLog::Image("Rendered", "Rendered image", result); 1970 1971 if (numFailedPixels > 0) 1972 { 1973 log << TestLog::Image("Reference", "Ideal reference image", reference) 1974 << TestLog::Image("ErrorMask", "Error mask", errorMask); 1975 } 1976 1977 log << TestLog::EndImageSet; 1978 1979 return numFailedPixels == 0; 1980} 1981 1982bool verifyTextureResult (tcu::TestContext& testCtx, 1983 const tcu::ConstPixelBufferAccess& result, 1984 const tcu::Texture2DView& src, 1985 const float* texCoord, 1986 const ReferenceParams& sampleParams, 1987 const tcu::LookupPrecision& lookupPrec, 1988 const tcu::LodPrecision& lodPrec, 1989 const tcu::PixelFormat& pixelFormat) 1990{ 1991 tcu::TestLog& log = testCtx.getLog(); 1992 tcu::Surface reference (result.getWidth(), result.getHeight()); 1993 tcu::Surface errorMask (result.getWidth(), result.getHeight()); 1994 int numFailedPixels; 1995 1996 DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask); 1997 1998 sampleTexture(SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams); 1999 numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog()); 2000 2001 if (numFailedPixels > 0) 2002 log << TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage; 2003 2004 log << TestLog::ImageSet("VerifyResult", "Verification result") 2005 << TestLog::Image("Rendered", "Rendered image", result); 2006 2007 if (numFailedPixels > 0) 2008 { 2009 log << TestLog::Image("Reference", "Ideal reference image", reference) 2010 << TestLog::Image("ErrorMask", "Error mask", errorMask); 2011 } 2012 2013 log << TestLog::EndImageSet; 2014 2015 return numFailedPixels == 0; 2016} 2017 2018//! Verifies texture lookup results and returns number of failed pixels. 2019int computeTextureLookupDiff (const tcu::ConstPixelBufferAccess& result, 2020 const tcu::ConstPixelBufferAccess& reference, 2021 const tcu::PixelBufferAccess& errorMask, 2022 const tcu::TextureCubeView& baseView, 2023 const float* texCoord, 2024 const ReferenceParams& sampleParams, 2025 const tcu::LookupPrecision& lookupPrec, 2026 const tcu::LodPrecision& lodPrec, 2027 qpWatchDog* watchDog) 2028{ 2029 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight()); 2030 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight()); 2031 2032 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage; 2033 const tcu::TextureCubeView src = getEffectiveView(getSubView(baseView, sampleParams.baseLevel, sampleParams.maxLevel), srcLevelStorage, sampleParams.sampler); 2034 2035 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]); 2036 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]); 2037 const tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]); 2038 2039 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight()); 2040 const float dstW = float(dstSize.x()); 2041 const float dstH = float(dstSize.y()); 2042 const int srcSize = src.getSize(); 2043 2044 // Coordinates per triangle. 2045 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) }; 2046 const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) }; 2047 const tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) }; 2048 const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) }; 2049 2050 const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f); 2051 2052 const float posEps = 1.0f / float(1<<MIN_SUBPIXEL_BITS); 2053 2054 int numFailed = 0; 2055 2056 const tcu::Vec2 lodOffsets[] = 2057 { 2058 tcu::Vec2(-1, 0), 2059 tcu::Vec2(+1, 0), 2060 tcu::Vec2( 0, -1), 2061 tcu::Vec2( 0, +1), 2062 2063 // \note Not strictly allowed by spec, but implementations do this in practice. 2064 tcu::Vec2(-1, -1), 2065 tcu::Vec2(-1, +1), 2066 tcu::Vec2(+1, -1), 2067 tcu::Vec2(+1, +1), 2068 }; 2069 2070 tcu::clear(errorMask, tcu::RGBA::green.toVec()); 2071 2072 for (int py = 0; py < result.getHeight(); py++) 2073 { 2074 // Ugly hack, validation can take way too long at the moment. 2075 if (watchDog) 2076 qpWatchDog_touch(watchDog); 2077 2078 for (int px = 0; px < result.getWidth(); px++) 2079 { 2080 const tcu::Vec4 resPix = (result.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale; 2081 const tcu::Vec4 refPix = (reference.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale; 2082 2083 // Try comparison to ideal reference first, and if that fails use slower verificator. 2084 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold))) 2085 { 2086 const float wx = (float)px + 0.5f; 2087 const float wy = (float)py + 0.5f; 2088 const float nx = wx / dstW; 2089 const float ny = wy / dstH; 2090 2091 const bool tri0 = (wx-posEps)/dstW + (wy-posEps)/dstH <= 1.0f; 2092 const bool tri1 = (wx+posEps)/dstW + (wy+posEps)/dstH >= 1.0f; 2093 2094 bool isOk = false; 2095 2096 DE_ASSERT(tri0 || tri1); 2097 2098 // Pixel can belong to either of the triangles if it lies close enough to the edge. 2099 for (int triNdx = (tri0?0:1); triNdx <= (tri1?1:0); triNdx++) 2100 { 2101 const float triWx = triNdx ? dstW - wx : wx; 2102 const float triWy = triNdx ? dstH - wy : wy; 2103 const float triNx = triNdx ? 1.0f - nx : nx; 2104 const float triNy = triNdx ? 1.0f - ny : ny; 2105 2106 const tcu::Vec3 coord (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy), 2107 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy), 2108 projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy)); 2109 const tcu::Vec3 coordDx (triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy), 2110 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy), 2111 triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy)); 2112 const tcu::Vec3 coordDy (triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx), 2113 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx), 2114 triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx)); 2115 2116 tcu::Vec2 lodBounds = tcu::computeCubeLodBoundsFromDerivates(coord, coordDx, coordDy, srcSize, lodPrec); 2117 2118 // Compute lod bounds across lodOffsets range. 2119 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++) 2120 { 2121 const float wxo = triWx + lodOffsets[lodOffsNdx].x(); 2122 const float wyo = triWy + lodOffsets[lodOffsNdx].y(); 2123 const float nxo = wxo/dstW; 2124 const float nyo = wyo/dstH; 2125 2126 const tcu::Vec3 coordO (projectedTriInterpolate(triS[triNdx], triW[triNdx], nxo, nyo), 2127 projectedTriInterpolate(triT[triNdx], triW[triNdx], nxo, nyo), 2128 projectedTriInterpolate(triR[triNdx], triW[triNdx], nxo, nyo)); 2129 const tcu::Vec3 coordDxo (triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo), 2130 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo), 2131 triDerivateX(triR[triNdx], triW[triNdx], wxo, dstW, nyo)); 2132 const tcu::Vec3 coordDyo (triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo), 2133 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo), 2134 triDerivateY(triR[triNdx], triW[triNdx], wyo, dstH, nxo)); 2135 const tcu::Vec2 lodO = tcu::computeCubeLodBoundsFromDerivates(coordO, coordDxo, coordDyo, srcSize, lodPrec); 2136 2137 lodBounds.x() = de::min(lodBounds.x(), lodO.x()); 2138 lodBounds.y() = de::max(lodBounds.y(), lodO.y()); 2139 } 2140 2141 const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec); 2142 2143 if (tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix)) 2144 { 2145 isOk = true; 2146 break; 2147 } 2148 } 2149 2150 if (!isOk) 2151 { 2152 errorMask.setPixel(tcu::RGBA::red.toVec(), px, py); 2153 numFailed += 1; 2154 } 2155 } 2156 } 2157 } 2158 2159 return numFailed; 2160} 2161 2162bool verifyTextureResult (tcu::TestContext& testCtx, 2163 const tcu::ConstPixelBufferAccess& result, 2164 const tcu::TextureCubeView& src, 2165 const float* texCoord, 2166 const ReferenceParams& sampleParams, 2167 const tcu::LookupPrecision& lookupPrec, 2168 const tcu::LodPrecision& lodPrec, 2169 const tcu::PixelFormat& pixelFormat) 2170{ 2171 tcu::TestLog& log = testCtx.getLog(); 2172 tcu::Surface reference (result.getWidth(), result.getHeight()); 2173 tcu::Surface errorMask (result.getWidth(), result.getHeight()); 2174 int numFailedPixels; 2175 2176 DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask); 2177 2178 sampleTexture(SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams); 2179 numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog()); 2180 2181 if (numFailedPixels > 0) 2182 log << TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage; 2183 2184 log << TestLog::ImageSet("VerifyResult", "Verification result") 2185 << TestLog::Image("Rendered", "Rendered image", result); 2186 2187 if (numFailedPixels > 0) 2188 { 2189 log << TestLog::Image("Reference", "Ideal reference image", reference) 2190 << TestLog::Image("ErrorMask", "Error mask", errorMask); 2191 } 2192 2193 log << TestLog::EndImageSet; 2194 2195 return numFailedPixels == 0; 2196} 2197 2198//! Verifies texture lookup results and returns number of failed pixels. 2199int computeTextureLookupDiff (const tcu::ConstPixelBufferAccess& result, 2200 const tcu::ConstPixelBufferAccess& reference, 2201 const tcu::PixelBufferAccess& errorMask, 2202 const tcu::Texture3DView& baseView, 2203 const float* texCoord, 2204 const ReferenceParams& sampleParams, 2205 const tcu::LookupPrecision& lookupPrec, 2206 const tcu::LodPrecision& lodPrec, 2207 qpWatchDog* watchDog) 2208{ 2209 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight()); 2210 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight()); 2211 2212 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage; 2213 const tcu::Texture3DView src = getEffectiveView(getSubView(baseView, sampleParams.baseLevel, sampleParams.maxLevel), srcLevelStorage, sampleParams.sampler); 2214 2215 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]); 2216 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]); 2217 const tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]); 2218 2219 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight()); 2220 const float dstW = float(dstSize.x()); 2221 const float dstH = float(dstSize.y()); 2222 const tcu::IVec3 srcSize = tcu::IVec3(src.getWidth(), src.getHeight(), src.getDepth()); 2223 2224 // Coordinates and lod per triangle. 2225 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) }; 2226 const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) }; 2227 const tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) }; 2228 const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) }; 2229 2230 const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f); 2231 2232 const float posEps = 1.0f / float(1<<MIN_SUBPIXEL_BITS); 2233 2234 int numFailed = 0; 2235 2236 const tcu::Vec2 lodOffsets[] = 2237 { 2238 tcu::Vec2(-1, 0), 2239 tcu::Vec2(+1, 0), 2240 tcu::Vec2( 0, -1), 2241 tcu::Vec2( 0, +1), 2242 }; 2243 2244 tcu::clear(errorMask, tcu::RGBA::green.toVec()); 2245 2246 for (int py = 0; py < result.getHeight(); py++) 2247 { 2248 // Ugly hack, validation can take way too long at the moment. 2249 if (watchDog) 2250 qpWatchDog_touch(watchDog); 2251 2252 for (int px = 0; px < result.getWidth(); px++) 2253 { 2254 const tcu::Vec4 resPix = (result.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale; 2255 const tcu::Vec4 refPix = (reference.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale; 2256 2257 // Try comparison to ideal reference first, and if that fails use slower verificator. 2258 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold))) 2259 { 2260 const float wx = (float)px + 0.5f; 2261 const float wy = (float)py + 0.5f; 2262 const float nx = wx / dstW; 2263 const float ny = wy / dstH; 2264 2265 const bool tri0 = (wx-posEps)/dstW + (wy-posEps)/dstH <= 1.0f; 2266 const bool tri1 = (wx+posEps)/dstW + (wy+posEps)/dstH >= 1.0f; 2267 2268 bool isOk = false; 2269 2270 DE_ASSERT(tri0 || tri1); 2271 2272 // Pixel can belong to either of the triangles if it lies close enough to the edge. 2273 for (int triNdx = (tri0?0:1); triNdx <= (tri1?1:0); triNdx++) 2274 { 2275 const float triWx = triNdx ? dstW - wx : wx; 2276 const float triWy = triNdx ? dstH - wy : wy; 2277 const float triNx = triNdx ? 1.0f - nx : nx; 2278 const float triNy = triNdx ? 1.0f - ny : ny; 2279 2280 const tcu::Vec3 coord (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy), 2281 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy), 2282 projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy)); 2283 const tcu::Vec3 coordDx = tcu::Vec3(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy), 2284 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy), 2285 triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy)) * srcSize.asFloat(); 2286 const tcu::Vec3 coordDy = tcu::Vec3(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx), 2287 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx), 2288 triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx)) * srcSize.asFloat(); 2289 2290 tcu::Vec2 lodBounds = tcu::computeLodBoundsFromDerivates(coordDx.x(), coordDx.y(), coordDx.z(), coordDy.x(), coordDy.y(), coordDy.z(), lodPrec); 2291 2292 // Compute lod bounds across lodOffsets range. 2293 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++) 2294 { 2295 const float wxo = triWx + lodOffsets[lodOffsNdx].x(); 2296 const float wyo = triWy + lodOffsets[lodOffsNdx].y(); 2297 const float nxo = wxo/dstW; 2298 const float nyo = wyo/dstH; 2299 2300 const tcu::Vec3 coordDxo = tcu::Vec3(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo), 2301 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo), 2302 triDerivateX(triR[triNdx], triW[triNdx], wxo, dstW, nyo)) * srcSize.asFloat(); 2303 const tcu::Vec3 coordDyo = tcu::Vec3(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo), 2304 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo), 2305 triDerivateY(triR[triNdx], triW[triNdx], wyo, dstH, nxo)) * srcSize.asFloat(); 2306 const tcu::Vec2 lodO = tcu::computeLodBoundsFromDerivates(coordDxo.x(), coordDxo.y(), coordDxo.z(), coordDyo.x(), coordDyo.y(), coordDyo.z(), lodPrec); 2307 2308 lodBounds.x() = de::min(lodBounds.x(), lodO.x()); 2309 lodBounds.y() = de::max(lodBounds.y(), lodO.y()); 2310 } 2311 2312 const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec); 2313 2314 if (tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix)) 2315 { 2316 isOk = true; 2317 break; 2318 } 2319 } 2320 2321 if (!isOk) 2322 { 2323 errorMask.setPixel(tcu::RGBA::red.toVec(), px, py); 2324 numFailed += 1; 2325 } 2326 } 2327 } 2328 } 2329 2330 return numFailed; 2331} 2332 2333bool verifyTextureResult (tcu::TestContext& testCtx, 2334 const tcu::ConstPixelBufferAccess& result, 2335 const tcu::Texture3DView& src, 2336 const float* texCoord, 2337 const ReferenceParams& sampleParams, 2338 const tcu::LookupPrecision& lookupPrec, 2339 const tcu::LodPrecision& lodPrec, 2340 const tcu::PixelFormat& pixelFormat) 2341{ 2342 tcu::TestLog& log = testCtx.getLog(); 2343 tcu::Surface reference (result.getWidth(), result.getHeight()); 2344 tcu::Surface errorMask (result.getWidth(), result.getHeight()); 2345 int numFailedPixels; 2346 2347 DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask); 2348 2349 sampleTexture(SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams); 2350 numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog()); 2351 2352 if (numFailedPixels > 0) 2353 log << TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage; 2354 2355 log << TestLog::ImageSet("VerifyResult", "Verification result") 2356 << TestLog::Image("Rendered", "Rendered image", result); 2357 2358 if (numFailedPixels > 0) 2359 { 2360 log << TestLog::Image("Reference", "Ideal reference image", reference) 2361 << TestLog::Image("ErrorMask", "Error mask", errorMask); 2362 } 2363 2364 log << TestLog::EndImageSet; 2365 2366 return numFailedPixels == 0; 2367} 2368 2369//! Verifies texture lookup results and returns number of failed pixels. 2370int computeTextureLookupDiff (const tcu::ConstPixelBufferAccess& result, 2371 const tcu::ConstPixelBufferAccess& reference, 2372 const tcu::PixelBufferAccess& errorMask, 2373 const tcu::Texture1DArrayView& baseView, 2374 const float* texCoord, 2375 const ReferenceParams& sampleParams, 2376 const tcu::LookupPrecision& lookupPrec, 2377 const tcu::LodPrecision& lodPrec, 2378 qpWatchDog* watchDog) 2379{ 2380 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight()); 2381 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight()); 2382 2383 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage; 2384 const tcu::Texture1DArrayView src = getEffectiveView(baseView, srcLevelStorage, sampleParams.sampler); 2385 2386 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[2+0], texCoord[4+0], texCoord[6+0]); 2387 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[2+1], texCoord[4+1], texCoord[6+1]); 2388 2389 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight()); 2390 const float dstW = float(dstSize.x()); 2391 const float dstH = float(dstSize.y()); 2392 const float srcSize = float(src.getWidth()); // For lod computation, thus #layers is ignored. 2393 2394 // Coordinates and lod per triangle. 2395 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) }; 2396 const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) }; 2397 const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) }; 2398 2399 const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f); 2400 2401 int numFailed = 0; 2402 2403 const tcu::Vec2 lodOffsets[] = 2404 { 2405 tcu::Vec2(-1, 0), 2406 tcu::Vec2(+1, 0), 2407 tcu::Vec2( 0, -1), 2408 tcu::Vec2( 0, +1), 2409 }; 2410 2411 tcu::clear(errorMask, tcu::RGBA::green.toVec()); 2412 2413 for (int py = 0; py < result.getHeight(); py++) 2414 { 2415 // Ugly hack, validation can take way too long at the moment. 2416 if (watchDog) 2417 qpWatchDog_touch(watchDog); 2418 2419 for (int px = 0; px < result.getWidth(); px++) 2420 { 2421 const tcu::Vec4 resPix = (result.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale; 2422 const tcu::Vec4 refPix = (reference.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale; 2423 2424 // Try comparison to ideal reference first, and if that fails use slower verificator. 2425 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold))) 2426 { 2427 const float wx = (float)px + 0.5f; 2428 const float wy = (float)py + 0.5f; 2429 const float nx = wx / dstW; 2430 const float ny = wy / dstH; 2431 2432 const int triNdx = nx + ny >= 1.0f ? 1 : 0; 2433 const float triWx = triNdx ? dstW - wx : wx; 2434 const float triWy = triNdx ? dstH - wy : wy; 2435 const float triNx = triNdx ? 1.0f - nx : nx; 2436 const float triNy = triNdx ? 1.0f - ny : ny; 2437 2438 const tcu::Vec2 coord (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy), 2439 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy)); 2440 const float coordDx = triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy) * srcSize; 2441 const float coordDy = triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx) * srcSize; 2442 2443 tcu::Vec2 lodBounds = tcu::computeLodBoundsFromDerivates(coordDx, coordDy, lodPrec); 2444 2445 // Compute lod bounds across lodOffsets range. 2446 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++) 2447 { 2448 const float wxo = triWx + lodOffsets[lodOffsNdx].x(); 2449 const float wyo = triWy + lodOffsets[lodOffsNdx].y(); 2450 const float nxo = wxo/dstW; 2451 const float nyo = wyo/dstH; 2452 2453 const float coordDxo = triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo) * srcSize; 2454 const float coordDyo = triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo) * srcSize; 2455 const tcu::Vec2 lodO = tcu::computeLodBoundsFromDerivates(coordDxo, coordDyo, lodPrec); 2456 2457 lodBounds.x() = de::min(lodBounds.x(), lodO.x()); 2458 lodBounds.y() = de::max(lodBounds.y(), lodO.y()); 2459 } 2460 2461 const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec); 2462 const bool isOk = tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix); 2463 2464 if (!isOk) 2465 { 2466 errorMask.setPixel(tcu::RGBA::red.toVec(), px, py); 2467 numFailed += 1; 2468 } 2469 } 2470 } 2471 } 2472 2473 return numFailed; 2474} 2475 2476//! Verifies texture lookup results and returns number of failed pixels. 2477int computeTextureLookupDiff (const tcu::ConstPixelBufferAccess& result, 2478 const tcu::ConstPixelBufferAccess& reference, 2479 const tcu::PixelBufferAccess& errorMask, 2480 const tcu::Texture2DArrayView& baseView, 2481 const float* texCoord, 2482 const ReferenceParams& sampleParams, 2483 const tcu::LookupPrecision& lookupPrec, 2484 const tcu::LodPrecision& lodPrec, 2485 qpWatchDog* watchDog) 2486{ 2487 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight()); 2488 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight()); 2489 2490 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage; 2491 const tcu::Texture2DArrayView src = getEffectiveView(baseView, srcLevelStorage, sampleParams.sampler); 2492 2493 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]); 2494 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]); 2495 const tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]); 2496 2497 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight()); 2498 const float dstW = float(dstSize.x()); 2499 const float dstH = float(dstSize.y()); 2500 const tcu::Vec2 srcSize = tcu::IVec2(src.getWidth(), src.getHeight()).asFloat(); // For lod computation, thus #layers is ignored. 2501 2502 // Coordinates and lod per triangle. 2503 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) }; 2504 const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) }; 2505 const tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) }; 2506 const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) }; 2507 2508 const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f); 2509 2510 int numFailed = 0; 2511 2512 const tcu::Vec2 lodOffsets[] = 2513 { 2514 tcu::Vec2(-1, 0), 2515 tcu::Vec2(+1, 0), 2516 tcu::Vec2( 0, -1), 2517 tcu::Vec2( 0, +1), 2518 }; 2519 2520 tcu::clear(errorMask, tcu::RGBA::green.toVec()); 2521 2522 for (int py = 0; py < result.getHeight(); py++) 2523 { 2524 // Ugly hack, validation can take way too long at the moment. 2525 if (watchDog) 2526 qpWatchDog_touch(watchDog); 2527 2528 for (int px = 0; px < result.getWidth(); px++) 2529 { 2530 const tcu::Vec4 resPix = (result.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale; 2531 const tcu::Vec4 refPix = (reference.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale; 2532 2533 // Try comparison to ideal reference first, and if that fails use slower verificator. 2534 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold))) 2535 { 2536 const float wx = (float)px + 0.5f; 2537 const float wy = (float)py + 0.5f; 2538 const float nx = wx / dstW; 2539 const float ny = wy / dstH; 2540 2541 const int triNdx = nx + ny >= 1.0f ? 1 : 0; 2542 const float triWx = triNdx ? dstW - wx : wx; 2543 const float triWy = triNdx ? dstH - wy : wy; 2544 const float triNx = triNdx ? 1.0f - nx : nx; 2545 const float triNy = triNdx ? 1.0f - ny : ny; 2546 2547 const tcu::Vec3 coord (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy), 2548 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy), 2549 projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy)); 2550 const tcu::Vec2 coordDx = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy), 2551 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy)) * srcSize; 2552 const tcu::Vec2 coordDy = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx), 2553 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx)) * srcSize; 2554 2555 tcu::Vec2 lodBounds = tcu::computeLodBoundsFromDerivates(coordDx.x(), coordDx.y(), coordDy.x(), coordDy.y(), lodPrec); 2556 2557 // Compute lod bounds across lodOffsets range. 2558 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++) 2559 { 2560 const float wxo = triWx + lodOffsets[lodOffsNdx].x(); 2561 const float wyo = triWy + lodOffsets[lodOffsNdx].y(); 2562 const float nxo = wxo/dstW; 2563 const float nyo = wyo/dstH; 2564 2565 const tcu::Vec2 coordDxo = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo), 2566 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo)) * srcSize; 2567 const tcu::Vec2 coordDyo = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo), 2568 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo)) * srcSize; 2569 const tcu::Vec2 lodO = tcu::computeLodBoundsFromDerivates(coordDxo.x(), coordDxo.y(), coordDyo.x(), coordDyo.y(), lodPrec); 2570 2571 lodBounds.x() = de::min(lodBounds.x(), lodO.x()); 2572 lodBounds.y() = de::max(lodBounds.y(), lodO.y()); 2573 } 2574 2575 const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec); 2576 const bool isOk = tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix); 2577 2578 if (!isOk) 2579 { 2580 errorMask.setPixel(tcu::RGBA::red.toVec(), px, py); 2581 numFailed += 1; 2582 } 2583 } 2584 } 2585 } 2586 2587 return numFailed; 2588} 2589 2590bool verifyTextureResult (tcu::TestContext& testCtx, 2591 const tcu::ConstPixelBufferAccess& result, 2592 const tcu::Texture1DArrayView& src, 2593 const float* texCoord, 2594 const ReferenceParams& sampleParams, 2595 const tcu::LookupPrecision& lookupPrec, 2596 const tcu::LodPrecision& lodPrec, 2597 const tcu::PixelFormat& pixelFormat) 2598{ 2599 tcu::TestLog& log = testCtx.getLog(); 2600 tcu::Surface reference (result.getWidth(), result.getHeight()); 2601 tcu::Surface errorMask (result.getWidth(), result.getHeight()); 2602 int numFailedPixels; 2603 2604 DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask); 2605 2606 sampleTexture(SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams); 2607 numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog()); 2608 2609 if (numFailedPixels > 0) 2610 log << TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage; 2611 2612 log << TestLog::ImageSet("VerifyResult", "Verification result") 2613 << TestLog::Image("Rendered", "Rendered image", result); 2614 2615 if (numFailedPixels > 0) 2616 { 2617 log << TestLog::Image("Reference", "Ideal reference image", reference) 2618 << TestLog::Image("ErrorMask", "Error mask", errorMask); 2619 } 2620 2621 log << TestLog::EndImageSet; 2622 2623 return numFailedPixels == 0; 2624} 2625 2626bool verifyTextureResult (tcu::TestContext& testCtx, 2627 const tcu::ConstPixelBufferAccess& result, 2628 const tcu::Texture2DArrayView& src, 2629 const float* texCoord, 2630 const ReferenceParams& sampleParams, 2631 const tcu::LookupPrecision& lookupPrec, 2632 const tcu::LodPrecision& lodPrec, 2633 const tcu::PixelFormat& pixelFormat) 2634{ 2635 tcu::TestLog& log = testCtx.getLog(); 2636 tcu::Surface reference (result.getWidth(), result.getHeight()); 2637 tcu::Surface errorMask (result.getWidth(), result.getHeight()); 2638 int numFailedPixels; 2639 2640 DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask); 2641 2642 sampleTexture(SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams); 2643 numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog()); 2644 2645 if (numFailedPixels > 0) 2646 log << TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage; 2647 2648 log << TestLog::ImageSet("VerifyResult", "Verification result") 2649 << TestLog::Image("Rendered", "Rendered image", result); 2650 2651 if (numFailedPixels > 0) 2652 { 2653 log << TestLog::Image("Reference", "Ideal reference image", reference) 2654 << TestLog::Image("ErrorMask", "Error mask", errorMask); 2655 } 2656 2657 log << TestLog::EndImageSet; 2658 2659 return numFailedPixels == 0; 2660} 2661 2662//! Verifies texture lookup results and returns number of failed pixels. 2663int computeTextureLookupDiff (const tcu::ConstPixelBufferAccess& result, 2664 const tcu::ConstPixelBufferAccess& reference, 2665 const tcu::PixelBufferAccess& errorMask, 2666 const tcu::TextureCubeArrayView& baseView, 2667 const float* texCoord, 2668 const ReferenceParams& sampleParams, 2669 const tcu::LookupPrecision& lookupPrec, 2670 const tcu::IVec4& coordBits, 2671 const tcu::LodPrecision& lodPrec, 2672 qpWatchDog* watchDog) 2673{ 2674 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight()); 2675 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight()); 2676 2677 std::vector<tcu::ConstPixelBufferAccess> srcLevelStorage; 2678 const tcu::TextureCubeArrayView src = getEffectiveView(getSubView(baseView, sampleParams.baseLevel, sampleParams.maxLevel), srcLevelStorage, sampleParams.sampler); 2679 2680 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[4+0], texCoord[8+0], texCoord[12+0]); 2681 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[4+1], texCoord[8+1], texCoord[12+1]); 2682 const tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[4+2], texCoord[8+2], texCoord[12+2]); 2683 const tcu::Vec4 qq = tcu::Vec4(texCoord[0+3], texCoord[4+3], texCoord[8+3], texCoord[12+3]); 2684 2685 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight()); 2686 const float dstW = float(dstSize.x()); 2687 const float dstH = float(dstSize.y()); 2688 const int srcSize = src.getSize(); 2689 2690 // Coordinates per triangle. 2691 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) }; 2692 const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) }; 2693 const tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) }; 2694 const tcu::Vec3 triQ[2] = { qq.swizzle(0, 1, 2), qq.swizzle(3, 2, 1) }; 2695 const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) }; 2696 2697 const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f); 2698 2699 const float posEps = 1.0f / float((1<<4) + 1); // ES3 requires at least 4 subpixel bits. 2700 2701 int numFailed = 0; 2702 2703 const tcu::Vec2 lodOffsets[] = 2704 { 2705 tcu::Vec2(-1, 0), 2706 tcu::Vec2(+1, 0), 2707 tcu::Vec2( 0, -1), 2708 tcu::Vec2( 0, +1), 2709 2710 // \note Not strictly allowed by spec, but implementations do this in practice. 2711 tcu::Vec2(-1, -1), 2712 tcu::Vec2(-1, +1), 2713 tcu::Vec2(+1, -1), 2714 tcu::Vec2(+1, +1), 2715 }; 2716 2717 tcu::clear(errorMask, tcu::RGBA::green.toVec()); 2718 2719 for (int py = 0; py < result.getHeight(); py++) 2720 { 2721 // Ugly hack, validation can take way too long at the moment. 2722 if (watchDog) 2723 qpWatchDog_touch(watchDog); 2724 2725 for (int px = 0; px < result.getWidth(); px++) 2726 { 2727 const tcu::Vec4 resPix = (result.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale; 2728 const tcu::Vec4 refPix = (reference.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale; 2729 2730 // Try comparison to ideal reference first, and if that fails use slower verificator. 2731 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold))) 2732 { 2733 const float wx = (float)px + 0.5f; 2734 const float wy = (float)py + 0.5f; 2735 const float nx = wx / dstW; 2736 const float ny = wy / dstH; 2737 2738 const bool tri0 = nx + ny - posEps <= 1.0f; 2739 const bool tri1 = nx + ny + posEps >= 1.0f; 2740 2741 bool isOk = false; 2742 2743 DE_ASSERT(tri0 || tri1); 2744 2745 // Pixel can belong to either of the triangles if it lies close enough to the edge. 2746 for (int triNdx = (tri0?0:1); triNdx <= (tri1?1:0); triNdx++) 2747 { 2748 const float triWx = triNdx ? dstW - wx : wx; 2749 const float triWy = triNdx ? dstH - wy : wy; 2750 const float triNx = triNdx ? 1.0f - nx : nx; 2751 const float triNy = triNdx ? 1.0f - ny : ny; 2752 2753 const tcu::Vec4 coord (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy), 2754 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy), 2755 projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy), 2756 projectedTriInterpolate(triQ[triNdx], triW[triNdx], triNx, triNy)); 2757 const tcu::Vec3 coordDx (triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy), 2758 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy), 2759 triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy)); 2760 const tcu::Vec3 coordDy (triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx), 2761 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx), 2762 triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx)); 2763 2764 tcu::Vec2 lodBounds = tcu::computeCubeLodBoundsFromDerivates(coord.toWidth<3>(), coordDx, coordDy, srcSize, lodPrec); 2765 2766 // Compute lod bounds across lodOffsets range. 2767 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++) 2768 { 2769 const float wxo = triWx + lodOffsets[lodOffsNdx].x(); 2770 const float wyo = triWy + lodOffsets[lodOffsNdx].y(); 2771 const float nxo = wxo/dstW; 2772 const float nyo = wyo/dstH; 2773 2774 const tcu::Vec3 coordO (projectedTriInterpolate(triS[triNdx], triW[triNdx], nxo, nyo), 2775 projectedTriInterpolate(triT[triNdx], triW[triNdx], nxo, nyo), 2776 projectedTriInterpolate(triR[triNdx], triW[triNdx], nxo, nyo)); 2777 const tcu::Vec3 coordDxo (triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo), 2778 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo), 2779 triDerivateX(triR[triNdx], triW[triNdx], wxo, dstW, nyo)); 2780 const tcu::Vec3 coordDyo (triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo), 2781 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo), 2782 triDerivateY(triR[triNdx], triW[triNdx], wyo, dstH, nxo)); 2783 const tcu::Vec2 lodO = tcu::computeCubeLodBoundsFromDerivates(coordO, coordDxo, coordDyo, srcSize, lodPrec); 2784 2785 lodBounds.x() = de::min(lodBounds.x(), lodO.x()); 2786 lodBounds.y() = de::max(lodBounds.y(), lodO.y()); 2787 } 2788 2789 const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec); 2790 2791 if (tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coordBits, coord, clampedLod, resPix)) 2792 { 2793 isOk = true; 2794 break; 2795 } 2796 } 2797 2798 if (!isOk) 2799 { 2800 errorMask.setPixel(tcu::RGBA::red.toVec(), px, py); 2801 numFailed += 1; 2802 } 2803 } 2804 } 2805 } 2806 2807 return numFailed; 2808} 2809 2810bool verifyTextureResult (tcu::TestContext& testCtx, 2811 const tcu::ConstPixelBufferAccess& result, 2812 const tcu::TextureCubeArrayView& src, 2813 const float* texCoord, 2814 const ReferenceParams& sampleParams, 2815 const tcu::LookupPrecision& lookupPrec, 2816 const tcu::IVec4& coordBits, 2817 const tcu::LodPrecision& lodPrec, 2818 const tcu::PixelFormat& pixelFormat) 2819{ 2820 tcu::TestLog& log = testCtx.getLog(); 2821 tcu::Surface reference (result.getWidth(), result.getHeight()); 2822 tcu::Surface errorMask (result.getWidth(), result.getHeight()); 2823 int numFailedPixels; 2824 2825 DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask); 2826 2827 sampleTexture(SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams); 2828 numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, coordBits, lodPrec, testCtx.getWatchDog()); 2829 2830 if (numFailedPixels > 0) 2831 log << TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage; 2832 2833 log << TestLog::ImageSet("VerifyResult", "Verification result") 2834 << TestLog::Image("Rendered", "Rendered image", result); 2835 2836 if (numFailedPixels > 0) 2837 { 2838 log << TestLog::Image("Reference", "Ideal reference image", reference) 2839 << TestLog::Image("ErrorMask", "Error mask", errorMask); 2840 } 2841 2842 log << TestLog::EndImageSet; 2843 2844 return numFailedPixels == 0; 2845} 2846 2847// Shadow lookup verification 2848 2849int computeTextureCompareDiff (const tcu::ConstPixelBufferAccess& result, 2850 const tcu::ConstPixelBufferAccess& reference, 2851 const tcu::PixelBufferAccess& errorMask, 2852 const tcu::Texture2DView& src, 2853 const float* texCoord, 2854 const ReferenceParams& sampleParams, 2855 const tcu::TexComparePrecision& comparePrec, 2856 const tcu::LodPrecision& lodPrec, 2857 const tcu::Vec3& nonShadowThreshold) 2858{ 2859 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight()); 2860 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight()); 2861 2862 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[2+0], texCoord[4+0], texCoord[6+0]); 2863 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[2+1], texCoord[4+1], texCoord[6+1]); 2864 2865 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight()); 2866 const float dstW = float(dstSize.x()); 2867 const float dstH = float(dstSize.y()); 2868 const tcu::IVec2 srcSize = tcu::IVec2(src.getWidth(), src.getHeight()); 2869 2870 // Coordinates and lod per triangle. 2871 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) }; 2872 const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) }; 2873 const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) }; 2874 2875 const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f); 2876 2877 int numFailed = 0; 2878 2879 const tcu::Vec2 lodOffsets[] = 2880 { 2881 tcu::Vec2(-1, 0), 2882 tcu::Vec2(+1, 0), 2883 tcu::Vec2( 0, -1), 2884 tcu::Vec2( 0, +1), 2885 }; 2886 2887 tcu::clear(errorMask, tcu::RGBA::green.toVec()); 2888 2889 for (int py = 0; py < result.getHeight(); py++) 2890 { 2891 for (int px = 0; px < result.getWidth(); px++) 2892 { 2893 const tcu::Vec4 resPix = result.getPixel(px, py); 2894 const tcu::Vec4 refPix = reference.getPixel(px, py); 2895 2896 // Other channels should trivially match to reference. 2897 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(refPix.swizzle(1,2,3) - resPix.swizzle(1,2,3)), nonShadowThreshold))) 2898 { 2899 errorMask.setPixel(tcu::RGBA::red.toVec(), px, py); 2900 numFailed += 1; 2901 continue; 2902 } 2903 2904 // Reference result is known to be a valid result, we can 2905 // skip verification if thes results are equal 2906 if (resPix.x() != refPix.x()) 2907 { 2908 const float wx = (float)px + 0.5f; 2909 const float wy = (float)py + 0.5f; 2910 const float nx = wx / dstW; 2911 const float ny = wy / dstH; 2912 2913 const int triNdx = nx + ny >= 1.0f ? 1 : 0; 2914 const float triWx = triNdx ? dstW - wx : wx; 2915 const float triWy = triNdx ? dstH - wy : wy; 2916 const float triNx = triNdx ? 1.0f - nx : nx; 2917 const float triNy = triNdx ? 1.0f - ny : ny; 2918 2919 const tcu::Vec2 coord (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy), 2920 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy)); 2921 const tcu::Vec2 coordDx = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy), 2922 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy)) * srcSize.asFloat(); 2923 const tcu::Vec2 coordDy = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx), 2924 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx)) * srcSize.asFloat(); 2925 2926 tcu::Vec2 lodBounds = tcu::computeLodBoundsFromDerivates(coordDx.x(), coordDx.y(), coordDy.x(), coordDy.y(), lodPrec); 2927 2928 // Compute lod bounds across lodOffsets range. 2929 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++) 2930 { 2931 const float wxo = triWx + lodOffsets[lodOffsNdx].x(); 2932 const float wyo = triWy + lodOffsets[lodOffsNdx].y(); 2933 const float nxo = wxo/dstW; 2934 const float nyo = wyo/dstH; 2935 2936 const tcu::Vec2 coordDxo = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo), 2937 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo)) * srcSize.asFloat(); 2938 const tcu::Vec2 coordDyo = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo), 2939 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo)) * srcSize.asFloat(); 2940 const tcu::Vec2 lodO = tcu::computeLodBoundsFromDerivates(coordDxo.x(), coordDxo.y(), coordDyo.x(), coordDyo.y(), lodPrec); 2941 2942 lodBounds.x() = de::min(lodBounds.x(), lodO.x()); 2943 lodBounds.y() = de::max(lodBounds.y(), lodO.y()); 2944 } 2945 2946 const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec); 2947 const bool isOk = tcu::isTexCompareResultValid(src, sampleParams.sampler, comparePrec, coord, clampedLod, sampleParams.ref, resPix.x()); 2948 2949 if (!isOk) 2950 { 2951 errorMask.setPixel(tcu::RGBA::red.toVec(), px, py); 2952 numFailed += 1; 2953 } 2954 } 2955 } 2956 } 2957 2958 return numFailed; 2959} 2960 2961int computeTextureCompareDiff (const tcu::ConstPixelBufferAccess& result, 2962 const tcu::ConstPixelBufferAccess& reference, 2963 const tcu::PixelBufferAccess& errorMask, 2964 const tcu::TextureCubeView& src, 2965 const float* texCoord, 2966 const ReferenceParams& sampleParams, 2967 const tcu::TexComparePrecision& comparePrec, 2968 const tcu::LodPrecision& lodPrec, 2969 const tcu::Vec3& nonShadowThreshold) 2970{ 2971 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight()); 2972 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight()); 2973 2974 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]); 2975 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]); 2976 const tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]); 2977 2978 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight()); 2979 const float dstW = float(dstSize.x()); 2980 const float dstH = float(dstSize.y()); 2981 const int srcSize = src.getSize(); 2982 2983 // Coordinates per triangle. 2984 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) }; 2985 const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) }; 2986 const tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) }; 2987 const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) }; 2988 2989 const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f); 2990 2991 int numFailed = 0; 2992 2993 const tcu::Vec2 lodOffsets[] = 2994 { 2995 tcu::Vec2(-1, 0), 2996 tcu::Vec2(+1, 0), 2997 tcu::Vec2( 0, -1), 2998 tcu::Vec2( 0, +1), 2999 }; 3000 3001 tcu::clear(errorMask, tcu::RGBA::green.toVec()); 3002 3003 for (int py = 0; py < result.getHeight(); py++) 3004 { 3005 for (int px = 0; px < result.getWidth(); px++) 3006 { 3007 const tcu::Vec4 resPix = result.getPixel(px, py); 3008 const tcu::Vec4 refPix = reference.getPixel(px, py); 3009 3010 // Other channels should trivially match to reference. 3011 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(refPix.swizzle(1,2,3) - resPix.swizzle(1,2,3)), nonShadowThreshold))) 3012 { 3013 errorMask.setPixel(tcu::RGBA::red.toVec(), px, py); 3014 numFailed += 1; 3015 continue; 3016 } 3017 3018 // Reference result is known to be a valid result, we can 3019 // skip verification if thes results are equal 3020 if (resPix.x() != refPix.x()) 3021 { 3022 const float wx = (float)px + 0.5f; 3023 const float wy = (float)py + 0.5f; 3024 const float nx = wx / dstW; 3025 const float ny = wy / dstH; 3026 3027 const int triNdx = nx + ny >= 1.0f ? 1 : 0; 3028 const float triWx = triNdx ? dstW - wx : wx; 3029 const float triWy = triNdx ? dstH - wy : wy; 3030 const float triNx = triNdx ? 1.0f - nx : nx; 3031 const float triNy = triNdx ? 1.0f - ny : ny; 3032 3033 const tcu::Vec3 coord (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy), 3034 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy), 3035 projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy)); 3036 const tcu::Vec3 coordDx (triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy), 3037 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy), 3038 triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy)); 3039 const tcu::Vec3 coordDy (triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx), 3040 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx), 3041 triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx)); 3042 3043 tcu::Vec2 lodBounds = tcu::computeCubeLodBoundsFromDerivates(coord, coordDx, coordDy, srcSize, lodPrec); 3044 3045 // Compute lod bounds across lodOffsets range. 3046 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++) 3047 { 3048 const float wxo = triWx + lodOffsets[lodOffsNdx].x(); 3049 const float wyo = triWy + lodOffsets[lodOffsNdx].y(); 3050 const float nxo = wxo/dstW; 3051 const float nyo = wyo/dstH; 3052 3053 const tcu::Vec3 coordO (projectedTriInterpolate(triS[triNdx], triW[triNdx], nxo, nyo), 3054 projectedTriInterpolate(triT[triNdx], triW[triNdx], nxo, nyo), 3055 projectedTriInterpolate(triR[triNdx], triW[triNdx], nxo, nyo)); 3056 const tcu::Vec3 coordDxo (triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo), 3057 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo), 3058 triDerivateX(triR[triNdx], triW[triNdx], wxo, dstW, nyo)); 3059 const tcu::Vec3 coordDyo (triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo), 3060 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo), 3061 triDerivateY(triR[triNdx], triW[triNdx], wyo, dstH, nxo)); 3062 const tcu::Vec2 lodO = tcu::computeCubeLodBoundsFromDerivates(coordO, coordDxo, coordDyo, srcSize, lodPrec); 3063 3064 lodBounds.x() = de::min(lodBounds.x(), lodO.x()); 3065 lodBounds.y() = de::max(lodBounds.y(), lodO.y()); 3066 } 3067 3068 const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec); 3069 const bool isOk = tcu::isTexCompareResultValid(src, sampleParams.sampler, comparePrec, coord, clampedLod, sampleParams.ref, resPix.x()); 3070 3071 if (!isOk) 3072 { 3073 errorMask.setPixel(tcu::RGBA::red.toVec(), px, py); 3074 numFailed += 1; 3075 } 3076 } 3077 } 3078 } 3079 3080 return numFailed; 3081} 3082 3083int computeTextureCompareDiff (const tcu::ConstPixelBufferAccess& result, 3084 const tcu::ConstPixelBufferAccess& reference, 3085 const tcu::PixelBufferAccess& errorMask, 3086 const tcu::Texture2DArrayView& src, 3087 const float* texCoord, 3088 const ReferenceParams& sampleParams, 3089 const tcu::TexComparePrecision& comparePrec, 3090 const tcu::LodPrecision& lodPrec, 3091 const tcu::Vec3& nonShadowThreshold) 3092{ 3093 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight()); 3094 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight()); 3095 3096 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]); 3097 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]); 3098 const tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]); 3099 3100 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight()); 3101 const float dstW = float(dstSize.x()); 3102 const float dstH = float(dstSize.y()); 3103 const tcu::IVec2 srcSize = tcu::IVec2(src.getWidth(), src.getHeight()); 3104 3105 // Coordinates and lod per triangle. 3106 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) }; 3107 const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) }; 3108 const tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) }; 3109 const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) }; 3110 3111 const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f); 3112 3113 int numFailed = 0; 3114 3115 const tcu::Vec2 lodOffsets[] = 3116 { 3117 tcu::Vec2(-1, 0), 3118 tcu::Vec2(+1, 0), 3119 tcu::Vec2( 0, -1), 3120 tcu::Vec2( 0, +1), 3121 }; 3122 3123 tcu::clear(errorMask, tcu::RGBA::green.toVec()); 3124 3125 for (int py = 0; py < result.getHeight(); py++) 3126 { 3127 for (int px = 0; px < result.getWidth(); px++) 3128 { 3129 const tcu::Vec4 resPix = result.getPixel(px, py); 3130 const tcu::Vec4 refPix = reference.getPixel(px, py); 3131 3132 // Other channels should trivially match to reference. 3133 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(refPix.swizzle(1,2,3) - resPix.swizzle(1,2,3)), nonShadowThreshold))) 3134 { 3135 errorMask.setPixel(tcu::RGBA::red.toVec(), px, py); 3136 numFailed += 1; 3137 continue; 3138 } 3139 3140 // Reference result is known to be a valid result, we can 3141 // skip verification if thes results are equal 3142 if (resPix.x() != refPix.x()) 3143 { 3144 const float wx = (float)px + 0.5f; 3145 const float wy = (float)py + 0.5f; 3146 const float nx = wx / dstW; 3147 const float ny = wy / dstH; 3148 3149 const int triNdx = nx + ny >= 1.0f ? 1 : 0; 3150 const float triWx = triNdx ? dstW - wx : wx; 3151 const float triWy = triNdx ? dstH - wy : wy; 3152 const float triNx = triNdx ? 1.0f - nx : nx; 3153 const float triNy = triNdx ? 1.0f - ny : ny; 3154 3155 const tcu::Vec3 coord (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy), 3156 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy), 3157 projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy)); 3158 const tcu::Vec2 coordDx = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy), 3159 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy)) * srcSize.asFloat(); 3160 const tcu::Vec2 coordDy = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx), 3161 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx)) * srcSize.asFloat(); 3162 3163 tcu::Vec2 lodBounds = tcu::computeLodBoundsFromDerivates(coordDx.x(), coordDx.y(), coordDy.x(), coordDy.y(), lodPrec); 3164 3165 // Compute lod bounds across lodOffsets range. 3166 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++) 3167 { 3168 const float wxo = triWx + lodOffsets[lodOffsNdx].x(); 3169 const float wyo = triWy + lodOffsets[lodOffsNdx].y(); 3170 const float nxo = wxo/dstW; 3171 const float nyo = wyo/dstH; 3172 3173 const tcu::Vec2 coordDxo = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo), 3174 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo)) * srcSize.asFloat(); 3175 const tcu::Vec2 coordDyo = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo), 3176 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo)) * srcSize.asFloat(); 3177 const tcu::Vec2 lodO = tcu::computeLodBoundsFromDerivates(coordDxo.x(), coordDxo.y(), coordDyo.x(), coordDyo.y(), lodPrec); 3178 3179 lodBounds.x() = de::min(lodBounds.x(), lodO.x()); 3180 lodBounds.y() = de::max(lodBounds.y(), lodO.y()); 3181 } 3182 3183 const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec); 3184 const bool isOk = tcu::isTexCompareResultValid(src, sampleParams.sampler, comparePrec, coord, clampedLod, sampleParams.ref, resPix.x()); 3185 3186 if (!isOk) 3187 { 3188 errorMask.setPixel(tcu::RGBA::red.toVec(), px, py); 3189 numFailed += 1; 3190 } 3191 } 3192 } 3193 } 3194 3195 return numFailed; 3196} 3197 3198// Mipmap generation comparison. 3199 3200static int compareGenMipmapBilinear (const tcu::ConstPixelBufferAccess& dst, const tcu::ConstPixelBufferAccess& src, const tcu::PixelBufferAccess& errorMask, const GenMipmapPrecision& precision) 3201{ 3202 DE_ASSERT(dst.getDepth() == 1 && src.getDepth() == 1); // \todo [2013-10-29 pyry] 3D textures. 3203 3204 const float dstW = float(dst.getWidth()); 3205 const float dstH = float(dst.getHeight()); 3206 const float srcW = float(src.getWidth()); 3207 const float srcH = float(src.getHeight()); 3208 int numFailed = 0; 3209 3210 // Translation to lookup verification parameters. 3211 const tcu::Sampler sampler (tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, 3212 tcu::Sampler::LINEAR, tcu::Sampler::LINEAR, 0.0f, false /* non-normalized coords */); 3213 tcu::LookupPrecision lookupPrec; 3214 3215 lookupPrec.colorThreshold = precision.colorThreshold; 3216 lookupPrec.colorMask = precision.colorMask; 3217 lookupPrec.coordBits = tcu::IVec3(22); 3218 lookupPrec.uvwBits = precision.filterBits; 3219 3220 for (int y = 0; y < dst.getHeight(); y++) 3221 for (int x = 0; x < dst.getWidth(); x++) 3222 { 3223 const tcu::Vec4 result = dst.getPixel(x, y); 3224 const float cx = (float(x)+0.5f) / dstW * srcW; 3225 const float cy = (float(y)+0.5f) / dstH * srcH; 3226 const bool isOk = tcu::isLinearSampleResultValid(src, sampler, lookupPrec, tcu::Vec2(cx, cy), 0, result); 3227 3228 errorMask.setPixel(isOk ? tcu::RGBA::green.toVec() : tcu::RGBA::red.toVec(), x, y); 3229 if (!isOk) 3230 numFailed += 1; 3231 } 3232 3233 return numFailed; 3234} 3235 3236static int compareGenMipmapBox (const tcu::ConstPixelBufferAccess& dst, const tcu::ConstPixelBufferAccess& src, const tcu::PixelBufferAccess& errorMask, const GenMipmapPrecision& precision) 3237{ 3238 DE_ASSERT(dst.getDepth() == 1 && src.getDepth() == 1); // \todo [2013-10-29 pyry] 3D textures. 3239 3240 const float dstW = float(dst.getWidth()); 3241 const float dstH = float(dst.getHeight()); 3242 const float srcW = float(src.getWidth()); 3243 const float srcH = float(src.getHeight()); 3244 int numFailed = 0; 3245 3246 // Translation to lookup verification parameters. 3247 const tcu::Sampler sampler (tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, 3248 tcu::Sampler::LINEAR, tcu::Sampler::LINEAR, 0.0f, false /* non-normalized coords */); 3249 tcu::LookupPrecision lookupPrec; 3250 3251 lookupPrec.colorThreshold = precision.colorThreshold; 3252 lookupPrec.colorMask = precision.colorMask; 3253 lookupPrec.coordBits = tcu::IVec3(22); 3254 lookupPrec.uvwBits = precision.filterBits; 3255 3256 for (int y = 0; y < dst.getHeight(); y++) 3257 for (int x = 0; x < dst.getWidth(); x++) 3258 { 3259 const tcu::Vec4 result = dst.getPixel(x, y); 3260 const float cx = deFloatFloor(float(x) / dstW * srcW) + 1.0f; 3261 const float cy = deFloatFloor(float(y) / dstH * srcH) + 1.0f; 3262 const bool isOk = tcu::isLinearSampleResultValid(src, sampler, lookupPrec, tcu::Vec2(cx, cy), 0, result); 3263 3264 errorMask.setPixel(isOk ? tcu::RGBA::green.toVec() : tcu::RGBA::red.toVec(), x, y); 3265 if (!isOk) 3266 numFailed += 1; 3267 } 3268 3269 return numFailed; 3270} 3271 3272static int compareGenMipmapVeryLenient (const tcu::ConstPixelBufferAccess& dst, const tcu::ConstPixelBufferAccess& src, const tcu::PixelBufferAccess& errorMask, const GenMipmapPrecision& precision) 3273{ 3274 DE_ASSERT(dst.getDepth() == 1 && src.getDepth() == 1); // \todo [2013-10-29 pyry] 3D textures. 3275 DE_UNREF(precision); 3276 3277 const float dstW = float(dst.getWidth()); 3278 const float dstH = float(dst.getHeight()); 3279 const float srcW = float(src.getWidth()); 3280 const float srcH = float(src.getHeight()); 3281 int numFailed = 0; 3282 3283 for (int y = 0; y < dst.getHeight(); y++) 3284 for (int x = 0; x < dst.getWidth(); x++) 3285 { 3286 const tcu::Vec4 result = dst.getPixel(x, y); 3287 const int minX = deFloorFloatToInt32(float(x-0.5f) / dstW * srcW); 3288 const int minY = deFloorFloatToInt32(float(y-0.5f) / dstH * srcH); 3289 const int maxX = deCeilFloatToInt32(float(x+1.5f) / dstW * srcW); 3290 const int maxY = deCeilFloatToInt32(float(y+1.5f) / dstH * srcH); 3291 tcu::Vec4 minVal, maxVal; 3292 bool isOk; 3293 3294 DE_ASSERT(minX < maxX && minY < maxY); 3295 3296 for (int ky = minY; ky <= maxY; ky++) 3297 { 3298 for (int kx = minX; kx <= maxX; kx++) 3299 { 3300 const int sx = de::clamp(kx, 0, src.getWidth()-1); 3301 const int sy = de::clamp(ky, 0, src.getHeight()-1); 3302 const tcu::Vec4 sample = src.getPixel(sx, sy); 3303 3304 if (ky == minY && kx == minX) 3305 { 3306 minVal = sample; 3307 maxVal = sample; 3308 } 3309 else 3310 { 3311 minVal = min(sample, minVal); 3312 maxVal = max(sample, maxVal); 3313 } 3314 } 3315 } 3316 3317 isOk = boolAll(logicalAnd(lessThanEqual(minVal, result), lessThanEqual(result, maxVal))); 3318 3319 errorMask.setPixel(isOk ? tcu::RGBA::green.toVec() : tcu::RGBA::red.toVec(), x, y); 3320 if (!isOk) 3321 numFailed += 1; 3322 } 3323 3324 return numFailed; 3325} 3326 3327qpTestResult compareGenMipmapResult (tcu::TestLog& log, const tcu::Texture2D& resultTexture, const tcu::Texture2D& level0Reference, const GenMipmapPrecision& precision) 3328{ 3329 qpTestResult result = QP_TEST_RESULT_PASS; 3330 3331 // Special comparison for level 0. 3332 { 3333 const tcu::Vec4 threshold = select(precision.colorThreshold, tcu::Vec4(1.0f), precision.colorMask); 3334 const bool level0Ok = tcu::floatThresholdCompare(log, "Level0", "Level 0", level0Reference.getLevel(0), resultTexture.getLevel(0), threshold, tcu::COMPARE_LOG_RESULT); 3335 3336 if (!level0Ok) 3337 { 3338 log << TestLog::Message << "ERROR: Level 0 comparison failed!" << TestLog::EndMessage; 3339 result = QP_TEST_RESULT_FAIL; 3340 } 3341 } 3342 3343 for (int levelNdx = 1; levelNdx < resultTexture.getNumLevels(); levelNdx++) 3344 { 3345 const tcu::ConstPixelBufferAccess src = resultTexture.getLevel(levelNdx-1); 3346 const tcu::ConstPixelBufferAccess dst = resultTexture.getLevel(levelNdx); 3347 tcu::Surface errorMask (dst.getWidth(), dst.getHeight()); 3348 bool levelOk = false; 3349 3350 // Try different comparisons in quality order. 3351 3352 if (!levelOk) 3353 { 3354 const int numFailed = compareGenMipmapBilinear(dst, src, errorMask.getAccess(), precision); 3355 if (numFailed == 0) 3356 levelOk = true; 3357 else 3358 log << TestLog::Message << "WARNING: Level " << levelNdx << " comparison to bilinear method failed, found " << numFailed << " invalid pixels." << TestLog::EndMessage; 3359 } 3360 3361 if (!levelOk) 3362 { 3363 const int numFailed = compareGenMipmapBox(dst, src, errorMask.getAccess(), precision); 3364 if (numFailed == 0) 3365 levelOk = true; 3366 else 3367 log << TestLog::Message << "WARNING: Level " << levelNdx << " comparison to box method failed, found " << numFailed << " invalid pixels." << TestLog::EndMessage; 3368 } 3369 3370 // At this point all high-quality methods have been used. 3371 if (!levelOk && result == QP_TEST_RESULT_PASS) 3372 result = QP_TEST_RESULT_QUALITY_WARNING; 3373 3374 if (!levelOk) 3375 { 3376 const int numFailed = compareGenMipmapVeryLenient(dst, src, errorMask.getAccess(), precision); 3377 if (numFailed == 0) 3378 levelOk = true; 3379 else 3380 log << TestLog::Message << "ERROR: Level " << levelNdx << " appears to contain " << numFailed << " completely wrong pixels, failing case!" << TestLog::EndMessage; 3381 } 3382 3383 if (!levelOk) 3384 result = QP_TEST_RESULT_FAIL; 3385 3386 log << TestLog::ImageSet(string("Level") + de::toString(levelNdx), string("Level ") + de::toString(levelNdx) + " result") 3387 << TestLog::Image("Result", "Result", dst); 3388 3389 if (!levelOk) 3390 log << TestLog::Image("ErrorMask", "Error mask", errorMask); 3391 3392 log << TestLog::EndImageSet; 3393 } 3394 3395 return result; 3396} 3397 3398qpTestResult compareGenMipmapResult (tcu::TestLog& log, const tcu::TextureCube& resultTexture, const tcu::TextureCube& level0Reference, const GenMipmapPrecision& precision) 3399{ 3400 qpTestResult result = QP_TEST_RESULT_PASS; 3401 3402 static const char* s_faceNames[] = { "-X", "+X", "-Y", "+Y", "-Z", "+Z" }; 3403 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_faceNames) == tcu::CUBEFACE_LAST); 3404 3405 // Special comparison for level 0. 3406 for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; faceNdx++) 3407 { 3408 const tcu::CubeFace face = tcu::CubeFace(faceNdx); 3409 const tcu::Vec4 threshold = select(precision.colorThreshold, tcu::Vec4(1.0f), precision.colorMask); 3410 const bool level0Ok = tcu::floatThresholdCompare(log, 3411 ("Level0Face" + de::toString(faceNdx)).c_str(), 3412 (string("Level 0, face ") + s_faceNames[face]).c_str(), 3413 level0Reference.getLevelFace(0, face), 3414 resultTexture.getLevelFace(0, face), 3415 threshold, tcu::COMPARE_LOG_RESULT); 3416 3417 if (!level0Ok) 3418 { 3419 log << TestLog::Message << "ERROR: Level 0, face " << s_faceNames[face] << " comparison failed!" << TestLog::EndMessage; 3420 result = QP_TEST_RESULT_FAIL; 3421 } 3422 } 3423 3424 for (int levelNdx = 1; levelNdx < resultTexture.getNumLevels(); levelNdx++) 3425 { 3426 for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; faceNdx++) 3427 { 3428 const tcu::CubeFace face = tcu::CubeFace(faceNdx); 3429 const char* faceName = s_faceNames[face]; 3430 const tcu::ConstPixelBufferAccess src = resultTexture.getLevelFace(levelNdx-1, face); 3431 const tcu::ConstPixelBufferAccess dst = resultTexture.getLevelFace(levelNdx, face); 3432 tcu::Surface errorMask (dst.getWidth(), dst.getHeight()); 3433 bool levelOk = false; 3434 3435 // Try different comparisons in quality order. 3436 3437 if (!levelOk) 3438 { 3439 const int numFailed = compareGenMipmapBilinear(dst, src, errorMask.getAccess(), precision); 3440 if (numFailed == 0) 3441 levelOk = true; 3442 else 3443 log << TestLog::Message << "WARNING: Level " << levelNdx << ", face " << faceName << " comparison to bilinear method failed, found " << numFailed << " invalid pixels." << TestLog::EndMessage; 3444 } 3445 3446 if (!levelOk) 3447 { 3448 const int numFailed = compareGenMipmapBox(dst, src, errorMask.getAccess(), precision); 3449 if (numFailed == 0) 3450 levelOk = true; 3451 else 3452 log << TestLog::Message << "WARNING: Level " << levelNdx << ", face " << faceName <<" comparison to box method failed, found " << numFailed << " invalid pixels." << TestLog::EndMessage; 3453 } 3454 3455 // At this point all high-quality methods have been used. 3456 if (!levelOk && result == QP_TEST_RESULT_PASS) 3457 result = QP_TEST_RESULT_QUALITY_WARNING; 3458 3459 if (!levelOk) 3460 { 3461 const int numFailed = compareGenMipmapVeryLenient(dst, src, errorMask.getAccess(), precision); 3462 if (numFailed == 0) 3463 levelOk = true; 3464 else 3465 log << TestLog::Message << "ERROR: Level " << levelNdx << ", face " << faceName << " appears to contain " << numFailed << " completely wrong pixels, failing case!" << TestLog::EndMessage; 3466 } 3467 3468 if (!levelOk) 3469 result = QP_TEST_RESULT_FAIL; 3470 3471 log << TestLog::ImageSet(string("Level") + de::toString(levelNdx) + "Face" + de::toString(faceNdx), string("Level ") + de::toString(levelNdx) + ", face " + string(faceName) + " result") 3472 << TestLog::Image("Result", "Result", dst); 3473 3474 if (!levelOk) 3475 log << TestLog::Image("ErrorMask", "Error mask", errorMask); 3476 3477 log << TestLog::EndImageSet; 3478 } 3479 } 3480 3481 return result; 3482} 3483 3484// Logging utilities. 3485 3486std::ostream& operator<< (std::ostream& str, const LogGradientFmt& fmt) 3487{ 3488 return str << "(R: " << fmt.valueMin->x() << " -> " << fmt.valueMax->x() << ", " 3489 << "G: " << fmt.valueMin->y() << " -> " << fmt.valueMax->y() << ", " 3490 << "B: " << fmt.valueMin->z() << " -> " << fmt.valueMax->z() << ", " 3491 << "A: " << fmt.valueMin->w() << " -> " << fmt.valueMax->w() << ")"; 3492} 3493 3494} // TextureTestUtil 3495} // gls 3496} // deqp 3497