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