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