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