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