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