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