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