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