1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL (ES) Module
3 * -----------------------------------------------
5 * Copyright 2014 The Android Open Source Project
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 * \brief Texture test utilities.
22 *//*--------------------------------------------------------------------*/
24 #include "glsTextureTestUtil.hpp"
25 #include "gluDefs.hpp"
26 #include "gluDrawUtil.hpp"
27 #include "gluRenderContext.hpp"
28 #include "deRandom.hpp"
29 #include "tcuTestLog.hpp"
30 #include "tcuVectorUtil.hpp"
31 #include "tcuTextureUtil.hpp"
32 #include "tcuImageCompare.hpp"
33 #include "tcuStringTemplate.hpp"
34 #include "tcuTexLookupVerifier.hpp"
35 #include "tcuTexCompareVerifier.hpp"
36 #include "glwEnums.hpp"
37 #include "glwFunctions.hpp"
38 #include "qpWatchDog.h"
39 #include "deStringUtil.hpp"
50 namespace TextureTestUtil
58 SamplerType getSamplerType (tcu::TextureFormat format)
60 using tcu::TextureFormat;
64 case TextureFormat::SIGNED_INT8:
65 case TextureFormat::SIGNED_INT16:
66 case TextureFormat::SIGNED_INT32:
67 return SAMPLERTYPE_INT;
69 case TextureFormat::UNSIGNED_INT8:
70 case TextureFormat::UNSIGNED_INT32:
71 case TextureFormat::UNSIGNED_INT_1010102_REV:
72 return SAMPLERTYPE_UINT;
74 // Texture formats used in depth/stencil textures.
75 case TextureFormat::UNSIGNED_INT16:
76 case TextureFormat::UNSIGNED_INT_24_8:
77 return (format.order == TextureFormat::D || format.order == TextureFormat::DS) ? SAMPLERTYPE_FLOAT : SAMPLERTYPE_UINT;
80 return SAMPLERTYPE_FLOAT;
84 SamplerType getFetchSamplerType (tcu::TextureFormat format)
86 using tcu::TextureFormat;
90 case TextureFormat::SIGNED_INT8:
91 case TextureFormat::SIGNED_INT16:
92 case TextureFormat::SIGNED_INT32:
93 return SAMPLERTYPE_FETCH_INT;
95 case TextureFormat::UNSIGNED_INT8:
96 case TextureFormat::UNSIGNED_INT32:
97 case TextureFormat::UNSIGNED_INT_1010102_REV:
98 return SAMPLERTYPE_FETCH_UINT;
100 // Texture formats used in depth/stencil textures.
101 case TextureFormat::UNSIGNED_INT16:
102 case TextureFormat::UNSIGNED_INT_24_8:
103 return (format.order == TextureFormat::D || format.order == TextureFormat::DS) ? SAMPLERTYPE_FETCH_FLOAT : SAMPLERTYPE_FETCH_UINT;
106 return SAMPLERTYPE_FETCH_FLOAT;
110 static tcu::Texture1DView getSubView (const tcu::Texture1DView& view, int baseLevel, int maxLevel)
112 const int clampedBase = de::clamp(baseLevel, 0, view.getNumLevels()-1);
113 const int clampedMax = de::clamp(maxLevel, clampedBase, view.getNumLevels()-1);
114 const int numLevels = clampedMax-clampedBase+1;
115 return tcu::Texture1DView(numLevels, view.getLevels()+clampedBase);
118 static tcu::Texture2DView getSubView (const tcu::Texture2DView& view, int baseLevel, int maxLevel)
120 const int clampedBase = de::clamp(baseLevel, 0, view.getNumLevels()-1);
121 const int clampedMax = de::clamp(maxLevel, clampedBase, view.getNumLevels()-1);
122 const int numLevels = clampedMax-clampedBase+1;
123 return tcu::Texture2DView(numLevels, view.getLevels()+clampedBase);
126 static tcu::TextureCubeView getSubView (const tcu::TextureCubeView& view, int baseLevel, int maxLevel)
128 const int clampedBase = de::clamp(baseLevel, 0, view.getNumLevels()-1);
129 const int clampedMax = de::clamp(maxLevel, clampedBase, view.getNumLevels()-1);
130 const int numLevels = clampedMax-clampedBase+1;
131 const tcu::ConstPixelBufferAccess* levels[tcu::CUBEFACE_LAST];
133 for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
134 levels[face] = view.getFaceLevels((tcu::CubeFace)face) + clampedBase;
136 return tcu::TextureCubeView(numLevels, levels);
139 static tcu::Texture3DView getSubView (const tcu::Texture3DView& view, int baseLevel, int maxLevel)
141 const int clampedBase = de::clamp(baseLevel, 0, view.getNumLevels()-1);
142 const int clampedMax = de::clamp(maxLevel, clampedBase, view.getNumLevels()-1);
143 const int numLevels = clampedMax-clampedBase+1;
144 return tcu::Texture3DView(numLevels, view.getLevels()+clampedBase);
147 static tcu::TextureCubeArrayView getSubView (const tcu::TextureCubeArrayView& view, int baseLevel, int maxLevel)
149 const int clampedBase = de::clamp(baseLevel, 0, view.getNumLevels()-1);
150 const int clampedMax = de::clamp(maxLevel, clampedBase, view.getNumLevels()-1);
151 const int numLevels = clampedMax-clampedBase+1;
152 return tcu::TextureCubeArrayView(numLevels, view.getLevels()+clampedBase);
155 inline float linearInterpolate (float t, float minVal, float maxVal)
157 return minVal + (maxVal - minVal) * t;
160 inline tcu::Vec4 linearInterpolate (float t, const tcu::Vec4& a, const tcu::Vec4& b)
162 return a + (b - a) * t;
165 inline float bilinearInterpolate (float x, float y, const tcu::Vec4& quad)
167 float w00 = (1.0f-x)*(1.0f-y);
168 float w01 = (1.0f-x)*y;
169 float w10 = x*(1.0f-y);
171 return quad.x()*w00 + quad.y()*w10 + quad.z()*w01 + quad.w()*w11;
174 inline float triangleInterpolate (float v0, float v1, float v2, float x, float y)
176 return v0 + (v2-v0)*x + (v1-v0)*y;
179 inline float triangleInterpolate (const tcu::Vec3& v, float x, float y)
181 return triangleInterpolate(v.x(), v.y(), v.z(), x, y);
184 inline float triQuadInterpolate (float x, float y, const tcu::Vec4& quad)
186 // \note Top left fill rule.
188 return triangleInterpolate(quad.x(), quad.y(), quad.z(), x, y);
190 return triangleInterpolate(quad.w(), quad.z(), quad.y(), 1.0f-x, 1.0f-y);
193 SurfaceAccess::SurfaceAccess (tcu::Surface& surface, const tcu::PixelFormat& colorFmt, int x, int y, int width, int height)
194 : m_surface (&surface)
195 , m_colorMask (getColorMask(colorFmt))
203 SurfaceAccess::SurfaceAccess (tcu::Surface& surface, const tcu::PixelFormat& colorFmt)
204 : m_surface (&surface)
205 , m_colorMask (getColorMask(colorFmt))
208 , m_width (surface.getWidth())
209 , m_height (surface.getHeight())
213 SurfaceAccess::SurfaceAccess (const SurfaceAccess& parent, int x, int y, int width, int height)
214 : m_surface (parent.m_surface)
215 , m_colorMask (parent.m_colorMask)
216 , m_x (parent.m_x + x)
217 , m_y (parent.m_y + y)
223 // 1D lookup LOD computation.
225 inline float computeLodFromDerivates (LodMode mode, float dudx, float dudy)
230 // \note [mika] Min and max bounds equal to exact with 1D textures
232 case LODMODE_MIN_BOUND:
233 case LODMODE_MAX_BOUND:
234 p = de::max(deFloatAbs(dudx), deFloatAbs(dudy));
241 return deFloatLog2(p);
244 static float computeNonProjectedTriLod (LodMode mode, const tcu::IVec2& dstSize, deInt32 srcSize, const tcu::Vec3& sq)
246 float dux = (sq.z() - sq.x()) * (float)srcSize;
247 float duy = (sq.y() - sq.x()) * (float)srcSize;
248 float dx = (float)dstSize.x();
249 float dy = (float)dstSize.y();
251 return computeLodFromDerivates(mode, dux/dx, duy/dy);
254 // 2D lookup LOD computation.
256 inline float computeLodFromDerivates (LodMode mode, float dudx, float dvdx, float dudy, float dvdy)
262 p = de::max(deFloatSqrt(dudx*dudx + dvdx*dvdx), deFloatSqrt(dudy*dudy + dvdy*dvdy));
265 case LODMODE_MIN_BOUND:
266 case LODMODE_MAX_BOUND:
268 float mu = de::max(deFloatAbs(dudx), deFloatAbs(dudy));
269 float mv = de::max(deFloatAbs(dvdx), deFloatAbs(dvdy));
271 p = mode == LODMODE_MIN_BOUND ? de::max(mu, mv) : mu + mv;
279 return deFloatLog2(p);
282 static float computeNonProjectedTriLod (LodMode mode, const tcu::IVec2& dstSize, const tcu::IVec2& srcSize, const tcu::Vec3& sq, const tcu::Vec3& tq)
284 float dux = (sq.z() - sq.x()) * (float)srcSize.x();
285 float duy = (sq.y() - sq.x()) * (float)srcSize.x();
286 float dvx = (tq.z() - tq.x()) * (float)srcSize.y();
287 float dvy = (tq.y() - tq.x()) * (float)srcSize.y();
288 float dx = (float)dstSize.x();
289 float dy = (float)dstSize.y();
291 return computeLodFromDerivates(mode, dux/dx, dvx/dx, duy/dy, dvy/dy);
294 // 3D lookup LOD computation.
296 inline float computeLodFromDerivates (LodMode mode, float dudx, float dvdx, float dwdx, float dudy, float dvdy, float dwdy)
302 p = de::max(deFloatSqrt(dudx*dudx + dvdx*dvdx + dwdx*dwdx), deFloatSqrt(dudy*dudy + dvdy*dvdy + dwdy*dwdy));
305 case LODMODE_MIN_BOUND:
306 case LODMODE_MAX_BOUND:
308 float mu = de::max(deFloatAbs(dudx), deFloatAbs(dudy));
309 float mv = de::max(deFloatAbs(dvdx), deFloatAbs(dvdy));
310 float mw = de::max(deFloatAbs(dwdx), deFloatAbs(dwdy));
312 p = mode == LODMODE_MIN_BOUND ? de::max(de::max(mu, mv), mw) : (mu + mv + mw);
320 return deFloatLog2(p);
323 static float computeNonProjectedTriLod (LodMode mode, const tcu::IVec2& dstSize, const tcu::IVec3& srcSize, const tcu::Vec3& sq, const tcu::Vec3& tq, const tcu::Vec3& rq)
325 float dux = (sq.z() - sq.x()) * (float)srcSize.x();
326 float duy = (sq.y() - sq.x()) * (float)srcSize.x();
327 float dvx = (tq.z() - tq.x()) * (float)srcSize.y();
328 float dvy = (tq.y() - tq.x()) * (float)srcSize.y();
329 float dwx = (rq.z() - rq.x()) * (float)srcSize.z();
330 float dwy = (rq.y() - rq.x()) * (float)srcSize.z();
331 float dx = (float)dstSize.x();
332 float dy = (float)dstSize.y();
334 return computeLodFromDerivates(mode, dux/dx, dvx/dx, dwx/dx, duy/dy, dvy/dy, dwy/dy);
337 static inline float projectedTriInterpolate (const tcu::Vec3& s, const tcu::Vec3& w, float nx, float ny)
339 return (s[0]*(1.0f-nx-ny)/w[0] + s[1]*ny/w[1] + s[2]*nx/w[2]) / ((1.0f-nx-ny)/w[0] + ny/w[1] + nx/w[2]);
342 static inline float triDerivateX (const tcu::Vec3& s, const tcu::Vec3& w, float wx, float width, float ny)
344 float d = w[1]*w[2]*(width*(ny - 1.0f) + wx) - w[0]*(w[2]*width*ny + w[1]*wx);
345 return (w[0]*w[1]*w[2]*width * (w[1]*(s[0] - s[2])*(ny - 1.0f) + ny*(w[2]*(s[1] - s[0]) + w[0]*(s[2] - s[1])))) / (d*d);
348 static inline float triDerivateY (const tcu::Vec3& s, const tcu::Vec3& w, float wy, float height, float nx)
350 float d = w[1]*w[2]*(height*(nx - 1.0f) + wy) - w[0]*(w[1]*height*nx + w[2]*wy);
351 return (w[0]*w[1]*w[2]*height * (w[2]*(s[0] - s[1])*(nx - 1.0f) + nx*(w[0]*(s[1] - s[2]) + w[1]*(s[2] - s[0])))) / (d*d);
355 static float computeProjectedTriLod (LodMode mode, const tcu::Vec3& u, const tcu::Vec3& projection, float wx, float wy, float width, float height)
357 // Exact derivatives.
358 float dudx = triDerivateX(u, projection, wx, width, wy/height);
359 float dudy = triDerivateY(u, projection, wy, height, wx/width);
361 return computeLodFromDerivates(mode, dudx, dudy);
365 static float computeProjectedTriLod (LodMode mode, const tcu::Vec3& u, const tcu::Vec3& v, const tcu::Vec3& projection, float wx, float wy, float width, float height)
367 // Exact derivatives.
368 float dudx = triDerivateX(u, projection, wx, width, wy/height);
369 float dvdx = triDerivateX(v, projection, wx, width, wy/height);
370 float dudy = triDerivateY(u, projection, wy, height, wx/width);
371 float dvdy = triDerivateY(v, projection, wy, height, wx/width);
373 return computeLodFromDerivates(mode, dudx, dvdx, dudy, dvdy);
377 static float computeProjectedTriLod (LodMode mode, const tcu::Vec3& u, const tcu::Vec3& v, const tcu::Vec3& w, const tcu::Vec3& projection, float wx, float wy, float width, float height)
379 // Exact derivatives.
380 float dudx = triDerivateX(u, projection, wx, width, wy/height);
381 float dvdx = triDerivateX(v, projection, wx, width, wy/height);
382 float dwdx = triDerivateX(w, projection, wx, width, wy/height);
383 float dudy = triDerivateY(u, projection, wy, height, wx/width);
384 float dvdy = triDerivateY(v, projection, wy, height, wx/width);
385 float dwdy = triDerivateY(w, projection, wy, height, wx/width);
387 return computeLodFromDerivates(mode, dudx, dvdx, dwdx, dudy, dvdy, dwdy);
390 static inline tcu::Vec4 execSample (const tcu::Texture1DView& src, const ReferenceParams& params, float s, float lod)
392 if (params.samplerType == SAMPLERTYPE_SHADOW)
393 return tcu::Vec4(src.sampleCompare(params.sampler, params.ref, s, lod), 0.0, 0.0, 1.0f);
395 return src.sample(params.sampler, s, lod);
398 static inline tcu::Vec4 execSample (const tcu::Texture2DView& src, const ReferenceParams& params, float s, float t, float lod)
400 if (params.samplerType == SAMPLERTYPE_SHADOW)
401 return tcu::Vec4(src.sampleCompare(params.sampler, params.ref, s, t, lod), 0.0, 0.0, 1.0f);
403 return src.sample(params.sampler, s, t, lod);
406 static inline tcu::Vec4 execSample (const tcu::TextureCubeView& src, const ReferenceParams& params, float s, float t, float r, float lod)
408 if (params.samplerType == SAMPLERTYPE_SHADOW)
409 return tcu::Vec4(src.sampleCompare(params.sampler, params.ref, s, t, r, lod), 0.0, 0.0, 1.0f);
411 return src.sample(params.sampler, s, t, r, lod);
414 static inline tcu::Vec4 execSample (const tcu::Texture2DArrayView& src, const ReferenceParams& params, float s, float t, float r, float lod)
416 if (params.samplerType == SAMPLERTYPE_SHADOW)
417 return tcu::Vec4(src.sampleCompare(params.sampler, params.ref, s, t, r, lod), 0.0, 0.0, 1.0f);
419 return src.sample(params.sampler, s, t, r, lod);
422 static inline tcu::Vec4 execSample (const tcu::TextureCubeArrayView& src, const ReferenceParams& params, float s, float t, float r, float q, float lod)
424 if (params.samplerType == SAMPLERTYPE_SHADOW)
425 return tcu::Vec4(src.sampleCompare(params.sampler, params.ref, s, t, r, q, lod), 0.0, 0.0, 1.0f);
427 return src.sample(params.sampler, s, t, r, q, lod);
430 static inline tcu::Vec4 execSample (const tcu::Texture1DArrayView& src, const ReferenceParams& params, float s, float t, float lod)
432 if (params.samplerType == SAMPLERTYPE_SHADOW)
433 return tcu::Vec4(src.sampleCompare(params.sampler, params.ref, s, t, lod), 0.0, 0.0, 1.0f);
435 return src.sample(params.sampler, s, t, lod);
438 static void sampleTextureNonProjected (const SurfaceAccess& dst, const tcu::Texture1DView& src, const tcu::Vec4& sq, const ReferenceParams& params)
440 float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
442 tcu::IVec2 dstSize = tcu::IVec2(dst.getWidth(), dst.getHeight());
443 int srcSize = src.getWidth();
445 // Coordinates and lod per triangle.
446 tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
447 float triLod[2] = { de::clamp(computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[0]) + lodBias, params.minLod, params.maxLod),
448 de::clamp(computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[1]) + lodBias, params.minLod, params.maxLod) };
450 for (int y = 0; y < dst.getHeight(); y++)
452 for (int x = 0; x < dst.getWidth(); x++)
454 float yf = ((float)y + 0.5f) / (float)dst.getHeight();
455 float xf = ((float)x + 0.5f) / (float)dst.getWidth();
457 int triNdx = xf + yf >= 1.0f ? 1 : 0; // Top left fill rule.
458 float triX = triNdx ? 1.0f-xf : xf;
459 float triY = triNdx ? 1.0f-yf : yf;
461 float s = triangleInterpolate(triS[triNdx].x(), triS[triNdx].y(), triS[triNdx].z(), triX, triY);
462 float lod = triLod[triNdx];
464 dst.setPixel(execSample(src, params, s, lod) * params.colorScale + params.colorBias, x, y);
469 static void sampleTextureNonProjected (const SurfaceAccess& dst, const tcu::Texture2DView& src, const tcu::Vec4& sq, const tcu::Vec4& tq, const ReferenceParams& params)
471 float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
473 tcu::IVec2 dstSize = tcu::IVec2(dst.getWidth(), dst.getHeight());
474 tcu::IVec2 srcSize = tcu::IVec2(src.getWidth(), src.getHeight());
476 // Coordinates and lod per triangle.
477 tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
478 tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
479 float triLod[2] = { de::clamp(computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[0], triT[0]) + lodBias, params.minLod, params.maxLod),
480 de::clamp(computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[1], triT[1]) + lodBias, params.minLod, params.maxLod) };
482 for (int y = 0; y < dst.getHeight(); y++)
484 for (int x = 0; x < dst.getWidth(); x++)
486 float yf = ((float)y + 0.5f) / (float)dst.getHeight();
487 float xf = ((float)x + 0.5f) / (float)dst.getWidth();
489 int triNdx = xf + yf >= 1.0f ? 1 : 0; // Top left fill rule.
490 float triX = triNdx ? 1.0f-xf : xf;
491 float triY = triNdx ? 1.0f-yf : yf;
493 float s = triangleInterpolate(triS[triNdx].x(), triS[triNdx].y(), triS[triNdx].z(), triX, triY);
494 float t = triangleInterpolate(triT[triNdx].x(), triT[triNdx].y(), triT[triNdx].z(), triX, triY);
495 float lod = triLod[triNdx];
497 dst.setPixel(execSample(src, params, s, t, lod) * params.colorScale + params.colorBias, x, y);
502 static void sampleTextureProjected (const SurfaceAccess& dst, const tcu::Texture1DView& src, const tcu::Vec4& sq, const ReferenceParams& params)
504 float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
505 float dstW = (float)dst.getWidth();
506 float dstH = (float)dst.getHeight();
508 tcu::Vec4 uq = sq * (float)src.getWidth();
510 tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
511 tcu::Vec3 triU[2] = { uq.swizzle(0, 1, 2), uq.swizzle(3, 2, 1) };
512 tcu::Vec3 triW[2] = { params.w.swizzle(0, 1, 2), params.w.swizzle(3, 2, 1) };
514 for (int py = 0; py < dst.getHeight(); py++)
516 for (int px = 0; px < dst.getWidth(); px++)
518 float wx = (float)px + 0.5f;
519 float wy = (float)py + 0.5f;
520 float nx = wx / dstW;
521 float ny = wy / dstH;
523 int triNdx = nx + ny >= 1.0f ? 1 : 0;
524 float triWx = triNdx ? dstW - wx : wx;
525 float triWy = triNdx ? dstH - wy : wy;
526 float triNx = triNdx ? 1.0f - nx : nx;
527 float triNy = triNdx ? 1.0f - ny : ny;
529 float s = projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy);
530 float lod = computeProjectedTriLod(params.lodMode, triU[triNdx], triW[triNdx], triWx, triWy, (float)dst.getWidth(), (float)dst.getHeight())
533 dst.setPixel(execSample(src, params, s, lod) * params.colorScale + params.colorBias, px, py);
538 static void sampleTextureProjected (const SurfaceAccess& dst, const tcu::Texture2DView& src, const tcu::Vec4& sq, const tcu::Vec4& tq, const ReferenceParams& params)
540 float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
541 float dstW = (float)dst.getWidth();
542 float dstH = (float)dst.getHeight();
544 tcu::Vec4 uq = sq * (float)src.getWidth();
545 tcu::Vec4 vq = tq * (float)src.getHeight();
547 tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
548 tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
549 tcu::Vec3 triU[2] = { uq.swizzle(0, 1, 2), uq.swizzle(3, 2, 1) };
550 tcu::Vec3 triV[2] = { vq.swizzle(0, 1, 2), vq.swizzle(3, 2, 1) };
551 tcu::Vec3 triW[2] = { params.w.swizzle(0, 1, 2), params.w.swizzle(3, 2, 1) };
553 for (int py = 0; py < dst.getHeight(); py++)
555 for (int px = 0; px < dst.getWidth(); px++)
557 float wx = (float)px + 0.5f;
558 float wy = (float)py + 0.5f;
559 float nx = wx / dstW;
560 float ny = wy / dstH;
562 int triNdx = nx + ny >= 1.0f ? 1 : 0;
563 float triWx = triNdx ? dstW - wx : wx;
564 float triWy = triNdx ? dstH - wy : wy;
565 float triNx = triNdx ? 1.0f - nx : nx;
566 float triNy = triNdx ? 1.0f - ny : ny;
568 float s = projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy);
569 float t = projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy);
570 float lod = computeProjectedTriLod(params.lodMode, triU[triNdx], triV[triNdx], triW[triNdx], triWx, triWy, (float)dst.getWidth(), (float)dst.getHeight())
573 dst.setPixel(execSample(src, params, s, t, lod) * params.colorScale + params.colorBias, px, py);
578 void sampleTexture (const SurfaceAccess& dst, const tcu::Texture2DView& src, const float* texCoord, const ReferenceParams& params)
580 const tcu::Texture2DView view = getSubView(src, params.baseLevel, params.maxLevel);
581 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[2+0], texCoord[4+0], texCoord[6+0]);
582 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[2+1], texCoord[4+1], texCoord[6+1]);
584 if (params.flags & ReferenceParams::PROJECTED)
585 sampleTextureProjected(dst, view, sq, tq, params);
587 sampleTextureNonProjected(dst, view, sq, tq, params);
590 void sampleTexture (const SurfaceAccess& dst, const tcu::Texture1DView& src, const float* texCoord, const ReferenceParams& params)
592 const tcu::Texture1DView view = getSubView(src, params.baseLevel, params.maxLevel);
593 const tcu::Vec4 sq = tcu::Vec4(texCoord[0], texCoord[1], texCoord[2], texCoord[3]);
595 if (params.flags & ReferenceParams::PROJECTED)
596 sampleTextureProjected(dst, view, sq, params);
598 sampleTextureNonProjected(dst, view, sq, params);
601 static float computeCubeLodFromDerivates (LodMode lodMode, const tcu::Vec3& coord, const tcu::Vec3& coordDx, const tcu::Vec3& coordDy, const int faceSize)
603 const tcu::CubeFace face = tcu::selectCubeFace(coord);
608 // \note Derivate signs don't matter when computing lod
611 case tcu::CUBEFACE_NEGATIVE_X:
612 case tcu::CUBEFACE_POSITIVE_X: maNdx = 0; sNdx = 2; tNdx = 1; break;
613 case tcu::CUBEFACE_NEGATIVE_Y:
614 case tcu::CUBEFACE_POSITIVE_Y: maNdx = 1; sNdx = 0; tNdx = 2; break;
615 case tcu::CUBEFACE_NEGATIVE_Z:
616 case tcu::CUBEFACE_POSITIVE_Z: maNdx = 2; sNdx = 0; tNdx = 1; break;
622 const float sc = coord[sNdx];
623 const float tc = coord[tNdx];
624 const float ma = de::abs(coord[maNdx]);
625 const float scdx = coordDx[sNdx];
626 const float tcdx = coordDx[tNdx];
627 const float madx = de::abs(coordDx[maNdx]);
628 const float scdy = coordDy[sNdx];
629 const float tcdy = coordDy[tNdx];
630 const float mady = de::abs(coordDy[maNdx]);
631 const float dudx = float(faceSize) * 0.5f * (scdx*ma - sc*madx) / (ma*ma);
632 const float dvdx = float(faceSize) * 0.5f * (tcdx*ma - tc*madx) / (ma*ma);
633 const float dudy = float(faceSize) * 0.5f * (scdy*ma - sc*mady) / (ma*ma);
634 const float dvdy = float(faceSize) * 0.5f * (tcdy*ma - tc*mady) / (ma*ma);
636 return computeLodFromDerivates(lodMode, dudx, dvdx, dudy, dvdy);
640 static void sampleTexture (const SurfaceAccess& dst, const tcu::TextureCubeView& src, const tcu::Vec4& sq, const tcu::Vec4& tq, const tcu::Vec4& rq, const ReferenceParams& params)
642 const tcu::IVec2 dstSize = tcu::IVec2(dst.getWidth(), dst.getHeight());
643 const float dstW = float(dstSize.x());
644 const float dstH = float(dstSize.y());
645 const int srcSize = src.getSize();
647 // Coordinates per triangle.
648 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
649 const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
650 const tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
651 const tcu::Vec3 triW[2] = { params.w.swizzle(0, 1, 2), params.w.swizzle(3, 2, 1) };
653 const float lodBias ((params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f);
655 for (int py = 0; py < dst.getHeight(); py++)
657 for (int px = 0; px < dst.getWidth(); px++)
659 const float wx = (float)px + 0.5f;
660 const float wy = (float)py + 0.5f;
661 const float nx = wx / dstW;
662 const float ny = wy / dstH;
664 const int triNdx = nx + ny >= 1.0f ? 1 : 0;
665 const float triNx = triNdx ? 1.0f - nx : nx;
666 const float triNy = triNdx ? 1.0f - ny : ny;
668 const tcu::Vec3 coord (triangleInterpolate(triS[triNdx], triNx, triNy),
669 triangleInterpolate(triT[triNdx], triNx, triNy),
670 triangleInterpolate(triR[triNdx], triNx, triNy));
671 const tcu::Vec3 coordDx (triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
672 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy),
673 triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy));
674 const tcu::Vec3 coordDy (triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
675 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx),
676 triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx));
678 const float lod = de::clamp(computeCubeLodFromDerivates(params.lodMode, coord, coordDx, coordDy, srcSize) + lodBias, params.minLod, params.maxLod);
680 dst.setPixel(execSample(src, params, coord.x(), coord.y(), coord.z(), lod) * params.colorScale + params.colorBias, px, py);
685 void sampleTexture (const SurfaceAccess& dst, const tcu::TextureCubeView& src, const float* texCoord, const ReferenceParams& params)
687 const tcu::TextureCubeView view = getSubView(src, params.baseLevel, params.maxLevel);
688 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
689 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
690 const tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
692 return sampleTexture(dst, view, sq, tq, rq, params);
695 // \todo [2013-07-17 pyry] Remove this!
696 void sampleTextureMultiFace (const SurfaceAccess& dst, const tcu::TextureCubeView& src, const float* texCoord, const ReferenceParams& params)
698 return sampleTexture(dst, src, texCoord, params);
701 static void sampleTextureNonProjected (const SurfaceAccess& dst, const tcu::Texture2DArrayView& src, const tcu::Vec4& sq, const tcu::Vec4& tq, const tcu::Vec4& rq, const ReferenceParams& params)
703 float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
705 tcu::IVec2 dstSize = tcu::IVec2(dst.getWidth(), dst.getHeight());
706 tcu::IVec2 srcSize = tcu::IVec2(src.getWidth(), src.getHeight());
708 // Coordinates and lod per triangle.
709 tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
710 tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
711 tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
712 float triLod[2] = { computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[0], triT[0]) + lodBias,
713 computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[1], triT[1]) + lodBias};
715 for (int y = 0; y < dst.getHeight(); y++)
717 for (int x = 0; x < dst.getWidth(); x++)
719 float yf = ((float)y + 0.5f) / (float)dst.getHeight();
720 float xf = ((float)x + 0.5f) / (float)dst.getWidth();
722 int triNdx = xf + yf >= 1.0f ? 1 : 0; // Top left fill rule.
723 float triX = triNdx ? 1.0f-xf : xf;
724 float triY = triNdx ? 1.0f-yf : yf;
726 float s = triangleInterpolate(triS[triNdx].x(), triS[triNdx].y(), triS[triNdx].z(), triX, triY);
727 float t = triangleInterpolate(triT[triNdx].x(), triT[triNdx].y(), triT[triNdx].z(), triX, triY);
728 float r = triangleInterpolate(triR[triNdx].x(), triR[triNdx].y(), triR[triNdx].z(), triX, triY);
729 float lod = triLod[triNdx];
731 dst.setPixel(execSample(src, params, s, t, r, lod) * params.colorScale + params.colorBias, x, y);
736 void sampleTexture (const SurfaceAccess& dst, const tcu::Texture2DArrayView& src, const float* texCoord, const ReferenceParams& params)
738 tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
739 tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
740 tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
742 DE_ASSERT(!(params.flags & ReferenceParams::PROJECTED)); // \todo [2012-02-17 pyry] Support projected lookups.
743 sampleTextureNonProjected(dst, src, sq, tq, rq, params);
746 static void sampleTextureNonProjected (const SurfaceAccess& dst, const tcu::Texture1DArrayView& src, const tcu::Vec4& sq, const tcu::Vec4& tq, const ReferenceParams& params)
748 float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
750 tcu::IVec2 dstSize = tcu::IVec2(dst.getWidth(), dst.getHeight());
751 deInt32 srcSize = src.getWidth();
753 // Coordinates and lod per triangle.
754 tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
755 tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
756 float triLod[2] = { computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[0]) + lodBias,
757 computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[1]) + lodBias};
759 for (int y = 0; y < dst.getHeight(); y++)
761 for (int x = 0; x < dst.getWidth(); x++)
763 float yf = ((float)y + 0.5f) / (float)dst.getHeight();
764 float xf = ((float)x + 0.5f) / (float)dst.getWidth();
766 int triNdx = xf + yf >= 1.0f ? 1 : 0; // Top left fill rule.
767 float triX = triNdx ? 1.0f-xf : xf;
768 float triY = triNdx ? 1.0f-yf : yf;
770 float s = triangleInterpolate(triS[triNdx].x(), triS[triNdx].y(), triS[triNdx].z(), triX, triY);
771 float t = triangleInterpolate(triT[triNdx].x(), triT[triNdx].y(), triT[triNdx].z(), triX, triY);
772 float lod = triLod[triNdx];
774 dst.setPixel(execSample(src, params, s, t, lod) * params.colorScale + params.colorBias, x, y);
779 void sampleTexture (const SurfaceAccess& dst, const tcu::Texture1DArrayView& src, const float* texCoord, const ReferenceParams& params)
781 tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[2+0], texCoord[4+0], texCoord[6+0]);
782 tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[2+1], texCoord[4+1], texCoord[6+1]);
784 DE_ASSERT(!(params.flags & ReferenceParams::PROJECTED)); // \todo [2014-06-09 mika] Support projected lookups.
785 sampleTextureNonProjected(dst, src, sq, tq, params);
788 static void sampleTextureNonProjected (const SurfaceAccess& dst, const tcu::Texture3DView& src, const tcu::Vec4& sq, const tcu::Vec4& tq, const tcu::Vec4& rq, const ReferenceParams& params)
790 float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
792 tcu::IVec2 dstSize = tcu::IVec2(dst.getWidth(), dst.getHeight());
793 tcu::IVec3 srcSize = tcu::IVec3(src.getWidth(), src.getHeight(), src.getDepth());
795 // Coordinates and lod per triangle.
796 tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
797 tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
798 tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
799 float triLod[2] = { de::clamp(computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[0], triT[0], triR[0]) + lodBias, params.minLod, params.maxLod),
800 de::clamp(computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[1], triT[1], triR[1]) + lodBias, params.minLod, params.maxLod) };
802 for (int y = 0; y < dst.getHeight(); y++)
804 for (int x = 0; x < dst.getWidth(); x++)
806 float yf = ((float)y + 0.5f) / (float)dst.getHeight();
807 float xf = ((float)x + 0.5f) / (float)dst.getWidth();
809 int triNdx = xf + yf >= 1.0f ? 1 : 0; // Top left fill rule.
810 float triX = triNdx ? 1.0f-xf : xf;
811 float triY = triNdx ? 1.0f-yf : yf;
813 float s = triangleInterpolate(triS[triNdx].x(), triS[triNdx].y(), triS[triNdx].z(), triX, triY);
814 float t = triangleInterpolate(triT[triNdx].x(), triT[triNdx].y(), triT[triNdx].z(), triX, triY);
815 float r = triangleInterpolate(triR[triNdx].x(), triR[triNdx].y(), triR[triNdx].z(), triX, triY);
816 float lod = triLod[triNdx];
818 dst.setPixel(src.sample(params.sampler, s, t, r, lod) * params.colorScale + params.colorBias, x, y);
823 static void sampleTextureProjected (const SurfaceAccess& dst, const tcu::Texture3DView& src, const tcu::Vec4& sq, const tcu::Vec4& tq, const tcu::Vec4& rq, const ReferenceParams& params)
825 float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
826 float dstW = (float)dst.getWidth();
827 float dstH = (float)dst.getHeight();
829 tcu::Vec4 uq = sq * (float)src.getWidth();
830 tcu::Vec4 vq = tq * (float)src.getHeight();
831 tcu::Vec4 wq = rq * (float)src.getDepth();
833 tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
834 tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
835 tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
836 tcu::Vec3 triU[2] = { uq.swizzle(0, 1, 2), uq.swizzle(3, 2, 1) };
837 tcu::Vec3 triV[2] = { vq.swizzle(0, 1, 2), vq.swizzle(3, 2, 1) };
838 tcu::Vec3 triW[2] = { wq.swizzle(0, 1, 2), wq.swizzle(3, 2, 1) };
839 tcu::Vec3 triP[2] = { params.w.swizzle(0, 1, 2), params.w.swizzle(3, 2, 1) };
841 for (int py = 0; py < dst.getHeight(); py++)
843 for (int px = 0; px < dst.getWidth(); px++)
845 float wx = (float)px + 0.5f;
846 float wy = (float)py + 0.5f;
847 float nx = wx / dstW;
848 float ny = wy / dstH;
850 int triNdx = nx + ny >= 1.0f ? 1 : 0;
851 float triWx = triNdx ? dstW - wx : wx;
852 float triWy = triNdx ? dstH - wy : wy;
853 float triNx = triNdx ? 1.0f - nx : nx;
854 float triNy = triNdx ? 1.0f - ny : ny;
856 float s = projectedTriInterpolate(triS[triNdx], triP[triNdx], triNx, triNy);
857 float t = projectedTriInterpolate(triT[triNdx], triP[triNdx], triNx, triNy);
858 float r = projectedTriInterpolate(triR[triNdx], triP[triNdx], triNx, triNy);
859 float lod = computeProjectedTriLod(params.lodMode, triU[triNdx], triV[triNdx], triW[triNdx], triP[triNdx], triWx, triWy, (float)dst.getWidth(), (float)dst.getHeight())
862 dst.setPixel(src.sample(params.sampler, s, t, r, lod) * params.colorScale + params.colorBias, px, py);
867 void sampleTexture (const SurfaceAccess& dst, const tcu::Texture3DView& src, const float* texCoord, const ReferenceParams& params)
869 const tcu::Texture3DView view = getSubView(src, params.baseLevel, params.maxLevel);
870 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
871 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
872 const tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
874 if (params.flags & ReferenceParams::PROJECTED)
875 sampleTextureProjected(dst, view, sq, tq, rq, params);
877 sampleTextureNonProjected(dst, view, sq, tq, rq, params);
880 static void sampleTexture (const SurfaceAccess& dst, const tcu::TextureCubeArrayView& src, const tcu::Vec4& sq, const tcu::Vec4& tq, const tcu::Vec4& rq, const tcu::Vec4& qq, const ReferenceParams& params)
882 const float dstW = (float)dst.getWidth();
883 const float dstH = (float)dst.getHeight();
885 // Coordinates per triangle.
886 tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
887 tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
888 tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
889 tcu::Vec3 triQ[2] = { qq.swizzle(0, 1, 2), qq.swizzle(3, 2, 1) };
890 const tcu::Vec3 triW[2] = { params.w.swizzle(0, 1, 2), params.w.swizzle(3, 2, 1) };
892 const float lodBias = (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
894 for (int py = 0; py < dst.getHeight(); py++)
896 for (int px = 0; px < dst.getWidth(); px++)
898 const float wx = (float)px + 0.5f;
899 const float wy = (float)py + 0.5f;
900 const float nx = wx / dstW;
901 const float ny = wy / dstH;
903 const int triNdx = nx + ny >= 1.0f ? 1 : 0;
904 const float triNx = triNdx ? 1.0f - nx : nx;
905 const float triNy = triNdx ? 1.0f - ny : ny;
907 const tcu::Vec3 coord (triangleInterpolate(triS[triNdx], triNx, triNy),
908 triangleInterpolate(triT[triNdx], triNx, triNy),
909 triangleInterpolate(triR[triNdx], triNx, triNy));
911 const float coordQ = triangleInterpolate(triQ[triNdx], triNx, triNy);
913 const tcu::Vec3 coordDx (triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
914 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy),
915 triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy));
916 const tcu::Vec3 coordDy (triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
917 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx),
918 triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx));
920 const float lod = de::clamp(computeCubeLodFromDerivates(params.lodMode, coord, coordDx, coordDy, src.getSize()) + lodBias, params.minLod, params.maxLod);
922 dst.setPixel(execSample(src, params, coord.x(), coord.y(), coord.z(), coordQ, lod) * params.colorScale + params.colorBias, px, py);
927 void sampleTexture (const SurfaceAccess& dst, const tcu::TextureCubeArrayView& src, const float* texCoord, const ReferenceParams& params)
929 tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[4+0], texCoord[8+0], texCoord[12+0]);
930 tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[4+1], texCoord[8+1], texCoord[12+1]);
931 tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[4+2], texCoord[8+2], texCoord[12+2]);
932 tcu::Vec4 qq = tcu::Vec4(texCoord[0+3], texCoord[4+3], texCoord[8+3], texCoord[12+3]);
934 sampleTexture(dst, src, sq, tq, rq, qq, params);
937 void fetchTexture (const SurfaceAccess& dst, const tcu::ConstPixelBufferAccess& src, const float* texCoord, const tcu::Vec4& colorScale, const tcu::Vec4& colorBias)
939 const tcu::Vec4 sq = tcu::Vec4(texCoord[0], texCoord[1], texCoord[2], texCoord[3]);
940 const tcu::IVec2 dstSize = tcu::IVec2(dst.getWidth(), dst.getHeight());
941 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
943 for (int y = 0; y < dst.getHeight(); y++)
945 for (int x = 0; x < dst.getWidth(); x++)
947 const float yf = ((float)y + 0.5f) / (float)dst.getHeight();
948 const float xf = ((float)x + 0.5f) / (float)dst.getWidth();
950 const int triNdx = xf + yf >= 1.0f ? 1 : 0; // Top left fill rule.
951 const float triX = triNdx ? 1.0f-xf : xf;
952 const float triY = triNdx ? 1.0f-yf : yf;
954 const float s = triangleInterpolate(triS[triNdx].x(), triS[triNdx].y(), triS[triNdx].z(), triX, triY);
956 dst.setPixel(src.getPixel((int)s, 0) * colorScale + colorBias, x, y);
961 void clear (const SurfaceAccess& dst, const tcu::Vec4& color)
963 for (int y = 0; y < dst.getHeight(); y++)
964 for (int x = 0; x < dst.getWidth(); x++)
965 dst.setPixel(color, x, y);
968 bool compareImages (TestLog& log, const tcu::Surface& reference, const tcu::Surface& rendered, tcu::RGBA threshold)
970 return tcu::pixelThresholdCompare(log, "Result", "Image comparison result", reference, rendered, threshold, tcu::COMPARE_LOG_RESULT);
973 bool compareImages (TestLog& log, const char* name, const char* desc, const tcu::Surface& reference, const tcu::Surface& rendered, tcu::RGBA threshold)
975 return tcu::pixelThresholdCompare(log, name, desc, reference, rendered, threshold, tcu::COMPARE_LOG_RESULT);
978 int measureAccuracy (tcu::TestLog& log, const tcu::Surface& reference, const tcu::Surface& rendered, int bestScoreDiff, int worstScoreDiff)
980 return tcu::measurePixelDiffAccuracy(log, "Result", "Image comparison result", reference, rendered, bestScoreDiff, worstScoreDiff, tcu::COMPARE_LOG_EVERYTHING);
983 inline int rangeDiff (int x, int a, int b)
993 inline tcu::RGBA rangeDiff (tcu::RGBA p, tcu::RGBA a, tcu::RGBA b)
995 int rMin = de::min(a.getRed(), b.getRed());
996 int rMax = de::max(a.getRed(), b.getRed());
997 int gMin = de::min(a.getGreen(), b.getGreen());
998 int gMax = de::max(a.getGreen(), b.getGreen());
999 int bMin = de::min(a.getBlue(), b.getBlue());
1000 int bMax = de::max(a.getBlue(), b.getBlue());
1001 int aMin = de::min(a.getAlpha(), b.getAlpha());
1002 int aMax = de::max(a.getAlpha(), b.getAlpha());
1004 return tcu::RGBA(rangeDiff(p.getRed(), rMin, rMax),
1005 rangeDiff(p.getGreen(), gMin, gMax),
1006 rangeDiff(p.getBlue(), bMin, bMax),
1007 rangeDiff(p.getAlpha(), aMin, aMax));
1010 inline bool rangeCompare (tcu::RGBA p, tcu::RGBA a, tcu::RGBA b, tcu::RGBA threshold)
1012 tcu::RGBA diff = rangeDiff(p, a, b);
1013 return diff.getRed() <= threshold.getRed() &&
1014 diff.getGreen() <= threshold.getGreen() &&
1015 diff.getBlue() <= threshold.getBlue() &&
1016 diff.getAlpha() <= threshold.getAlpha();
1019 RandomViewport::RandomViewport (const tcu::RenderTarget& renderTarget, int preferredWidth, int preferredHeight, deUint32 seed)
1022 , width (deMin32(preferredWidth, renderTarget.getWidth()))
1023 , height (deMin32(preferredHeight, renderTarget.getHeight()))
1025 de::Random rnd(seed);
1026 x = rnd.getInt(0, renderTarget.getWidth() - width);
1027 y = rnd.getInt(0, renderTarget.getHeight() - height);
1030 ProgramLibrary::ProgramLibrary (const glu::RenderContext& context, tcu::TestContext& testCtx, glu::GLSLVersion glslVersion, glu::Precision texCoordPrecision)
1031 : m_context (context)
1032 , m_testCtx (testCtx)
1033 , m_glslVersion (glslVersion)
1034 , m_texCoordPrecision (texCoordPrecision)
1038 ProgramLibrary::~ProgramLibrary (void)
1043 void ProgramLibrary::clear (void)
1045 for (map<Program, glu::ShaderProgram*>::iterator i = m_programs.begin(); i != m_programs.end(); i++)
1048 i->second = DE_NULL;
1053 glu::ShaderProgram* ProgramLibrary::getProgram (Program program)
1055 TestLog& log = m_testCtx.getLog();
1057 if (m_programs.find(program) != m_programs.end())
1058 return m_programs[program]; // Return from cache.
1060 static const char* vertShaderTemplate =
1062 "${VTX_IN} highp vec4 a_position;\n"
1063 "${VTX_IN} ${PRECISION} ${TEXCOORD_TYPE} a_texCoord;\n"
1064 "${VTX_OUT} ${PRECISION} ${TEXCOORD_TYPE} v_texCoord;\n"
1066 "void main (void)\n"
1068 " gl_Position = a_position;\n"
1069 " v_texCoord = a_texCoord;\n"
1071 static const char* fragShaderTemplate =
1073 "${FRAG_IN} ${PRECISION} ${TEXCOORD_TYPE} v_texCoord;\n"
1074 "uniform ${PRECISION} float u_bias;\n"
1075 "uniform ${PRECISION} float u_ref;\n"
1076 "uniform ${PRECISION} vec4 u_colorScale;\n"
1077 "uniform ${PRECISION} vec4 u_colorBias;\n"
1078 "uniform ${PRECISION} ${SAMPLER_TYPE} u_sampler;\n"
1080 "void main (void)\n"
1082 " ${FRAG_COLOR} = ${LOOKUP} * u_colorScale + u_colorBias;\n"
1085 map<string, string> params;
1087 bool isCube = de::inRange<int>(program, PROGRAM_CUBE_FLOAT, PROGRAM_CUBE_SHADOW_BIAS);
1088 bool isArray = de::inRange<int>(program, PROGRAM_2D_ARRAY_FLOAT, PROGRAM_2D_ARRAY_SHADOW)
1089 || de::inRange<int>(program, PROGRAM_1D_ARRAY_FLOAT, PROGRAM_1D_ARRAY_SHADOW);
1091 bool is1D = de::inRange<int>(program, PROGRAM_1D_FLOAT, PROGRAM_1D_UINT_BIAS)
1092 || de::inRange<int>(program, PROGRAM_1D_ARRAY_FLOAT, PROGRAM_1D_ARRAY_SHADOW)
1093 || de::inRange<int>(program, PROGRAM_BUFFER_FLOAT, PROGRAM_BUFFER_UINT);
1095 bool is2D = de::inRange<int>(program, PROGRAM_2D_FLOAT, PROGRAM_2D_UINT_BIAS)
1096 || de::inRange<int>(program, PROGRAM_2D_ARRAY_FLOAT, PROGRAM_2D_ARRAY_SHADOW);
1098 bool is3D = de::inRange<int>(program, PROGRAM_3D_FLOAT, PROGRAM_3D_UINT_BIAS);
1099 bool isCubeArray = de::inRange<int>(program, PROGRAM_CUBE_ARRAY_FLOAT, PROGRAM_CUBE_ARRAY_SHADOW);
1100 bool isBuffer = de::inRange<int>(program, PROGRAM_BUFFER_FLOAT, PROGRAM_BUFFER_UINT);
1102 if (m_glslVersion == glu::GLSL_VERSION_100_ES)
1104 params["FRAG_HEADER"] = "";
1105 params["VTX_HEADER"] = "";
1106 params["VTX_IN"] = "attribute";
1107 params["VTX_OUT"] = "varying";
1108 params["FRAG_IN"] = "varying";
1109 params["FRAG_COLOR"] = "gl_FragColor";
1111 else if (m_glslVersion == glu::GLSL_VERSION_300_ES || m_glslVersion == glu::GLSL_VERSION_310_ES || m_glslVersion == glu::GLSL_VERSION_330)
1113 const string version = glu::getGLSLVersionDeclaration(m_glslVersion);
1114 const char* ext = DE_NULL;
1116 if (isCubeArray && glu::glslVersionIsES(m_glslVersion))
1117 ext = "GL_EXT_texture_cube_map_array";
1118 else if (isBuffer && glu::glslVersionIsES(m_glslVersion))
1119 ext = "GL_EXT_texture_buffer";
1121 params["FRAG_HEADER"] = version + (ext ? string("\n#extension ") + ext + " : require" : string()) + "\nlayout(location = 0) out mediump vec4 dEQP_FragColor;\n";
1122 params["VTX_HEADER"] = version + "\n";
1123 params["VTX_IN"] = "in";
1124 params["VTX_OUT"] = "out";
1125 params["FRAG_IN"] = "in";
1126 params["FRAG_COLOR"] = "dEQP_FragColor";
1129 DE_ASSERT(!"Unsupported version");
1131 params["PRECISION"] = glu::getPrecisionName(m_texCoordPrecision);
1134 params["TEXCOORD_TYPE"] = "vec4";
1135 else if (isCube || (is2D && isArray) || is3D)
1136 params["TEXCOORD_TYPE"] = "vec3";
1137 else if ((is1D && isArray) || is2D)
1138 params["TEXCOORD_TYPE"] = "vec2";
1140 params["TEXCOORD_TYPE"] = "float";
1142 DE_ASSERT(DE_FALSE);
1144 const char* sampler = DE_NULL;
1145 const char* lookup = DE_NULL;
1147 if (m_glslVersion == glu::GLSL_VERSION_300_ES || m_glslVersion == glu::GLSL_VERSION_310_ES || m_glslVersion == glu::GLSL_VERSION_330)
1151 case PROGRAM_2D_FLOAT: sampler = "sampler2D"; lookup = "texture(u_sampler, v_texCoord)"; break;
1152 case PROGRAM_2D_INT: sampler = "isampler2D"; lookup = "vec4(texture(u_sampler, v_texCoord))"; break;
1153 case PROGRAM_2D_UINT: sampler = "usampler2D"; lookup = "vec4(texture(u_sampler, v_texCoord))"; break;
1154 case PROGRAM_2D_SHADOW: sampler = "sampler2DShadow"; lookup = "vec4(texture(u_sampler, vec3(v_texCoord, u_ref)), 0.0, 0.0, 1.0)"; break;
1155 case PROGRAM_2D_FLOAT_BIAS: sampler = "sampler2D"; lookup = "texture(u_sampler, v_texCoord, u_bias)"; break;
1156 case PROGRAM_2D_INT_BIAS: sampler = "isampler2D"; lookup = "vec4(texture(u_sampler, v_texCoord, u_bias))"; break;
1157 case PROGRAM_2D_UINT_BIAS: sampler = "usampler2D"; lookup = "vec4(texture(u_sampler, v_texCoord, u_bias))"; break;
1158 case PROGRAM_2D_SHADOW_BIAS: sampler = "sampler2DShadow"; lookup = "vec4(texture(u_sampler, vec3(v_texCoord, u_ref), u_bias), 0.0, 0.0, 1.0)"; break;
1159 case PROGRAM_1D_FLOAT: sampler = "sampler1D"; lookup = "texture(u_sampler, v_texCoord)"; break;
1160 case PROGRAM_1D_INT: sampler = "isampler1D"; lookup = "vec4(texture(u_sampler, v_texCoord))"; break;
1161 case PROGRAM_1D_UINT: sampler = "usampler1D"; lookup = "vec4(texture(u_sampler, v_texCoord))"; break;
1162 case PROGRAM_1D_SHADOW: sampler = "sampler1DShadow"; lookup = "vec4(texture(u_sampler, vec3(v_texCoord, u_ref)), 0.0, 0.0, 1.0)"; break;
1163 case PROGRAM_1D_FLOAT_BIAS: sampler = "sampler1D"; lookup = "texture(u_sampler, v_texCoord, u_bias)"; break;
1164 case PROGRAM_1D_INT_BIAS: sampler = "isampler1D"; lookup = "vec4(texture(u_sampler, v_texCoord, u_bias))"; break;
1165 case PROGRAM_1D_UINT_BIAS: sampler = "usampler1D"; lookup = "vec4(texture(u_sampler, v_texCoord, u_bias))"; break;
1166 case PROGRAM_1D_SHADOW_BIAS: sampler = "sampler1DShadow"; lookup = "vec4(texture(u_sampler, vec3(v_texCoord, u_ref), u_bias), 0.0, 0.0, 1.0)"; break;
1167 case PROGRAM_CUBE_FLOAT: sampler = "samplerCube"; lookup = "texture(u_sampler, v_texCoord)"; break;
1168 case PROGRAM_CUBE_INT: sampler = "isamplerCube"; lookup = "vec4(texture(u_sampler, v_texCoord))"; break;
1169 case PROGRAM_CUBE_UINT: sampler = "usamplerCube"; lookup = "vec4(texture(u_sampler, v_texCoord))"; break;
1170 case PROGRAM_CUBE_SHADOW: sampler = "samplerCubeShadow"; lookup = "vec4(texture(u_sampler, vec4(v_texCoord, u_ref)), 0.0, 0.0, 1.0)"; break;
1171 case PROGRAM_CUBE_FLOAT_BIAS: sampler = "samplerCube"; lookup = "texture(u_sampler, v_texCoord, u_bias)"; break;
1172 case PROGRAM_CUBE_INT_BIAS: sampler = "isamplerCube"; lookup = "vec4(texture(u_sampler, v_texCoord, u_bias))"; break;
1173 case PROGRAM_CUBE_UINT_BIAS: sampler = "usamplerCube"; lookup = "vec4(texture(u_sampler, v_texCoord, u_bias))"; break;
1174 case PROGRAM_CUBE_SHADOW_BIAS: sampler = "samplerCubeShadow"; lookup = "vec4(texture(u_sampler, vec4(v_texCoord, u_ref), u_bias), 0.0, 0.0, 1.0)"; break;
1175 case PROGRAM_2D_ARRAY_FLOAT: sampler = "sampler2DArray"; lookup = "texture(u_sampler, v_texCoord)"; break;
1176 case PROGRAM_2D_ARRAY_INT: sampler = "isampler2DArray"; lookup = "vec4(texture(u_sampler, v_texCoord))"; break;
1177 case PROGRAM_2D_ARRAY_UINT: sampler = "usampler2DArray"; lookup = "vec4(texture(u_sampler, v_texCoord))"; break;
1178 case PROGRAM_2D_ARRAY_SHADOW: sampler = "sampler2DArrayShadow"; lookup = "vec4(texture(u_sampler, vec4(v_texCoord, u_ref)), 0.0, 0.0, 1.0)"; break;
1179 case PROGRAM_3D_FLOAT: sampler = "sampler3D"; lookup = "texture(u_sampler, v_texCoord)"; break;
1180 case PROGRAM_3D_INT: sampler = "isampler3D"; lookup = "vec4(texture(u_sampler, v_texCoord))"; break;
1181 case PROGRAM_3D_UINT: sampler =" usampler3D"; lookup = "vec4(texture(u_sampler, v_texCoord))"; break;
1182 case PROGRAM_3D_FLOAT_BIAS: sampler = "sampler3D"; lookup = "texture(u_sampler, v_texCoord, u_bias)"; break;
1183 case PROGRAM_3D_INT_BIAS: sampler = "isampler3D"; lookup = "vec4(texture(u_sampler, v_texCoord, u_bias))"; break;
1184 case PROGRAM_3D_UINT_BIAS: sampler =" usampler3D"; lookup = "vec4(texture(u_sampler, v_texCoord, u_bias))"; break;
1185 case PROGRAM_CUBE_ARRAY_FLOAT: sampler = "samplerCubeArray"; lookup = "texture(u_sampler, v_texCoord)"; break;
1186 case PROGRAM_CUBE_ARRAY_INT: sampler = "isamplerCubeArray"; lookup = "vec4(texture(u_sampler, v_texCoord))"; break;
1187 case PROGRAM_CUBE_ARRAY_UINT: sampler = "usamplerCubeArray"; lookup = "vec4(texture(u_sampler, v_texCoord))"; break;
1188 case PROGRAM_CUBE_ARRAY_SHADOW: sampler = "samplerCubeArrayShadow"; lookup = "vec4(texture(u_sampler, vec4(v_texCoord, u_ref)), 0.0, 0.0, 1.0)"; break;
1189 case PROGRAM_1D_ARRAY_FLOAT: sampler = "sampler1DArray"; lookup = "texture(u_sampler, v_texCoord)"; break;
1190 case PROGRAM_1D_ARRAY_INT: sampler = "isampler1DArray"; lookup = "vec4(texture(u_sampler, v_texCoord))"; break;
1191 case PROGRAM_1D_ARRAY_UINT: sampler = "usampler1DArray"; lookup = "vec4(texture(u_sampler, v_texCoord))"; break;
1192 case PROGRAM_1D_ARRAY_SHADOW: sampler = "sampler1DArrayShadow"; lookup = "vec4(texture(u_sampler, vec4(v_texCoord, u_ref)), 0.0, 0.0, 1.0)"; break;
1193 case PROGRAM_BUFFER_FLOAT: sampler = "samplerBuffer"; lookup = "texelFetch(u_sampler, int(v_texCoord))"; break;
1194 case PROGRAM_BUFFER_INT: sampler = "isamplerBuffer"; lookup = "vec4(texelFetch(u_sampler, int(v_texCoord)))"; break;
1195 case PROGRAM_BUFFER_UINT: sampler = "usamplerBuffer"; lookup = "vec4(texelFetch(u_sampler, int(v_texCoord)))"; break;
1200 else if (m_glslVersion == glu::GLSL_VERSION_100_ES)
1202 sampler = isCube ? "samplerCube" : "sampler2D";
1206 case PROGRAM_2D_FLOAT: lookup = "texture2D(u_sampler, v_texCoord)"; break;
1207 case PROGRAM_2D_FLOAT_BIAS: lookup = "texture2D(u_sampler, v_texCoord, u_bias)"; break;
1208 case PROGRAM_CUBE_FLOAT: lookup = "textureCube(u_sampler, v_texCoord)"; break;
1209 case PROGRAM_CUBE_FLOAT_BIAS: lookup = "textureCube(u_sampler, v_texCoord, u_bias)"; break;
1215 DE_ASSERT(!"Unsupported version");
1217 params["SAMPLER_TYPE"] = sampler;
1218 params["LOOKUP"] = lookup;
1220 std::string vertSrc = tcu::StringTemplate(vertShaderTemplate).specialize(params);
1221 std::string fragSrc = tcu::StringTemplate(fragShaderTemplate).specialize(params);
1223 glu::ShaderProgram* progObj = new glu::ShaderProgram(m_context, glu::makeVtxFragSources(vertSrc, fragSrc));
1224 if (!progObj->isOk())
1228 TCU_FAIL("Failed to compile shader program");
1233 m_programs[program] = progObj;
1244 TextureRenderer::TextureRenderer (const glu::RenderContext& context, tcu::TestContext& testCtx, glu::GLSLVersion glslVersion, glu::Precision texCoordPrecision)
1245 : m_renderCtx (context)
1246 , m_testCtx (testCtx)
1247 , m_programLibrary (context, testCtx, glslVersion, texCoordPrecision)
1251 TextureRenderer::~TextureRenderer (void)
1256 void TextureRenderer::clear (void)
1258 m_programLibrary.clear();
1261 void TextureRenderer::renderQuad (int texUnit, const float* texCoord, TextureType texType)
1263 renderQuad(texUnit, texCoord, RenderParams(texType));
1266 void TextureRenderer::renderQuad (int texUnit, const float* texCoord, const RenderParams& params)
1268 const glw::Functions& gl = m_renderCtx.getFunctions();
1269 tcu::Vec4 wCoord = params.flags & RenderParams::PROJECTED ? params.w : tcu::Vec4(1.0f);
1270 bool useBias = !!(params.flags & RenderParams::USE_BIAS);
1271 TestLog& log = m_testCtx.getLog();
1272 bool logUniforms = !!(params.flags & RenderParams::LOG_UNIFORMS);
1274 // Render quad with texture.
1277 -1.0f*wCoord.x(), -1.0f*wCoord.x(), 0.0f, wCoord.x(),
1278 -1.0f*wCoord.y(), +1.0f*wCoord.y(), 0.0f, wCoord.y(),
1279 +1.0f*wCoord.z(), -1.0f*wCoord.z(), 0.0f, wCoord.z(),
1280 +1.0f*wCoord.w(), +1.0f*wCoord.w(), 0.0f, wCoord.w()
1282 static const deUint16 indices[] = { 0, 1, 2, 2, 1, 3 };
1284 Program progSpec = PROGRAM_LAST;
1286 if (params.texType == TEXTURETYPE_2D)
1290 switch (params.samplerType)
1292 case SAMPLERTYPE_FLOAT: progSpec = useBias ? PROGRAM_2D_FLOAT_BIAS : PROGRAM_2D_FLOAT; break;
1293 case SAMPLERTYPE_INT: progSpec = useBias ? PROGRAM_2D_INT_BIAS : PROGRAM_2D_INT; break;
1294 case SAMPLERTYPE_UINT: progSpec = useBias ? PROGRAM_2D_UINT_BIAS : PROGRAM_2D_UINT; break;
1295 case SAMPLERTYPE_SHADOW: progSpec = useBias ? PROGRAM_2D_SHADOW_BIAS : PROGRAM_2D_SHADOW; break;
1296 default: DE_ASSERT(false);
1299 else if (params.texType == TEXTURETYPE_1D)
1303 switch (params.samplerType)
1305 case SAMPLERTYPE_FLOAT: progSpec = useBias ? PROGRAM_1D_FLOAT_BIAS : PROGRAM_1D_FLOAT; break;
1306 case SAMPLERTYPE_INT: progSpec = useBias ? PROGRAM_1D_INT_BIAS : PROGRAM_1D_INT; break;
1307 case SAMPLERTYPE_UINT: progSpec = useBias ? PROGRAM_1D_UINT_BIAS : PROGRAM_1D_UINT; break;
1308 case SAMPLERTYPE_SHADOW: progSpec = useBias ? PROGRAM_1D_SHADOW_BIAS : PROGRAM_1D_SHADOW; break;
1309 default: DE_ASSERT(false);
1312 else if (params.texType == TEXTURETYPE_CUBE)
1316 switch (params.samplerType)
1318 case SAMPLERTYPE_FLOAT: progSpec = useBias ? PROGRAM_CUBE_FLOAT_BIAS : PROGRAM_CUBE_FLOAT; break;
1319 case SAMPLERTYPE_INT: progSpec = useBias ? PROGRAM_CUBE_INT_BIAS : PROGRAM_CUBE_INT; break;
1320 case SAMPLERTYPE_UINT: progSpec = useBias ? PROGRAM_CUBE_UINT_BIAS : PROGRAM_CUBE_UINT; break;
1321 case SAMPLERTYPE_SHADOW: progSpec = useBias ? PROGRAM_CUBE_SHADOW_BIAS : PROGRAM_CUBE_SHADOW; break;
1322 default: DE_ASSERT(false);
1325 else if (params.texType == TEXTURETYPE_3D)
1329 switch (params.samplerType)
1331 case SAMPLERTYPE_FLOAT: progSpec = useBias ? PROGRAM_3D_FLOAT_BIAS : PROGRAM_3D_FLOAT; break;
1332 case SAMPLERTYPE_INT: progSpec = useBias ? PROGRAM_3D_INT_BIAS : PROGRAM_3D_INT; break;
1333 case SAMPLERTYPE_UINT: progSpec = useBias ? PROGRAM_3D_UINT_BIAS : PROGRAM_3D_UINT; break;
1334 default: DE_ASSERT(false);
1337 else if (params.texType == TEXTURETYPE_2D_ARRAY)
1339 DE_ASSERT(!useBias); // \todo [2012-02-17 pyry] Support bias.
1343 switch (params.samplerType)
1345 case SAMPLERTYPE_FLOAT: progSpec = PROGRAM_2D_ARRAY_FLOAT; break;
1346 case SAMPLERTYPE_INT: progSpec = PROGRAM_2D_ARRAY_INT; break;
1347 case SAMPLERTYPE_UINT: progSpec = PROGRAM_2D_ARRAY_UINT; break;
1348 case SAMPLERTYPE_SHADOW: progSpec = PROGRAM_2D_ARRAY_SHADOW; break;
1349 default: DE_ASSERT(false);
1352 else if (params.texType == TEXTURETYPE_CUBE_ARRAY)
1354 DE_ASSERT(!useBias);
1358 switch (params.samplerType)
1360 case SAMPLERTYPE_FLOAT: progSpec = PROGRAM_CUBE_ARRAY_FLOAT; break;
1361 case SAMPLERTYPE_INT: progSpec = PROGRAM_CUBE_ARRAY_INT; break;
1362 case SAMPLERTYPE_UINT: progSpec = PROGRAM_CUBE_ARRAY_UINT; break;
1363 case SAMPLERTYPE_SHADOW: progSpec = PROGRAM_CUBE_ARRAY_SHADOW; break;
1364 default: DE_ASSERT(false);
1367 else if (params.texType == TEXTURETYPE_1D_ARRAY)
1369 DE_ASSERT(!useBias); // \todo [2012-02-17 pyry] Support bias.
1373 switch (params.samplerType)
1375 case SAMPLERTYPE_FLOAT: progSpec = PROGRAM_1D_ARRAY_FLOAT; break;
1376 case SAMPLERTYPE_INT: progSpec = PROGRAM_1D_ARRAY_INT; break;
1377 case SAMPLERTYPE_UINT: progSpec = PROGRAM_1D_ARRAY_UINT; break;
1378 case SAMPLERTYPE_SHADOW: progSpec = PROGRAM_1D_ARRAY_SHADOW; break;
1379 default: DE_ASSERT(false);
1382 else if (params.texType == TEXTURETYPE_BUFFER)
1386 switch (params.samplerType)
1388 case SAMPLERTYPE_FETCH_FLOAT: progSpec = PROGRAM_BUFFER_FLOAT; break;
1389 case SAMPLERTYPE_FETCH_INT: progSpec = PROGRAM_BUFFER_INT; break;
1390 case SAMPLERTYPE_FETCH_UINT: progSpec = PROGRAM_BUFFER_UINT; break;
1391 default: DE_ASSERT(false);
1395 DE_ASSERT(DE_FALSE);
1397 glu::ShaderProgram* program = m_programLibrary.getProgram(progSpec);
1399 // \todo [2012-09-26 pyry] Move to ProgramLibrary and log unique programs only(?)
1400 if (params.flags & RenderParams::LOG_PROGRAMS)
1403 GLU_EXPECT_NO_ERROR(gl.getError(), "Set vertex attributes");
1405 // Program and uniforms.
1406 deUint32 prog = program->getProgram();
1407 gl.useProgram(prog);
1409 gl.uniform1i(gl.getUniformLocation(prog, "u_sampler"), texUnit);
1411 log << TestLog::Message << "u_sampler = " << texUnit << TestLog::EndMessage;
1415 gl.uniform1f(gl.getUniformLocation(prog, "u_bias"), params.bias);
1417 log << TestLog::Message << "u_bias = " << params.bias << TestLog::EndMessage;
1420 if (params.samplerType == SAMPLERTYPE_SHADOW)
1422 gl.uniform1f(gl.getUniformLocation(prog, "u_ref"), params.ref);
1424 log << TestLog::Message << "u_ref = " << params.ref << TestLog::EndMessage;
1427 gl.uniform4fv(gl.getUniformLocation(prog, "u_colorScale"), 1, params.colorScale.getPtr());
1428 gl.uniform4fv(gl.getUniformLocation(prog, "u_colorBias"), 1, params.colorBias.getPtr());
1432 log << TestLog::Message << "u_colorScale = " << params.colorScale << TestLog::EndMessage;
1433 log << TestLog::Message << "u_colorBias = " << params.colorBias << TestLog::EndMessage;
1436 GLU_EXPECT_NO_ERROR(gl.getError(), "Set program state");
1439 const glu::VertexArrayBinding vertexArrays[] =
1441 glu::va::Float("a_position", 4, 4, 0, &position[0]),
1442 glu::va::Float("a_texCoord", numComps, 4, 0, texCoord)
1444 glu::draw(m_renderCtx, prog, DE_LENGTH_OF_ARRAY(vertexArrays), &vertexArrays[0],
1445 glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indices), &indices[0]));
1449 void computeQuadTexCoord1D (std::vector<float>& dst, float left, float right)
1459 void computeQuadTexCoord1DArray (std::vector<float>& dst, int layerNdx, float left, float right)
1463 dst[0] = left; dst[1] = (float)layerNdx;
1464 dst[2] = left; dst[3] = (float)layerNdx;
1465 dst[4] = right; dst[5] = (float)layerNdx;
1466 dst[6] = right; dst[7] = (float)layerNdx;
1469 void computeQuadTexCoord2D (std::vector<float>& dst, const tcu::Vec2& bottomLeft, const tcu::Vec2& topRight)
1473 dst[0] = bottomLeft.x(); dst[1] = bottomLeft.y();
1474 dst[2] = bottomLeft.x(); dst[3] = topRight.y();
1475 dst[4] = topRight.x(); dst[5] = bottomLeft.y();
1476 dst[6] = topRight.x(); dst[7] = topRight.y();
1479 void computeQuadTexCoord2DArray (std::vector<float>& dst, int layerNdx, const tcu::Vec2& bottomLeft, const tcu::Vec2& topRight)
1483 dst[0] = bottomLeft.x(); dst[ 1] = bottomLeft.y(); dst[ 2] = (float)layerNdx;
1484 dst[3] = bottomLeft.x(); dst[ 4] = topRight.y(); dst[ 5] = (float)layerNdx;
1485 dst[6] = topRight.x(); dst[ 7] = bottomLeft.y(); dst[ 8] = (float)layerNdx;
1486 dst[9] = topRight.x(); dst[10] = topRight.y(); dst[11] = (float)layerNdx;
1489 void computeQuadTexCoord3D (std::vector<float>& dst, const tcu::Vec3& p0, const tcu::Vec3& p1, const tcu::IVec3& dirSwz)
1491 tcu::Vec3 f0 = tcu::Vec3(0.0f, 0.0f, 0.0f).swizzle(dirSwz[0], dirSwz[1], dirSwz[2]);
1492 tcu::Vec3 f1 = tcu::Vec3(0.0f, 1.0f, 0.0f).swizzle(dirSwz[0], dirSwz[1], dirSwz[2]);
1493 tcu::Vec3 f2 = tcu::Vec3(1.0f, 0.0f, 0.0f).swizzle(dirSwz[0], dirSwz[1], dirSwz[2]);
1494 tcu::Vec3 f3 = tcu::Vec3(1.0f, 1.0f, 0.0f).swizzle(dirSwz[0], dirSwz[1], dirSwz[2]);
1496 tcu::Vec3 v0 = p0 + (p1-p0)*f0;
1497 tcu::Vec3 v1 = p0 + (p1-p0)*f1;
1498 tcu::Vec3 v2 = p0 + (p1-p0)*f2;
1499 tcu::Vec3 v3 = p0 + (p1-p0)*f3;
1503 dst[0] = v0.x(); dst[ 1] = v0.y(); dst[ 2] = v0.z();
1504 dst[3] = v1.x(); dst[ 4] = v1.y(); dst[ 5] = v1.z();
1505 dst[6] = v2.x(); dst[ 7] = v2.y(); dst[ 8] = v2.z();
1506 dst[9] = v3.x(); dst[10] = v3.y(); dst[11] = v3.z();
1509 void computeQuadTexCoordCube (std::vector<float>& dst, tcu::CubeFace face)
1511 static const float texCoordNegX[] =
1514 -1.0f, -1.0f, -1.0f,
1518 static const float texCoordPosX[] =
1525 static const float texCoordNegY[] =
1528 -1.0f, -1.0f, -1.0f,
1532 static const float texCoordPosY[] =
1534 -1.0f, +1.0f, -1.0f,
1539 static const float texCoordNegZ[] =
1546 static const float texCoordPosZ[] =
1549 -1.0f, -1.0f, +1.0f,
1554 const float* texCoord = DE_NULL;
1555 int texCoordSize = DE_LENGTH_OF_ARRAY(texCoordNegX);
1559 case tcu::CUBEFACE_NEGATIVE_X: texCoord = texCoordNegX; break;
1560 case tcu::CUBEFACE_POSITIVE_X: texCoord = texCoordPosX; break;
1561 case tcu::CUBEFACE_NEGATIVE_Y: texCoord = texCoordNegY; break;
1562 case tcu::CUBEFACE_POSITIVE_Y: texCoord = texCoordPosY; break;
1563 case tcu::CUBEFACE_NEGATIVE_Z: texCoord = texCoordNegZ; break;
1564 case tcu::CUBEFACE_POSITIVE_Z: texCoord = texCoordPosZ; break;
1566 DE_ASSERT(DE_FALSE);
1570 dst.resize(texCoordSize);
1571 std::copy(texCoord, texCoord+texCoordSize, dst.begin());
1574 void computeQuadTexCoordCube (std::vector<float>& dst, tcu::CubeFace face, const tcu::Vec2& bottomLeft, const tcu::Vec2& topRight)
1585 case tcu::CUBEFACE_NEGATIVE_X: mRow = 0; sRow = 2; tRow = 1; mSign = -1.0f; tSign = -1.0f; break;
1586 case tcu::CUBEFACE_POSITIVE_X: mRow = 0; sRow = 2; tRow = 1; sSign = -1.0f; tSign = -1.0f; break;
1587 case tcu::CUBEFACE_NEGATIVE_Y: mRow = 1; sRow = 0; tRow = 2; mSign = -1.0f; tSign = -1.0f; break;
1588 case tcu::CUBEFACE_POSITIVE_Y: mRow = 1; sRow = 0; tRow = 2; break;
1589 case tcu::CUBEFACE_NEGATIVE_Z: mRow = 2; sRow = 0; tRow = 1; mSign = -1.0f; sSign = -1.0f; tSign = -1.0f; break;
1590 case tcu::CUBEFACE_POSITIVE_Z: mRow = 2; sRow = 0; tRow = 1; tSign = -1.0f; break;
1592 DE_ASSERT(DE_FALSE);
1598 dst[0+mRow] = mSign;
1599 dst[3+mRow] = mSign;
1600 dst[6+mRow] = mSign;
1601 dst[9+mRow] = mSign;
1603 dst[0+sRow] = sSign * bottomLeft.x();
1604 dst[3+sRow] = sSign * bottomLeft.x();
1605 dst[6+sRow] = sSign * topRight.x();
1606 dst[9+sRow] = sSign * topRight.x();
1608 dst[0+tRow] = tSign * bottomLeft.y();
1609 dst[3+tRow] = tSign * topRight.y();
1610 dst[6+tRow] = tSign * bottomLeft.y();
1611 dst[9+tRow] = tSign * topRight.y();
1614 void computeQuadTexCoordCubeArray (std::vector<float>& dst, tcu::CubeFace face, const tcu::Vec2& bottomLeft, const tcu::Vec2& topRight, const tcu::Vec2& layerRange)
1623 const float l0 = layerRange.x();
1624 const float l1 = layerRange.y();
1628 case tcu::CUBEFACE_NEGATIVE_X: mRow = 0; sRow = 2; tRow = 1; mSign = -1.0f; tSign = -1.0f; break;
1629 case tcu::CUBEFACE_POSITIVE_X: mRow = 0; sRow = 2; tRow = 1; sSign = -1.0f; tSign = -1.0f; break;
1630 case tcu::CUBEFACE_NEGATIVE_Y: mRow = 1; sRow = 0; tRow = 2; mSign = -1.0f; tSign = -1.0f; break;
1631 case tcu::CUBEFACE_POSITIVE_Y: mRow = 1; sRow = 0; tRow = 2; break;
1632 case tcu::CUBEFACE_NEGATIVE_Z: mRow = 2; sRow = 0; tRow = 1; mSign = -1.0f; sSign = -1.0f; tSign = -1.0f; break;
1633 case tcu::CUBEFACE_POSITIVE_Z: mRow = 2; sRow = 0; tRow = 1; tSign = -1.0f; break;
1635 DE_ASSERT(DE_FALSE);
1641 dst[ 0+mRow] = mSign;
1642 dst[ 4+mRow] = mSign;
1643 dst[ 8+mRow] = mSign;
1644 dst[12+mRow] = mSign;
1646 dst[ 0+sRow] = sSign * bottomLeft.x();
1647 dst[ 4+sRow] = sSign * bottomLeft.x();
1648 dst[ 8+sRow] = sSign * topRight.x();
1649 dst[12+sRow] = sSign * topRight.x();
1651 dst[ 0+tRow] = tSign * bottomLeft.y();
1652 dst[ 4+tRow] = tSign * topRight.y();
1653 dst[ 8+tRow] = tSign * bottomLeft.y();
1654 dst[12+tRow] = tSign * topRight.y();
1659 dst[ 4+qRow] = l0*0.5f + l1*0.5f;
1660 dst[ 8+qRow] = l0*0.5f + l1*0.5f;
1672 // Texture result verification
1674 //! Verifies texture lookup results and returns number of failed pixels.
1675 int computeTextureLookupDiff (const tcu::ConstPixelBufferAccess& result,
1676 const tcu::ConstPixelBufferAccess& reference,
1677 const tcu::PixelBufferAccess& errorMask,
1678 const tcu::Texture1DView& baseView,
1679 const float* texCoord,
1680 const ReferenceParams& sampleParams,
1681 const tcu::LookupPrecision& lookupPrec,
1682 const tcu::LodPrecision& lodPrec,
1683 qpWatchDog* watchDog)
1685 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
1686 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
1688 const tcu::Texture1DView src = getSubView(baseView, sampleParams.baseLevel, sampleParams.maxLevel);
1690 const tcu::Vec4 sq = tcu::Vec4(texCoord[0], texCoord[1], texCoord[2], texCoord[3]);
1692 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
1693 const float dstW = float(dstSize.x());
1694 const float dstH = float(dstSize.y());
1695 const int srcSize = src.getWidth();
1697 // Coordinates and lod per triangle.
1698 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
1699 const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
1701 const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
1705 const tcu::Vec2 lodOffsets[] =
1713 tcu::clear(errorMask, tcu::RGBA::green.toVec());
1715 for (int py = 0; py < result.getHeight(); py++)
1717 // Ugly hack, validation can take way too long at the moment.
1719 qpWatchDog_touch(watchDog);
1721 for (int px = 0; px < result.getWidth(); px++)
1723 const tcu::Vec4 resPix = (result.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
1724 const tcu::Vec4 refPix = (reference.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
1726 // Try comparison to ideal reference first, and if that fails use slower verificator.
1727 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
1729 const float wx = (float)px + 0.5f;
1730 const float wy = (float)py + 0.5f;
1731 const float nx = wx / dstW;
1732 const float ny = wy / dstH;
1734 const int triNdx = nx + ny >= 1.0f ? 1 : 0;
1735 const float triWx = triNdx ? dstW - wx : wx;
1736 const float triWy = triNdx ? dstH - wy : wy;
1737 const float triNx = triNdx ? 1.0f - nx : nx;
1738 const float triNy = triNdx ? 1.0f - ny : ny;
1740 const float coord = projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy);
1741 const float coordDx = triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy) * float(srcSize);
1742 const float coordDy = triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx) * float(srcSize);
1744 tcu::Vec2 lodBounds = tcu::computeLodBoundsFromDerivates(coordDx, coordDy, lodPrec);
1746 // Compute lod bounds across lodOffsets range.
1747 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
1749 const float wxo = triWx + lodOffsets[lodOffsNdx].x();
1750 const float wyo = triWy + lodOffsets[lodOffsNdx].y();
1751 const float nxo = wxo/dstW;
1752 const float nyo = wyo/dstH;
1754 const float coordDxo = triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo) * float(srcSize);
1755 const float coordDyo = triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo) * float(srcSize);
1756 const tcu::Vec2 lodO = tcu::computeLodBoundsFromDerivates(coordDxo, coordDyo, lodPrec);
1758 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
1759 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
1762 const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
1763 const bool isOk = tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix);
1767 errorMask.setPixel(tcu::RGBA::red.toVec(), px, py);
1777 int computeTextureLookupDiff (const tcu::ConstPixelBufferAccess& result,
1778 const tcu::ConstPixelBufferAccess& reference,
1779 const tcu::PixelBufferAccess& errorMask,
1780 const tcu::Texture2DView& baseView,
1781 const float* texCoord,
1782 const ReferenceParams& sampleParams,
1783 const tcu::LookupPrecision& lookupPrec,
1784 const tcu::LodPrecision& lodPrec,
1785 qpWatchDog* watchDog)
1787 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
1788 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
1790 const tcu::Texture2DView src = getSubView(baseView, sampleParams.baseLevel, sampleParams.maxLevel);
1792 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[2+0], texCoord[4+0], texCoord[6+0]);
1793 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[2+1], texCoord[4+1], texCoord[6+1]);
1795 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
1796 const float dstW = float(dstSize.x());
1797 const float dstH = float(dstSize.y());
1798 const tcu::IVec2 srcSize = tcu::IVec2(src.getWidth(), src.getHeight());
1800 // Coordinates and lod per triangle.
1801 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
1802 const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
1803 const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
1805 const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
1809 const tcu::Vec2 lodOffsets[] =
1817 tcu::clear(errorMask, tcu::RGBA::green.toVec());
1819 for (int py = 0; py < result.getHeight(); py++)
1821 // Ugly hack, validation can take way too long at the moment.
1823 qpWatchDog_touch(watchDog);
1825 for (int px = 0; px < result.getWidth(); px++)
1827 const tcu::Vec4 resPix = (result.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
1828 const tcu::Vec4 refPix = (reference.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
1830 // Try comparison to ideal reference first, and if that fails use slower verificator.
1831 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
1833 const float wx = (float)px + 0.5f;
1834 const float wy = (float)py + 0.5f;
1835 const float nx = wx / dstW;
1836 const float ny = wy / dstH;
1838 const int triNdx = nx + ny >= 1.0f ? 1 : 0;
1839 const float triWx = triNdx ? dstW - wx : wx;
1840 const float triWy = triNdx ? dstH - wy : wy;
1841 const float triNx = triNdx ? 1.0f - nx : nx;
1842 const float triNy = triNdx ? 1.0f - ny : ny;
1844 const tcu::Vec2 coord (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
1845 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy));
1846 const tcu::Vec2 coordDx = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
1847 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy)) * srcSize.asFloat();
1848 const tcu::Vec2 coordDy = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
1849 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx)) * srcSize.asFloat();
1851 tcu::Vec2 lodBounds = tcu::computeLodBoundsFromDerivates(coordDx.x(), coordDx.y(), coordDy.x(), coordDy.y(), lodPrec);
1853 // Compute lod bounds across lodOffsets range.
1854 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
1856 const float wxo = triWx + lodOffsets[lodOffsNdx].x();
1857 const float wyo = triWy + lodOffsets[lodOffsNdx].y();
1858 const float nxo = wxo/dstW;
1859 const float nyo = wyo/dstH;
1861 const tcu::Vec2 coordO (projectedTriInterpolate(triS[triNdx], triW[triNdx], nxo, nyo),
1862 projectedTriInterpolate(triT[triNdx], triW[triNdx], nxo, nyo));
1863 const tcu::Vec2 coordDxo = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
1864 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo)) * srcSize.asFloat();
1865 const tcu::Vec2 coordDyo = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
1866 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo)) * srcSize.asFloat();
1867 const tcu::Vec2 lodO = tcu::computeLodBoundsFromDerivates(coordDxo.x(), coordDxo.y(), coordDyo.x(), coordDyo.y(), lodPrec);
1869 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
1870 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
1873 const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
1874 const bool isOk = tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix);
1878 errorMask.setPixel(tcu::RGBA::red.toVec(), px, py);
1888 bool verifyTextureResult (tcu::TestContext& testCtx,
1889 const tcu::ConstPixelBufferAccess& result,
1890 const tcu::Texture1DView& src,
1891 const float* texCoord,
1892 const ReferenceParams& sampleParams,
1893 const tcu::LookupPrecision& lookupPrec,
1894 const tcu::LodPrecision& lodPrec,
1895 const tcu::PixelFormat& pixelFormat)
1897 tcu::TestLog& log = testCtx.getLog();
1898 tcu::Surface reference (result.getWidth(), result.getHeight());
1899 tcu::Surface errorMask (result.getWidth(), result.getHeight());
1900 int numFailedPixels;
1902 DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
1904 sampleTexture(SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
1905 numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog());
1907 if (numFailedPixels > 0)
1908 log << TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
1910 log << TestLog::ImageSet("VerifyResult", "Verification result")
1911 << TestLog::Image("Rendered", "Rendered image", result);
1913 if (numFailedPixels > 0)
1915 log << TestLog::Image("Reference", "Ideal reference image", reference)
1916 << TestLog::Image("ErrorMask", "Error mask", errorMask);
1919 log << TestLog::EndImageSet;
1921 return numFailedPixels == 0;
1924 bool verifyTextureResult (tcu::TestContext& testCtx,
1925 const tcu::ConstPixelBufferAccess& result,
1926 const tcu::Texture2DView& src,
1927 const float* texCoord,
1928 const ReferenceParams& sampleParams,
1929 const tcu::LookupPrecision& lookupPrec,
1930 const tcu::LodPrecision& lodPrec,
1931 const tcu::PixelFormat& pixelFormat)
1933 tcu::TestLog& log = testCtx.getLog();
1934 tcu::Surface reference (result.getWidth(), result.getHeight());
1935 tcu::Surface errorMask (result.getWidth(), result.getHeight());
1936 int numFailedPixels;
1938 DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
1940 sampleTexture(SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
1941 numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog());
1943 if (numFailedPixels > 0)
1944 log << TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
1946 log << TestLog::ImageSet("VerifyResult", "Verification result")
1947 << TestLog::Image("Rendered", "Rendered image", result);
1949 if (numFailedPixels > 0)
1951 log << TestLog::Image("Reference", "Ideal reference image", reference)
1952 << TestLog::Image("ErrorMask", "Error mask", errorMask);
1955 log << TestLog::EndImageSet;
1957 return numFailedPixels == 0;
1960 //! Verifies texture lookup results and returns number of failed pixels.
1961 int computeTextureLookupDiff (const tcu::ConstPixelBufferAccess& result,
1962 const tcu::ConstPixelBufferAccess& reference,
1963 const tcu::PixelBufferAccess& errorMask,
1964 const tcu::TextureCubeView& baseView,
1965 const float* texCoord,
1966 const ReferenceParams& sampleParams,
1967 const tcu::LookupPrecision& lookupPrec,
1968 const tcu::LodPrecision& lodPrec,
1969 qpWatchDog* watchDog)
1971 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
1972 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
1974 const tcu::TextureCubeView src = getSubView(baseView, sampleParams.baseLevel, sampleParams.maxLevel);
1976 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
1977 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
1978 const tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
1980 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
1981 const float dstW = float(dstSize.x());
1982 const float dstH = float(dstSize.y());
1983 const int srcSize = src.getSize();
1985 // Coordinates per triangle.
1986 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
1987 const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
1988 const tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
1989 const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
1991 const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
1993 const float posEps = 1.0f / float((1<<MIN_SUBPIXEL_BITS) + 1);
1997 const tcu::Vec2 lodOffsets[] =
2004 // \note Not strictly allowed by spec, but implementations do this in practice.
2011 tcu::clear(errorMask, tcu::RGBA::green.toVec());
2013 for (int py = 0; py < result.getHeight(); py++)
2015 // Ugly hack, validation can take way too long at the moment.
2017 qpWatchDog_touch(watchDog);
2019 for (int px = 0; px < result.getWidth(); px++)
2021 const tcu::Vec4 resPix = (result.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
2022 const tcu::Vec4 refPix = (reference.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
2024 // Try comparison to ideal reference first, and if that fails use slower verificator.
2025 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
2027 const float wx = (float)px + 0.5f;
2028 const float wy = (float)py + 0.5f;
2029 const float nx = wx / dstW;
2030 const float ny = wy / dstH;
2032 const bool tri0 = nx + ny - posEps <= 1.0f;
2033 const bool tri1 = nx + ny + posEps >= 1.0f;
2037 DE_ASSERT(tri0 || tri1);
2039 // Pixel can belong to either of the triangles if it lies close enough to the edge.
2040 for (int triNdx = (tri0?0:1); triNdx <= (tri1?1:0); triNdx++)
2042 const float triWx = triNdx ? dstW - wx : wx;
2043 const float triWy = triNdx ? dstH - wy : wy;
2044 const float triNx = triNdx ? 1.0f - nx : nx;
2045 const float triNy = triNdx ? 1.0f - ny : ny;
2047 const tcu::Vec3 coord (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
2048 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
2049 projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy));
2050 const tcu::Vec3 coordDx (triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
2051 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy),
2052 triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy));
2053 const tcu::Vec3 coordDy (triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
2054 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx),
2055 triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx));
2057 tcu::Vec2 lodBounds = tcu::computeCubeLodBoundsFromDerivates(coord, coordDx, coordDy, srcSize, lodPrec);
2059 // Compute lod bounds across lodOffsets range.
2060 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
2062 const float wxo = triWx + lodOffsets[lodOffsNdx].x();
2063 const float wyo = triWy + lodOffsets[lodOffsNdx].y();
2064 const float nxo = wxo/dstW;
2065 const float nyo = wyo/dstH;
2067 const tcu::Vec3 coordO (projectedTriInterpolate(triS[triNdx], triW[triNdx], nxo, nyo),
2068 projectedTriInterpolate(triT[triNdx], triW[triNdx], nxo, nyo),
2069 projectedTriInterpolate(triR[triNdx], triW[triNdx], nxo, nyo));
2070 const tcu::Vec3 coordDxo (triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
2071 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo),
2072 triDerivateX(triR[triNdx], triW[triNdx], wxo, dstW, nyo));
2073 const tcu::Vec3 coordDyo (triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
2074 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo),
2075 triDerivateY(triR[triNdx], triW[triNdx], wyo, dstH, nxo));
2076 const tcu::Vec2 lodO = tcu::computeCubeLodBoundsFromDerivates(coordO, coordDxo, coordDyo, srcSize, lodPrec);
2078 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
2079 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
2082 const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
2084 if (tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix))
2093 errorMask.setPixel(tcu::RGBA::red.toVec(), px, py);
2103 bool verifyTextureResult (tcu::TestContext& testCtx,
2104 const tcu::ConstPixelBufferAccess& result,
2105 const tcu::TextureCubeView& src,
2106 const float* texCoord,
2107 const ReferenceParams& sampleParams,
2108 const tcu::LookupPrecision& lookupPrec,
2109 const tcu::LodPrecision& lodPrec,
2110 const tcu::PixelFormat& pixelFormat)
2112 tcu::TestLog& log = testCtx.getLog();
2113 tcu::Surface reference (result.getWidth(), result.getHeight());
2114 tcu::Surface errorMask (result.getWidth(), result.getHeight());
2115 int numFailedPixels;
2117 DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
2119 sampleTextureMultiFace(SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
2120 numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog());
2122 if (numFailedPixels > 0)
2123 log << TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
2125 log << TestLog::ImageSet("VerifyResult", "Verification result")
2126 << TestLog::Image("Rendered", "Rendered image", result);
2128 if (numFailedPixels > 0)
2130 log << TestLog::Image("Reference", "Ideal reference image", reference)
2131 << TestLog::Image("ErrorMask", "Error mask", errorMask);
2134 log << TestLog::EndImageSet;
2136 return numFailedPixels == 0;
2139 //! Verifies texture lookup results and returns number of failed pixels.
2140 int computeTextureLookupDiff (const tcu::ConstPixelBufferAccess& result,
2141 const tcu::ConstPixelBufferAccess& reference,
2142 const tcu::PixelBufferAccess& errorMask,
2143 const tcu::Texture3DView& baseView,
2144 const float* texCoord,
2145 const ReferenceParams& sampleParams,
2146 const tcu::LookupPrecision& lookupPrec,
2147 const tcu::LodPrecision& lodPrec,
2148 qpWatchDog* watchDog)
2150 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
2151 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
2153 const tcu::Texture3DView src = getSubView(baseView, sampleParams.baseLevel, sampleParams.maxLevel);
2155 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
2156 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
2157 const tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
2159 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
2160 const float dstW = float(dstSize.x());
2161 const float dstH = float(dstSize.y());
2162 const tcu::IVec3 srcSize = tcu::IVec3(src.getWidth(), src.getHeight(), src.getDepth());
2164 // Coordinates and lod per triangle.
2165 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
2166 const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
2167 const tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
2168 const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
2170 const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
2172 const float posEps = 1.0f / float((1<<MIN_SUBPIXEL_BITS) + 1);
2176 const tcu::Vec2 lodOffsets[] =
2184 tcu::clear(errorMask, tcu::RGBA::green.toVec());
2186 for (int py = 0; py < result.getHeight(); py++)
2188 // Ugly hack, validation can take way too long at the moment.
2190 qpWatchDog_touch(watchDog);
2192 for (int px = 0; px < result.getWidth(); px++)
2194 const tcu::Vec4 resPix = (result.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
2195 const tcu::Vec4 refPix = (reference.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
2197 // Try comparison to ideal reference first, and if that fails use slower verificator.
2198 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
2200 const float wx = (float)px + 0.5f;
2201 const float wy = (float)py + 0.5f;
2202 const float nx = wx / dstW;
2203 const float ny = wy / dstH;
2205 const bool tri0 = nx + ny - posEps <= 1.0f;
2206 const bool tri1 = nx + ny + posEps >= 1.0f;
2210 DE_ASSERT(tri0 || tri1);
2212 // Pixel can belong to either of the triangles if it lies close enough to the edge.
2213 for (int triNdx = (tri0?0:1); triNdx <= (tri1?1:0); triNdx++)
2215 const float triWx = triNdx ? dstW - wx : wx;
2216 const float triWy = triNdx ? dstH - wy : wy;
2217 const float triNx = triNdx ? 1.0f - nx : nx;
2218 const float triNy = triNdx ? 1.0f - ny : ny;
2220 const tcu::Vec3 coord (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
2221 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
2222 projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy));
2223 const tcu::Vec3 coordDx = tcu::Vec3(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
2224 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy),
2225 triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy)) * srcSize.asFloat();
2226 const tcu::Vec3 coordDy = tcu::Vec3(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
2227 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx),
2228 triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx)) * srcSize.asFloat();
2230 tcu::Vec2 lodBounds = tcu::computeLodBoundsFromDerivates(coordDx.x(), coordDx.y(), coordDx.z(), coordDy.x(), coordDy.y(), coordDy.z(), lodPrec);
2232 // Compute lod bounds across lodOffsets range.
2233 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
2235 const float wxo = triWx + lodOffsets[lodOffsNdx].x();
2236 const float wyo = triWy + lodOffsets[lodOffsNdx].y();
2237 const float nxo = wxo/dstW;
2238 const float nyo = wyo/dstH;
2240 const tcu::Vec3 coordO (projectedTriInterpolate(triS[triNdx], triW[triNdx], nxo, nyo),
2241 projectedTriInterpolate(triT[triNdx], triW[triNdx], nxo, nyo),
2242 projectedTriInterpolate(triR[triNdx], triW[triNdx], nxo, nyo));
2243 const tcu::Vec3 coordDxo = tcu::Vec3(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
2244 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo),
2245 triDerivateX(triR[triNdx], triW[triNdx], wxo, dstW, nyo)) * srcSize.asFloat();
2246 const tcu::Vec3 coordDyo = tcu::Vec3(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
2247 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo),
2248 triDerivateY(triR[triNdx], triW[triNdx], wyo, dstH, nxo)) * srcSize.asFloat();
2249 const tcu::Vec2 lodO = tcu::computeLodBoundsFromDerivates(coordDxo.x(), coordDxo.y(), coordDxo.z(), coordDyo.x(), coordDyo.y(), coordDyo.z(), lodPrec);
2251 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
2252 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
2255 const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
2257 if (tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix))
2266 errorMask.setPixel(tcu::RGBA::red.toVec(), px, py);
2276 bool verifyTextureResult (tcu::TestContext& testCtx,
2277 const tcu::ConstPixelBufferAccess& result,
2278 const tcu::Texture3DView& src,
2279 const float* texCoord,
2280 const ReferenceParams& sampleParams,
2281 const tcu::LookupPrecision& lookupPrec,
2282 const tcu::LodPrecision& lodPrec,
2283 const tcu::PixelFormat& pixelFormat)
2285 tcu::TestLog& log = testCtx.getLog();
2286 tcu::Surface reference (result.getWidth(), result.getHeight());
2287 tcu::Surface errorMask (result.getWidth(), result.getHeight());
2288 int numFailedPixels;
2290 DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
2292 sampleTexture(SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
2293 numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog());
2295 if (numFailedPixels > 0)
2296 log << TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
2298 log << TestLog::ImageSet("VerifyResult", "Verification result")
2299 << TestLog::Image("Rendered", "Rendered image", result);
2301 if (numFailedPixels > 0)
2303 log << TestLog::Image("Reference", "Ideal reference image", reference)
2304 << TestLog::Image("ErrorMask", "Error mask", errorMask);
2307 log << TestLog::EndImageSet;
2309 return numFailedPixels == 0;
2312 //! Verifies texture lookup results and returns number of failed pixels.
2313 int computeTextureLookupDiff (const tcu::ConstPixelBufferAccess& result,
2314 const tcu::ConstPixelBufferAccess& reference,
2315 const tcu::PixelBufferAccess& errorMask,
2316 const tcu::Texture1DArrayView& src,
2317 const float* texCoord,
2318 const ReferenceParams& sampleParams,
2319 const tcu::LookupPrecision& lookupPrec,
2320 const tcu::LodPrecision& lodPrec,
2321 qpWatchDog* watchDog)
2323 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
2324 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
2326 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[2+0], texCoord[4+0], texCoord[6+0]);
2327 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[2+1], texCoord[4+1], texCoord[6+1]);
2329 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
2330 const float dstW = float(dstSize.x());
2331 const float dstH = float(dstSize.y());
2332 const float srcSize = float(src.getWidth()); // For lod computation, thus #layers is ignored.
2334 // Coordinates and lod per triangle.
2335 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
2336 const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
2337 const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
2339 const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
2343 const tcu::Vec2 lodOffsets[] =
2351 tcu::clear(errorMask, tcu::RGBA::green.toVec());
2353 for (int py = 0; py < result.getHeight(); py++)
2355 // Ugly hack, validation can take way too long at the moment.
2357 qpWatchDog_touch(watchDog);
2359 for (int px = 0; px < result.getWidth(); px++)
2361 const tcu::Vec4 resPix = (result.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
2362 const tcu::Vec4 refPix = (reference.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
2364 // Try comparison to ideal reference first, and if that fails use slower verificator.
2365 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
2367 const float wx = (float)px + 0.5f;
2368 const float wy = (float)py + 0.5f;
2369 const float nx = wx / dstW;
2370 const float ny = wy / dstH;
2372 const int triNdx = nx + ny >= 1.0f ? 1 : 0;
2373 const float triWx = triNdx ? dstW - wx : wx;
2374 const float triWy = triNdx ? dstH - wy : wy;
2375 const float triNx = triNdx ? 1.0f - nx : nx;
2376 const float triNy = triNdx ? 1.0f - ny : ny;
2378 const tcu::Vec2 coord (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
2379 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy));
2380 const float coordDx = triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy) * srcSize;
2381 const float coordDy = triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx) * srcSize;
2383 tcu::Vec2 lodBounds = tcu::computeLodBoundsFromDerivates(coordDx, coordDy, lodPrec);
2385 // Compute lod bounds across lodOffsets range.
2386 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
2388 const float wxo = triWx + lodOffsets[lodOffsNdx].x();
2389 const float wyo = triWy + lodOffsets[lodOffsNdx].y();
2390 const float nxo = wxo/dstW;
2391 const float nyo = wyo/dstH;
2393 const tcu::Vec2 coordO (projectedTriInterpolate(triS[triNdx], triW[triNdx], nxo, nyo),
2394 projectedTriInterpolate(triT[triNdx], triW[triNdx], nxo, nyo));
2395 const float coordDxo = triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo) * srcSize;
2396 const float coordDyo = triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo) * srcSize;
2397 const tcu::Vec2 lodO = tcu::computeLodBoundsFromDerivates(coordDxo, coordDyo, lodPrec);
2399 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
2400 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
2403 const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
2404 const bool isOk = tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix);
2408 errorMask.setPixel(tcu::RGBA::red.toVec(), px, py);
2418 //! Verifies texture lookup results and returns number of failed pixels.
2419 int computeTextureLookupDiff (const tcu::ConstPixelBufferAccess& result,
2420 const tcu::ConstPixelBufferAccess& reference,
2421 const tcu::PixelBufferAccess& errorMask,
2422 const tcu::Texture2DArrayView& src,
2423 const float* texCoord,
2424 const ReferenceParams& sampleParams,
2425 const tcu::LookupPrecision& lookupPrec,
2426 const tcu::LodPrecision& lodPrec,
2427 qpWatchDog* watchDog)
2429 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
2430 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
2432 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
2433 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
2434 const tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
2436 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
2437 const float dstW = float(dstSize.x());
2438 const float dstH = float(dstSize.y());
2439 const tcu::Vec2 srcSize = tcu::IVec2(src.getWidth(), src.getHeight()).asFloat(); // For lod computation, thus #layers is ignored.
2441 // Coordinates and lod per triangle.
2442 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
2443 const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
2444 const tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
2445 const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
2447 const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
2451 const tcu::Vec2 lodOffsets[] =
2459 tcu::clear(errorMask, tcu::RGBA::green.toVec());
2461 for (int py = 0; py < result.getHeight(); py++)
2463 // Ugly hack, validation can take way too long at the moment.
2465 qpWatchDog_touch(watchDog);
2467 for (int px = 0; px < result.getWidth(); px++)
2469 const tcu::Vec4 resPix = (result.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
2470 const tcu::Vec4 refPix = (reference.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
2472 // Try comparison to ideal reference first, and if that fails use slower verificator.
2473 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
2475 const float wx = (float)px + 0.5f;
2476 const float wy = (float)py + 0.5f;
2477 const float nx = wx / dstW;
2478 const float ny = wy / dstH;
2480 const int triNdx = nx + ny >= 1.0f ? 1 : 0;
2481 const float triWx = triNdx ? dstW - wx : wx;
2482 const float triWy = triNdx ? dstH - wy : wy;
2483 const float triNx = triNdx ? 1.0f - nx : nx;
2484 const float triNy = triNdx ? 1.0f - ny : ny;
2486 const tcu::Vec3 coord (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
2487 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
2488 projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy));
2489 const tcu::Vec2 coordDx = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
2490 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy)) * srcSize;
2491 const tcu::Vec2 coordDy = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
2492 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx)) * srcSize;
2494 tcu::Vec2 lodBounds = tcu::computeLodBoundsFromDerivates(coordDx.x(), coordDx.y(), coordDy.x(), coordDy.y(), lodPrec);
2496 // Compute lod bounds across lodOffsets range.
2497 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
2499 const float wxo = triWx + lodOffsets[lodOffsNdx].x();
2500 const float wyo = triWy + lodOffsets[lodOffsNdx].y();
2501 const float nxo = wxo/dstW;
2502 const float nyo = wyo/dstH;
2504 const tcu::Vec3 coordO (projectedTriInterpolate(triS[triNdx], triW[triNdx], nxo, nyo),
2505 projectedTriInterpolate(triT[triNdx], triW[triNdx], nxo, nyo),
2506 projectedTriInterpolate(triR[triNdx], triW[triNdx], nxo, nyo));
2507 const tcu::Vec2 coordDxo = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
2508 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo)) * srcSize;
2509 const tcu::Vec2 coordDyo = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
2510 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo)) * srcSize;
2511 const tcu::Vec2 lodO = tcu::computeLodBoundsFromDerivates(coordDxo.x(), coordDxo.y(), coordDyo.x(), coordDyo.y(), lodPrec);
2513 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
2514 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
2517 const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
2518 const bool isOk = tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix);
2522 errorMask.setPixel(tcu::RGBA::red.toVec(), px, py);
2532 bool verifyTextureResult (tcu::TestContext& testCtx,
2533 const tcu::ConstPixelBufferAccess& result,
2534 const tcu::Texture1DArrayView& src,
2535 const float* texCoord,
2536 const ReferenceParams& sampleParams,
2537 const tcu::LookupPrecision& lookupPrec,
2538 const tcu::LodPrecision& lodPrec,
2539 const tcu::PixelFormat& pixelFormat)
2541 tcu::TestLog& log = testCtx.getLog();
2542 tcu::Surface reference (result.getWidth(), result.getHeight());
2543 tcu::Surface errorMask (result.getWidth(), result.getHeight());
2544 int numFailedPixels;
2546 DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
2548 sampleTexture(SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
2549 numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog());
2551 if (numFailedPixels > 0)
2552 log << TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
2554 log << TestLog::ImageSet("VerifyResult", "Verification result")
2555 << TestLog::Image("Rendered", "Rendered image", result);
2557 if (numFailedPixels > 0)
2559 log << TestLog::Image("Reference", "Ideal reference image", reference)
2560 << TestLog::Image("ErrorMask", "Error mask", errorMask);
2563 log << TestLog::EndImageSet;
2565 return numFailedPixels == 0;
2568 bool verifyTextureResult (tcu::TestContext& testCtx,
2569 const tcu::ConstPixelBufferAccess& result,
2570 const tcu::Texture2DArrayView& src,
2571 const float* texCoord,
2572 const ReferenceParams& sampleParams,
2573 const tcu::LookupPrecision& lookupPrec,
2574 const tcu::LodPrecision& lodPrec,
2575 const tcu::PixelFormat& pixelFormat)
2577 tcu::TestLog& log = testCtx.getLog();
2578 tcu::Surface reference (result.getWidth(), result.getHeight());
2579 tcu::Surface errorMask (result.getWidth(), result.getHeight());
2580 int numFailedPixels;
2582 DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
2584 sampleTexture(SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
2585 numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog());
2587 if (numFailedPixels > 0)
2588 log << TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
2590 log << TestLog::ImageSet("VerifyResult", "Verification result")
2591 << TestLog::Image("Rendered", "Rendered image", result);
2593 if (numFailedPixels > 0)
2595 log << TestLog::Image("Reference", "Ideal reference image", reference)
2596 << TestLog::Image("ErrorMask", "Error mask", errorMask);
2599 log << TestLog::EndImageSet;
2601 return numFailedPixels == 0;
2604 //! Verifies texture lookup results and returns number of failed pixels.
2605 int computeTextureLookupDiff (const tcu::ConstPixelBufferAccess& result,
2606 const tcu::ConstPixelBufferAccess& reference,
2607 const tcu::PixelBufferAccess& errorMask,
2608 const tcu::TextureCubeArrayView& baseView,
2609 const float* texCoord,
2610 const ReferenceParams& sampleParams,
2611 const tcu::LookupPrecision& lookupPrec,
2612 const tcu::IVec4& coordBits,
2613 const tcu::LodPrecision& lodPrec,
2614 qpWatchDog* watchDog)
2616 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
2617 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
2619 const tcu::TextureCubeArrayView src = getSubView(baseView, sampleParams.baseLevel, sampleParams.maxLevel);
2621 // What is the 'q' in all these names? Also a two char name for something that is in scope for ~120 lines and only used twice each seems excessive
2622 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[4+0], texCoord[8+0], texCoord[12+0]);
2623 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[4+1], texCoord[8+1], texCoord[12+1]);
2624 const tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[4+2], texCoord[8+2], texCoord[12+2]);
2625 const tcu::Vec4 qq = tcu::Vec4(texCoord[0+3], texCoord[4+3], texCoord[8+3], texCoord[12+3]);
2627 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
2628 const float dstW = float(dstSize.x());
2629 const float dstH = float(dstSize.y());
2630 const int srcSize = src.getSize();
2632 // Coordinates per triangle.
2633 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
2634 const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
2635 const tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
2636 const tcu::Vec3 triQ[2] = { qq.swizzle(0, 1, 2), qq.swizzle(3, 2, 1) };
2637 const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
2639 const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
2641 const float posEps = 1.0f / float((1<<4) + 1); // ES3 requires at least 4 subpixel bits.
2645 const tcu::Vec2 lodOffsets[] =
2652 // \note Not strictly allowed by spec, but implementations do this in practice.
2659 tcu::clear(errorMask, tcu::RGBA::green.toVec());
2661 for (int py = 0; py < result.getHeight(); py++)
2663 // Ugly hack, validation can take way too long at the moment.
2665 qpWatchDog_touch(watchDog);
2667 for (int px = 0; px < result.getWidth(); px++)
2669 const tcu::Vec4 resPix = (result.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
2670 const tcu::Vec4 refPix = (reference.getPixel(px, py) - sampleParams.colorBias) / sampleParams.colorScale;
2672 // Try comparison to ideal reference first, and if that fails use slower verificator.
2673 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
2675 const float wx = (float)px + 0.5f;
2676 const float wy = (float)py + 0.5f;
2677 const float nx = wx / dstW;
2678 const float ny = wy / dstH;
2680 const bool tri0 = nx + ny - posEps <= 1.0f;
2681 const bool tri1 = nx + ny + posEps >= 1.0f;
2685 DE_ASSERT(tri0 || tri1);
2687 // Pixel can belong to either of the triangles if it lies close enough to the edge.
2688 for (int triNdx = (tri0?0:1); triNdx <= (tri1?1:0); triNdx++)
2690 const float triWx = triNdx ? dstW - wx : wx;
2691 const float triWy = triNdx ? dstH - wy : wy;
2692 const float triNx = triNdx ? 1.0f - nx : nx;
2693 const float triNy = triNdx ? 1.0f - ny : ny;
2695 const tcu::Vec4 coord (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
2696 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
2697 projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy),
2698 projectedTriInterpolate(triQ[triNdx], triW[triNdx], triNx, triNy));
2699 const tcu::Vec3 coordDx (triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
2700 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy),
2701 triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy));
2702 const tcu::Vec3 coordDy (triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
2703 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx),
2704 triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx));
2706 tcu::Vec2 lodBounds = tcu::computeCubeLodBoundsFromDerivates(coord.toWidth<3>(), coordDx, coordDy, srcSize, lodPrec);
2708 // Compute lod bounds across lodOffsets range.
2709 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
2711 const float wxo = triWx + lodOffsets[lodOffsNdx].x();
2712 const float wyo = triWy + lodOffsets[lodOffsNdx].y();
2713 const float nxo = wxo/dstW;
2714 const float nyo = wyo/dstH;
2716 const tcu::Vec3 coordO (projectedTriInterpolate(triS[triNdx], triW[triNdx], nxo, nyo),
2717 projectedTriInterpolate(triT[triNdx], triW[triNdx], nxo, nyo),
2718 projectedTriInterpolate(triR[triNdx], triW[triNdx], nxo, nyo));
2719 const tcu::Vec3 coordDxo (triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
2720 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo),
2721 triDerivateX(triR[triNdx], triW[triNdx], wxo, dstW, nyo));
2722 const tcu::Vec3 coordDyo (triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
2723 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo),
2724 triDerivateY(triR[triNdx], triW[triNdx], wyo, dstH, nxo));
2725 const tcu::Vec2 lodO = tcu::computeCubeLodBoundsFromDerivates(coordO, coordDxo, coordDyo, srcSize, lodPrec);
2727 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
2728 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
2731 const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
2733 if (tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coordBits, coord, clampedLod, resPix))
2742 errorMask.setPixel(tcu::RGBA::red.toVec(), px, py);
2752 bool verifyTextureResult (tcu::TestContext& testCtx,
2753 const tcu::ConstPixelBufferAccess& result,
2754 const tcu::TextureCubeArrayView& src,
2755 const float* texCoord,
2756 const ReferenceParams& sampleParams,
2757 const tcu::LookupPrecision& lookupPrec,
2758 const tcu::IVec4& coordBits,
2759 const tcu::LodPrecision& lodPrec,
2760 const tcu::PixelFormat& pixelFormat)
2762 tcu::TestLog& log = testCtx.getLog();
2763 tcu::Surface reference (result.getWidth(), result.getHeight());
2764 tcu::Surface errorMask (result.getWidth(), result.getHeight());
2765 int numFailedPixels;
2767 DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
2769 sampleTexture(SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
2770 numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, coordBits, lodPrec, testCtx.getWatchDog());
2772 if (numFailedPixels > 0)
2773 log << TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
2775 log << TestLog::ImageSet("VerifyResult", "Verification result")
2776 << TestLog::Image("Rendered", "Rendered image", result);
2778 if (numFailedPixels > 0)
2780 log << TestLog::Image("Reference", "Ideal reference image", reference)
2781 << TestLog::Image("ErrorMask", "Error mask", errorMask);
2784 log << TestLog::EndImageSet;
2786 return numFailedPixels == 0;
2789 // Shadow lookup verification
2791 int computeTextureCompareDiff (const tcu::ConstPixelBufferAccess& result,
2792 const tcu::ConstPixelBufferAccess& reference,
2793 const tcu::PixelBufferAccess& errorMask,
2794 const tcu::Texture2DView& src,
2795 const float* texCoord,
2796 const ReferenceParams& sampleParams,
2797 const tcu::TexComparePrecision& comparePrec,
2798 const tcu::LodPrecision& lodPrec,
2799 const tcu::Vec3& nonShadowThreshold)
2801 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
2802 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
2804 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[2+0], texCoord[4+0], texCoord[6+0]);
2805 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[2+1], texCoord[4+1], texCoord[6+1]);
2807 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
2808 const float dstW = float(dstSize.x());
2809 const float dstH = float(dstSize.y());
2810 const tcu::IVec2 srcSize = tcu::IVec2(src.getWidth(), src.getHeight());
2812 // Coordinates and lod per triangle.
2813 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
2814 const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
2815 const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
2817 const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
2821 const tcu::Vec2 lodOffsets[] =
2829 tcu::clear(errorMask, tcu::RGBA::green.toVec());
2831 for (int py = 0; py < result.getHeight(); py++)
2833 for (int px = 0; px < result.getWidth(); px++)
2835 const tcu::Vec4 resPix = result.getPixel(px, py);
2836 const tcu::Vec4 refPix = reference.getPixel(px, py);
2838 // Other channels should trivially match to reference.
2839 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(refPix.swizzle(1,2,3) - resPix.swizzle(1,2,3)), nonShadowThreshold)))
2841 errorMask.setPixel(tcu::RGBA::red.toVec(), px, py);
2847 const float wx = (float)px + 0.5f;
2848 const float wy = (float)py + 0.5f;
2849 const float nx = wx / dstW;
2850 const float ny = wy / dstH;
2852 const int triNdx = nx + ny >= 1.0f ? 1 : 0;
2853 const float triWx = triNdx ? dstW - wx : wx;
2854 const float triWy = triNdx ? dstH - wy : wy;
2855 const float triNx = triNdx ? 1.0f - nx : nx;
2856 const float triNy = triNdx ? 1.0f - ny : ny;
2858 const tcu::Vec2 coord (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
2859 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy));
2860 const tcu::Vec2 coordDx = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
2861 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy)) * srcSize.asFloat();
2862 const tcu::Vec2 coordDy = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
2863 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx)) * srcSize.asFloat();
2865 tcu::Vec2 lodBounds = tcu::computeLodBoundsFromDerivates(coordDx.x(), coordDx.y(), coordDy.x(), coordDy.y(), lodPrec);
2867 // Compute lod bounds across lodOffsets range.
2868 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
2870 const float wxo = triWx + lodOffsets[lodOffsNdx].x();
2871 const float wyo = triWy + lodOffsets[lodOffsNdx].y();
2872 const float nxo = wxo/dstW;
2873 const float nyo = wyo/dstH;
2875 const tcu::Vec2 coordO (projectedTriInterpolate(triS[triNdx], triW[triNdx], nxo, nyo),
2876 projectedTriInterpolate(triT[triNdx], triW[triNdx], nxo, nyo));
2877 const tcu::Vec2 coordDxo = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
2878 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo)) * srcSize.asFloat();
2879 const tcu::Vec2 coordDyo = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
2880 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo)) * srcSize.asFloat();
2881 const tcu::Vec2 lodO = tcu::computeLodBoundsFromDerivates(coordDxo.x(), coordDxo.y(), coordDyo.x(), coordDyo.y(), lodPrec);
2883 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
2884 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
2887 const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
2888 const bool isOk = tcu::isTexCompareResultValid(src, sampleParams.sampler, comparePrec, coord, clampedLod, sampleParams.ref, resPix.x());
2892 errorMask.setPixel(tcu::RGBA::red.toVec(), px, py);
2902 int computeTextureCompareDiff (const tcu::ConstPixelBufferAccess& result,
2903 const tcu::ConstPixelBufferAccess& reference,
2904 const tcu::PixelBufferAccess& errorMask,
2905 const tcu::TextureCubeView& src,
2906 const float* texCoord,
2907 const ReferenceParams& sampleParams,
2908 const tcu::TexComparePrecision& comparePrec,
2909 const tcu::LodPrecision& lodPrec,
2910 const tcu::Vec3& nonShadowThreshold)
2912 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
2913 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
2915 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
2916 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
2917 const tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
2919 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
2920 const float dstW = float(dstSize.x());
2921 const float dstH = float(dstSize.y());
2922 const int srcSize = src.getSize();
2924 // Coordinates per triangle.
2925 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
2926 const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
2927 const tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
2928 const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
2930 const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
2934 const tcu::Vec2 lodOffsets[] =
2942 tcu::clear(errorMask, tcu::RGBA::green.toVec());
2944 for (int py = 0; py < result.getHeight(); py++)
2946 for (int px = 0; px < result.getWidth(); px++)
2948 const tcu::Vec4 resPix = result.getPixel(px, py);
2949 const tcu::Vec4 refPix = reference.getPixel(px, py);
2951 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(refPix.swizzle(1,2,3) - resPix.swizzle(1,2,3)), nonShadowThreshold)))
2953 errorMask.setPixel(tcu::RGBA::red.toVec(), px, py);
2959 const float wx = (float)px + 0.5f;
2960 const float wy = (float)py + 0.5f;
2961 const float nx = wx / dstW;
2962 const float ny = wy / dstH;
2964 const int triNdx = nx + ny >= 1.0f ? 1 : 0;
2965 const float triWx = triNdx ? dstW - wx : wx;
2966 const float triWy = triNdx ? dstH - wy : wy;
2967 const float triNx = triNdx ? 1.0f - nx : nx;
2968 const float triNy = triNdx ? 1.0f - ny : ny;
2970 const tcu::Vec3 coord (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
2971 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
2972 projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy));
2973 const tcu::Vec3 coordDx (triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
2974 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy),
2975 triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy));
2976 const tcu::Vec3 coordDy (triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
2977 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx),
2978 triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx));
2980 tcu::Vec2 lodBounds = tcu::computeCubeLodBoundsFromDerivates(coord, coordDx, coordDy, srcSize, lodPrec);
2982 // Compute lod bounds across lodOffsets range.
2983 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
2985 const float wxo = triWx + lodOffsets[lodOffsNdx].x();
2986 const float wyo = triWy + lodOffsets[lodOffsNdx].y();
2987 const float nxo = wxo/dstW;
2988 const float nyo = wyo/dstH;
2990 const tcu::Vec3 coordO (projectedTriInterpolate(triS[triNdx], triW[triNdx], nxo, nyo),
2991 projectedTriInterpolate(triT[triNdx], triW[triNdx], nxo, nyo),
2992 projectedTriInterpolate(triR[triNdx], triW[triNdx], nxo, nyo));
2993 const tcu::Vec3 coordDxo (triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
2994 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo),
2995 triDerivateX(triR[triNdx], triW[triNdx], wxo, dstW, nyo));
2996 const tcu::Vec3 coordDyo (triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
2997 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo),
2998 triDerivateY(triR[triNdx], triW[triNdx], wyo, dstH, nxo));
2999 const tcu::Vec2 lodO = tcu::computeCubeLodBoundsFromDerivates(coordO, coordDxo, coordDyo, srcSize, lodPrec);
3001 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
3002 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
3005 const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
3006 const bool isOk = tcu::isTexCompareResultValid(src, sampleParams.sampler, comparePrec, coord, clampedLod, sampleParams.ref, resPix.x());
3010 errorMask.setPixel(tcu::RGBA::red.toVec(), px, py);
3020 int computeTextureCompareDiff (const tcu::ConstPixelBufferAccess& result,
3021 const tcu::ConstPixelBufferAccess& reference,
3022 const tcu::PixelBufferAccess& errorMask,
3023 const tcu::Texture2DArrayView& src,
3024 const float* texCoord,
3025 const ReferenceParams& sampleParams,
3026 const tcu::TexComparePrecision& comparePrec,
3027 const tcu::LodPrecision& lodPrec,
3028 const tcu::Vec3& nonShadowThreshold)
3030 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
3031 DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
3033 const tcu::Vec4 sq = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
3034 const tcu::Vec4 tq = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
3035 const tcu::Vec4 rq = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
3037 const tcu::IVec2 dstSize = tcu::IVec2(result.getWidth(), result.getHeight());
3038 const float dstW = float(dstSize.x());
3039 const float dstH = float(dstSize.y());
3040 const tcu::IVec2 srcSize = tcu::IVec2(src.getWidth(), src.getHeight());
3042 // Coordinates and lod per triangle.
3043 const tcu::Vec3 triS[2] = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
3044 const tcu::Vec3 triT[2] = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
3045 const tcu::Vec3 triR[2] = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
3046 const tcu::Vec3 triW[2] = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
3048 const tcu::Vec2 lodBias ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
3052 const tcu::Vec2 lodOffsets[] =
3060 tcu::clear(errorMask, tcu::RGBA::green.toVec());
3062 for (int py = 0; py < result.getHeight(); py++)
3064 for (int px = 0; px < result.getWidth(); px++)
3066 const tcu::Vec4 resPix = result.getPixel(px, py);
3067 const tcu::Vec4 refPix = reference.getPixel(px, py);
3069 if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(refPix.swizzle(1,2,3) - resPix.swizzle(1,2,3)), nonShadowThreshold)))
3071 errorMask.setPixel(tcu::RGBA::red.toVec(), px, py);
3077 const float wx = (float)px + 0.5f;
3078 const float wy = (float)py + 0.5f;
3079 const float nx = wx / dstW;
3080 const float ny = wy / dstH;
3082 const int triNdx = nx + ny >= 1.0f ? 1 : 0;
3083 const float triWx = triNdx ? dstW - wx : wx;
3084 const float triWy = triNdx ? dstH - wy : wy;
3085 const float triNx = triNdx ? 1.0f - nx : nx;
3086 const float triNy = triNdx ? 1.0f - ny : ny;
3088 const tcu::Vec3 coord (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
3089 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
3090 projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy));
3091 const tcu::Vec2 coordDx = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
3092 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy)) * srcSize.asFloat();
3093 const tcu::Vec2 coordDy = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
3094 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx)) * srcSize.asFloat();
3096 tcu::Vec2 lodBounds = tcu::computeLodBoundsFromDerivates(coordDx.x(), coordDx.y(), coordDy.x(), coordDy.y(), lodPrec);
3098 // Compute lod bounds across lodOffsets range.
3099 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
3101 const float wxo = triWx + lodOffsets[lodOffsNdx].x();
3102 const float wyo = triWy + lodOffsets[lodOffsNdx].y();
3103 const float nxo = wxo/dstW;
3104 const float nyo = wyo/dstH;
3106 const tcu::Vec2 coordO (projectedTriInterpolate(triS[triNdx], triW[triNdx], nxo, nyo),
3107 projectedTriInterpolate(triT[triNdx], triW[triNdx], nxo, nyo));
3108 const tcu::Vec2 coordDxo = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
3109 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo)) * srcSize.asFloat();
3110 const tcu::Vec2 coordDyo = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
3111 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo)) * srcSize.asFloat();
3112 const tcu::Vec2 lodO = tcu::computeLodBoundsFromDerivates(coordDxo.x(), coordDxo.y(), coordDyo.x(), coordDyo.y(), lodPrec);
3114 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
3115 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
3118 const tcu::Vec2 clampedLod = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
3119 const bool isOk = tcu::isTexCompareResultValid(src, sampleParams.sampler, comparePrec, coord, clampedLod, sampleParams.ref, resPix.x());
3123 errorMask.setPixel(tcu::RGBA::red.toVec(), px, py);
3133 // Mipmap generation comparison.
3135 static int compareGenMipmapBilinear (const tcu::ConstPixelBufferAccess& dst, const tcu::ConstPixelBufferAccess& src, const tcu::PixelBufferAccess& errorMask, const GenMipmapPrecision& precision)
3137 DE_ASSERT(dst.getDepth() == 1 && src.getDepth() == 1); // \todo [2013-10-29 pyry] 3D textures.
3139 const float dstW = float(dst.getWidth());
3140 const float dstH = float(dst.getHeight());
3141 const float srcW = float(src.getWidth());
3142 const float srcH = float(src.getHeight());
3145 // Translation to lookup verification parameters.
3146 const tcu::Sampler sampler (tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE,
3147 tcu::Sampler::LINEAR, tcu::Sampler::LINEAR, 0.0f, false /* non-normalized coords */);
3148 tcu::LookupPrecision lookupPrec;
3150 lookupPrec.colorThreshold = precision.colorThreshold;
3151 lookupPrec.colorMask = precision.colorMask;
3152 lookupPrec.coordBits = tcu::IVec3(22);
3153 lookupPrec.uvwBits = precision.filterBits;
3155 for (int y = 0; y < dst.getHeight(); y++)
3156 for (int x = 0; x < dst.getWidth(); x++)
3158 const tcu::Vec4 result = dst.getPixel(x, y);
3159 const float cx = (float(x)+0.5f) / dstW * srcW;
3160 const float cy = (float(y)+0.5f) / dstH * srcH;
3161 const bool isOk = tcu::isLinearSampleResultValid(src, sampler, lookupPrec, tcu::Vec2(cx, cy), 0, result);
3163 errorMask.setPixel(isOk ? tcu::RGBA::green.toVec() : tcu::RGBA::red.toVec(), x, y);
3171 static int compareGenMipmapBox (const tcu::ConstPixelBufferAccess& dst, const tcu::ConstPixelBufferAccess& src, const tcu::PixelBufferAccess& errorMask, const GenMipmapPrecision& precision)
3173 DE_ASSERT(dst.getDepth() == 1 && src.getDepth() == 1); // \todo [2013-10-29 pyry] 3D textures.
3175 const float dstW = float(dst.getWidth());
3176 const float dstH = float(dst.getHeight());
3177 const float srcW = float(src.getWidth());
3178 const float srcH = float(src.getHeight());
3181 // Translation to lookup verification parameters.
3182 const tcu::Sampler sampler (tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE,
3183 tcu::Sampler::LINEAR, tcu::Sampler::LINEAR, 0.0f, false /* non-normalized coords */);
3184 tcu::LookupPrecision lookupPrec;
3186 lookupPrec.colorThreshold = precision.colorThreshold;
3187 lookupPrec.colorMask = precision.colorMask;
3188 lookupPrec.coordBits = tcu::IVec3(22);
3189 lookupPrec.uvwBits = precision.filterBits;
3191 for (int y = 0; y < dst.getHeight(); y++)
3192 for (int x = 0; x < dst.getWidth(); x++)
3194 const tcu::Vec4 result = dst.getPixel(x, y);
3195 const float cx = deFloatFloor(float(x) / dstW * srcW) + 1.0f;
3196 const float cy = deFloatFloor(float(y) / dstH * srcH) + 1.0f;
3197 const bool isOk = tcu::isLinearSampleResultValid(src, sampler, lookupPrec, tcu::Vec2(cx, cy), 0, result);
3199 errorMask.setPixel(isOk ? tcu::RGBA::green.toVec() : tcu::RGBA::red.toVec(), x, y);
3207 static int compareGenMipmapVeryLenient (const tcu::ConstPixelBufferAccess& dst, const tcu::ConstPixelBufferAccess& src, const tcu::PixelBufferAccess& errorMask, const GenMipmapPrecision& precision)
3209 DE_ASSERT(dst.getDepth() == 1 && src.getDepth() == 1); // \todo [2013-10-29 pyry] 3D textures.
3210 DE_UNREF(precision);
3212 const float dstW = float(dst.getWidth());
3213 const float dstH = float(dst.getHeight());
3214 const float srcW = float(src.getWidth());
3215 const float srcH = float(src.getHeight());
3218 for (int y = 0; y < dst.getHeight(); y++)
3219 for (int x = 0; x < dst.getWidth(); x++)
3221 const tcu::Vec4 result = dst.getPixel(x, y);
3222 const int minX = deFloorFloatToInt32(float(x-0.5f) / dstW * srcW);
3223 const int minY = deFloorFloatToInt32(float(y-0.5f) / dstH * srcH);
3224 const int maxX = deCeilFloatToInt32(float(x+1.5f) / dstW * srcW);
3225 const int maxY = deCeilFloatToInt32(float(y+1.5f) / dstH * srcH);
3226 tcu::Vec4 minVal, maxVal;
3229 DE_ASSERT(minX < maxX && minY < maxY);
3231 for (int ky = minY; ky <= maxY; ky++)
3233 for (int kx = minX; kx <= maxX; kx++)
3235 const int sx = de::clamp(kx, 0, src.getWidth()-1);
3236 const int sy = de::clamp(ky, 0, src.getHeight()-1);
3237 const tcu::Vec4 sample = src.getPixel(sx, sy);
3239 if (ky == minY && kx == minX)
3246 minVal = min(sample, minVal);
3247 maxVal = max(sample, maxVal);
3252 isOk = boolAll(logicalAnd(lessThanEqual(minVal, result), lessThanEqual(result, maxVal)));
3254 errorMask.setPixel(isOk ? tcu::RGBA::green.toVec() : tcu::RGBA::red.toVec(), x, y);
3262 qpTestResult compareGenMipmapResult (tcu::TestLog& log, const tcu::Texture2D& resultTexture, const tcu::Texture2D& level0Reference, const GenMipmapPrecision& precision)
3264 qpTestResult result = QP_TEST_RESULT_PASS;
3266 // Special comparison for level 0.
3268 const tcu::Vec4 threshold = select(precision.colorThreshold, tcu::Vec4(1.0f), precision.colorMask);
3269 const bool level0Ok = tcu::floatThresholdCompare(log, "Level0", "Level 0", level0Reference.getLevel(0), resultTexture.getLevel(0), threshold, tcu::COMPARE_LOG_RESULT);
3273 log << TestLog::Message << "ERROR: Level 0 comparison failed!" << TestLog::EndMessage;
3274 result = QP_TEST_RESULT_FAIL;
3278 for (int levelNdx = 1; levelNdx < resultTexture.getNumLevels(); levelNdx++)
3280 const tcu::ConstPixelBufferAccess src = resultTexture.getLevel(levelNdx-1);
3281 const tcu::ConstPixelBufferAccess dst = resultTexture.getLevel(levelNdx);
3282 tcu::Surface errorMask (dst.getWidth(), dst.getHeight());
3283 bool levelOk = false;
3285 // Try different comparisons in quality order.
3289 const int numFailed = compareGenMipmapBilinear(dst, src, errorMask.getAccess(), precision);
3293 log << TestLog::Message << "WARNING: Level " << levelNdx << " comparison to bilinear method failed, found " << numFailed << " invalid pixels." << TestLog::EndMessage;
3298 const int numFailed = compareGenMipmapBox(dst, src, errorMask.getAccess(), precision);
3302 log << TestLog::Message << "WARNING: Level " << levelNdx << " comparison to box method failed, found " << numFailed << " invalid pixels." << TestLog::EndMessage;
3305 // At this point all high-quality methods have been used.
3306 if (!levelOk && result == QP_TEST_RESULT_PASS)
3307 result = QP_TEST_RESULT_QUALITY_WARNING;
3311 const int numFailed = compareGenMipmapVeryLenient(dst, src, errorMask.getAccess(), precision);
3315 log << TestLog::Message << "ERROR: Level " << levelNdx << " appears to contain " << numFailed << " completely wrong pixels, failing case!" << TestLog::EndMessage;
3319 result = QP_TEST_RESULT_FAIL;
3321 log << TestLog::ImageSet(string("Level") + de::toString(levelNdx), string("Level ") + de::toString(levelNdx) + " result")
3322 << TestLog::Image("Result", "Result", dst);
3325 log << TestLog::Image("ErrorMask", "Error mask", errorMask);
3327 log << TestLog::EndImageSet;
3333 qpTestResult compareGenMipmapResult (tcu::TestLog& log, const tcu::TextureCube& resultTexture, const tcu::TextureCube& level0Reference, const GenMipmapPrecision& precision)
3335 qpTestResult result = QP_TEST_RESULT_PASS;
3337 static const char* s_faceNames[] = { "-X", "+X", "-Y", "+Y", "-Z", "+Z" };
3338 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_faceNames) == tcu::CUBEFACE_LAST);
3340 // Special comparison for level 0.
3341 for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; faceNdx++)
3343 const tcu::CubeFace face = tcu::CubeFace(faceNdx);
3344 const tcu::Vec4 threshold = select(precision.colorThreshold, tcu::Vec4(1.0f), precision.colorMask);
3345 const bool level0Ok = tcu::floatThresholdCompare(log,
3346 ("Level0Face" + de::toString(faceNdx)).c_str(),
3347 (string("Level 0, face ") + s_faceNames[face]).c_str(),
3348 level0Reference.getLevelFace(0, face),
3349 resultTexture.getLevelFace(0, face),
3350 threshold, tcu::COMPARE_LOG_RESULT);
3354 log << TestLog::Message << "ERROR: Level 0, face " << s_faceNames[face] << " comparison failed!" << TestLog::EndMessage;
3355 result = QP_TEST_RESULT_FAIL;
3359 for (int levelNdx = 1; levelNdx < resultTexture.getNumLevels(); levelNdx++)
3361 for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; faceNdx++)
3363 const tcu::CubeFace face = tcu::CubeFace(faceNdx);
3364 const char* faceName = s_faceNames[face];
3365 const tcu::ConstPixelBufferAccess src = resultTexture.getLevelFace(levelNdx-1, face);
3366 const tcu::ConstPixelBufferAccess dst = resultTexture.getLevelFace(levelNdx, face);
3367 tcu::Surface errorMask (dst.getWidth(), dst.getHeight());
3368 bool levelOk = false;
3370 // Try different comparisons in quality order.
3374 const int numFailed = compareGenMipmapBilinear(dst, src, errorMask.getAccess(), precision);
3378 log << TestLog::Message << "WARNING: Level " << levelNdx << ", face " << faceName << " comparison to bilinear method failed, found " << numFailed << " invalid pixels." << TestLog::EndMessage;
3383 const int numFailed = compareGenMipmapBox(dst, src, errorMask.getAccess(), precision);
3387 log << TestLog::Message << "WARNING: Level " << levelNdx << ", face " << faceName <<" comparison to box method failed, found " << numFailed << " invalid pixels." << TestLog::EndMessage;
3390 // At this point all high-quality methods have been used.
3391 if (!levelOk && result == QP_TEST_RESULT_PASS)
3392 result = QP_TEST_RESULT_QUALITY_WARNING;
3396 const int numFailed = compareGenMipmapVeryLenient(dst, src, errorMask.getAccess(), precision);
3400 log << TestLog::Message << "ERROR: Level " << levelNdx << ", face " << faceName << " appears to contain " << numFailed << " completely wrong pixels, failing case!" << TestLog::EndMessage;
3404 result = QP_TEST_RESULT_FAIL;
3406 log << TestLog::ImageSet(string("Level") + de::toString(levelNdx) + "Face" + de::toString(faceNdx), string("Level ") + de::toString(levelNdx) + ", face " + string(faceName) + " result")
3407 << TestLog::Image("Result", "Result", dst);
3410 log << TestLog::Image("ErrorMask", "Error mask", errorMask);
3412 log << TestLog::EndImageSet;
3419 // Logging utilities.
3421 std::ostream& operator<< (std::ostream& str, const LogGradientFmt& fmt)
3423 return str << "(R: " << fmt.valueMin->x() << " -> " << fmt.valueMax->x() << ", "
3424 << "G: " << fmt.valueMin->y() << " -> " << fmt.valueMax->y() << ", "
3425 << "B: " << fmt.valueMin->z() << " -> " << fmt.valueMax->z() << ", "
3426 << "A: " << fmt.valueMin->w() << " -> " << fmt.valueMax->w() << ")";
3429 } // TextureTestUtil