Use correct, stricter coverage variation thresholds in texture tests
[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::IVec2        dstSize         = tcu::IVec2(dst.getWidth(), dst.getHeight());
941         const tcu::Vec3         triS[2]         = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
942
943         for (int y = 0; y < dst.getHeight(); y++)
944         {
945                 for (int x = 0; x < dst.getWidth(); x++)
946                 {
947                         const float     yf              = ((float)y + 0.5f) / (float)dst.getHeight();
948                         const float     xf              = ((float)x + 0.5f) / (float)dst.getWidth();
949
950                         const int       triNdx  = xf + yf >= 1.0f ? 1 : 0; // Top left fill rule.
951                         const float     triX    = triNdx ? 1.0f-xf : xf;
952                         const float     triY    = triNdx ? 1.0f-yf : yf;
953
954                         const float     s               = triangleInterpolate(triS[triNdx].x(), triS[triNdx].y(), triS[triNdx].z(), triX, triY);
955
956                         dst.setPixel(src.getPixel((int)s, 0) * colorScale + colorBias, x, y);
957                 }
958         }
959 }
960
961 void clear (const SurfaceAccess& dst, const tcu::Vec4& color)
962 {
963         for (int y = 0; y < dst.getHeight(); y++)
964                 for (int x = 0; x < dst.getWidth(); x++)
965                         dst.setPixel(color, x, y);
966 }
967
968 bool compareImages (TestLog& log, const tcu::Surface& reference, const tcu::Surface& rendered, tcu::RGBA threshold)
969 {
970         return tcu::pixelThresholdCompare(log, "Result", "Image comparison result", reference, rendered, threshold, tcu::COMPARE_LOG_RESULT);
971 }
972
973 bool compareImages (TestLog& log, const char* name, const char* desc, const tcu::Surface& reference, const tcu::Surface& rendered, tcu::RGBA threshold)
974 {
975         return tcu::pixelThresholdCompare(log, name, desc, reference, rendered, threshold, tcu::COMPARE_LOG_RESULT);
976 }
977
978 int measureAccuracy (tcu::TestLog& log, const tcu::Surface& reference, const tcu::Surface& rendered, int bestScoreDiff, int worstScoreDiff)
979 {
980         return tcu::measurePixelDiffAccuracy(log, "Result", "Image comparison result", reference, rendered, bestScoreDiff, worstScoreDiff, tcu::COMPARE_LOG_EVERYTHING);
981 }
982
983 inline int rangeDiff (int x, int a, int b)
984 {
985         if (x < a)
986                 return a-x;
987         else if (x > b)
988                 return x-b;
989         else
990                 return 0;
991 }
992
993 inline tcu::RGBA rangeDiff (tcu::RGBA p, tcu::RGBA a, tcu::RGBA b)
994 {
995         int rMin = de::min(a.getRed(),          b.getRed());
996         int rMax = de::max(a.getRed(),          b.getRed());
997         int gMin = de::min(a.getGreen(),        b.getGreen());
998         int gMax = de::max(a.getGreen(),        b.getGreen());
999         int bMin = de::min(a.getBlue(),         b.getBlue());
1000         int bMax = de::max(a.getBlue(),         b.getBlue());
1001         int aMin = de::min(a.getAlpha(),        b.getAlpha());
1002         int aMax = de::max(a.getAlpha(),        b.getAlpha());
1003
1004         return tcu::RGBA(rangeDiff(p.getRed(),          rMin, rMax),
1005                                          rangeDiff(p.getGreen(),        gMin, gMax),
1006                                          rangeDiff(p.getBlue(),         bMin, bMax),
1007                                          rangeDiff(p.getAlpha(),        aMin, aMax));
1008 }
1009
1010 inline bool rangeCompare (tcu::RGBA p, tcu::RGBA a, tcu::RGBA b, tcu::RGBA threshold)
1011 {
1012         tcu::RGBA diff = rangeDiff(p, a, b);
1013         return diff.getRed()    <= threshold.getRed() &&
1014                    diff.getGreen()      <= threshold.getGreen() &&
1015                    diff.getBlue()       <= threshold.getBlue() &&
1016                    diff.getAlpha()      <= threshold.getAlpha();
1017 }
1018
1019 RandomViewport::RandomViewport (const tcu::RenderTarget& renderTarget, int preferredWidth, int preferredHeight, deUint32 seed)
1020         : x                     (0)
1021         , y                     (0)
1022         , width         (deMin32(preferredWidth, renderTarget.getWidth()))
1023         , height        (deMin32(preferredHeight, renderTarget.getHeight()))
1024 {
1025         de::Random rnd(seed);
1026         x = rnd.getInt(0, renderTarget.getWidth()       - width);
1027         y = rnd.getInt(0, renderTarget.getHeight()      - height);
1028 }
1029
1030 ProgramLibrary::ProgramLibrary (const glu::RenderContext& context, tcu::TestContext& testCtx, glu::GLSLVersion glslVersion, glu::Precision texCoordPrecision)
1031         : m_context                             (context)
1032         , m_testCtx                             (testCtx)
1033         , m_glslVersion                 (glslVersion)
1034         , m_texCoordPrecision   (texCoordPrecision)
1035 {
1036 }
1037
1038 ProgramLibrary::~ProgramLibrary (void)
1039 {
1040         clear();
1041 }
1042
1043 void ProgramLibrary::clear (void)
1044 {
1045         for (map<Program, glu::ShaderProgram*>::iterator i = m_programs.begin(); i != m_programs.end(); i++)
1046         {
1047                 delete i->second;
1048                 i->second = DE_NULL;
1049         }
1050         m_programs.clear();
1051 }
1052
1053 glu::ShaderProgram* ProgramLibrary::getProgram (Program program)
1054 {
1055         TestLog& log = m_testCtx.getLog();
1056
1057         if (m_programs.find(program) != m_programs.end())
1058                 return m_programs[program]; // Return from cache.
1059
1060         static const char* vertShaderTemplate =
1061                 "${VTX_HEADER}"
1062                 "${VTX_IN} highp vec4 a_position;\n"
1063                 "${VTX_IN} ${PRECISION} ${TEXCOORD_TYPE} a_texCoord;\n"
1064                 "${VTX_OUT} ${PRECISION} ${TEXCOORD_TYPE} v_texCoord;\n"
1065                 "\n"
1066                 "void main (void)\n"
1067                 "{\n"
1068                 "       gl_Position = a_position;\n"
1069                 "       v_texCoord = a_texCoord;\n"
1070                 "}\n";
1071         static const char* fragShaderTemplate =
1072                 "${FRAG_HEADER}"
1073                 "${FRAG_IN} ${PRECISION} ${TEXCOORD_TYPE} v_texCoord;\n"
1074                 "uniform ${PRECISION} float u_bias;\n"
1075                 "uniform ${PRECISION} float u_ref;\n"
1076                 "uniform ${PRECISION} vec4 u_colorScale;\n"
1077                 "uniform ${PRECISION} vec4 u_colorBias;\n"
1078                 "uniform ${PRECISION} ${SAMPLER_TYPE} u_sampler;\n"
1079                 "\n"
1080                 "void main (void)\n"
1081                 "{\n"
1082                 "       ${FRAG_COLOR} = ${LOOKUP} * u_colorScale + u_colorBias;\n"
1083                 "}\n";
1084
1085         map<string, string> params;
1086
1087         bool    isCube          = de::inRange<int>(program, PROGRAM_CUBE_FLOAT, PROGRAM_CUBE_SHADOW_BIAS);
1088         bool    isArray         = de::inRange<int>(program, PROGRAM_2D_ARRAY_FLOAT, PROGRAM_2D_ARRAY_SHADOW)
1089                                                         || de::inRange<int>(program, PROGRAM_1D_ARRAY_FLOAT, PROGRAM_1D_ARRAY_SHADOW);
1090
1091         bool    is1D            = de::inRange<int>(program, PROGRAM_1D_FLOAT, PROGRAM_1D_UINT_BIAS)
1092                                                         || de::inRange<int>(program, PROGRAM_1D_ARRAY_FLOAT, PROGRAM_1D_ARRAY_SHADOW)
1093                                                         || de::inRange<int>(program, PROGRAM_BUFFER_FLOAT, PROGRAM_BUFFER_UINT);
1094
1095         bool    is2D            = de::inRange<int>(program, PROGRAM_2D_FLOAT, PROGRAM_2D_UINT_BIAS)
1096                                                         || de::inRange<int>(program, PROGRAM_2D_ARRAY_FLOAT, PROGRAM_2D_ARRAY_SHADOW);
1097
1098         bool    is3D            = de::inRange<int>(program, PROGRAM_3D_FLOAT, PROGRAM_3D_UINT_BIAS);
1099         bool    isCubeArray     = de::inRange<int>(program, PROGRAM_CUBE_ARRAY_FLOAT, PROGRAM_CUBE_ARRAY_SHADOW);
1100         bool    isBuffer        = de::inRange<int>(program, PROGRAM_BUFFER_FLOAT, PROGRAM_BUFFER_UINT);
1101
1102         if (m_glslVersion == glu::GLSL_VERSION_100_ES)
1103         {
1104                 params["FRAG_HEADER"]   = "";
1105                 params["VTX_HEADER"]    = "";
1106                 params["VTX_IN"]                = "attribute";
1107                 params["VTX_OUT"]               = "varying";
1108                 params["FRAG_IN"]               = "varying";
1109                 params["FRAG_COLOR"]    = "gl_FragColor";
1110         }
1111         else if (m_glslVersion == glu::GLSL_VERSION_300_ES || m_glslVersion == glu::GLSL_VERSION_310_ES || m_glslVersion == glu::GLSL_VERSION_330)
1112         {
1113                 const string    version = glu::getGLSLVersionDeclaration(m_glslVersion);
1114                 const char*             ext             = DE_NULL;
1115
1116                 if (isCubeArray && glu::glslVersionIsES(m_glslVersion))
1117                         ext = "GL_EXT_texture_cube_map_array";
1118                 else if (isBuffer && glu::glslVersionIsES(m_glslVersion))
1119                         ext = "GL_EXT_texture_buffer";
1120
1121                 params["FRAG_HEADER"]   = version + (ext ? string("\n#extension ") + ext + " : require" : string()) + "\nlayout(location = 0) out mediump vec4 dEQP_FragColor;\n";
1122                 params["VTX_HEADER"]    = version + "\n";
1123                 params["VTX_IN"]                = "in";
1124                 params["VTX_OUT"]               = "out";
1125                 params["FRAG_IN"]               = "in";
1126                 params["FRAG_COLOR"]    = "dEQP_FragColor";
1127         }
1128         else
1129                 DE_ASSERT(!"Unsupported version");
1130
1131         params["PRECISION"]             = glu::getPrecisionName(m_texCoordPrecision);
1132
1133         if (isCubeArray)
1134                 params["TEXCOORD_TYPE"] = "vec4";
1135         else if (isCube || (is2D && isArray) || is3D)
1136                 params["TEXCOORD_TYPE"] = "vec3";
1137         else if ((is1D && isArray) || is2D)
1138                 params["TEXCOORD_TYPE"] = "vec2";
1139         else if (is1D)
1140                 params["TEXCOORD_TYPE"] = "float";
1141         else
1142                 DE_ASSERT(DE_FALSE);
1143
1144         const char*     sampler = DE_NULL;
1145         const char*     lookup  = DE_NULL;
1146
1147         if (m_glslVersion == glu::GLSL_VERSION_300_ES || m_glslVersion == glu::GLSL_VERSION_310_ES || m_glslVersion == glu::GLSL_VERSION_330)
1148         {
1149                 switch (program)
1150                 {
1151                         case PROGRAM_2D_FLOAT:                  sampler = "sampler2D";                          lookup = "texture(u_sampler, v_texCoord)";                                                                                              break;
1152                         case PROGRAM_2D_INT:                    sampler = "isampler2D";                         lookup = "vec4(texture(u_sampler, v_texCoord))";                                                                                break;
1153                         case PROGRAM_2D_UINT:                   sampler = "usampler2D";                         lookup = "vec4(texture(u_sampler, v_texCoord))";                                                                                break;
1154                         case PROGRAM_2D_SHADOW:                 sampler = "sampler2DShadow";            lookup = "vec4(texture(u_sampler, vec3(v_texCoord, u_ref)), 0.0, 0.0, 1.0)";                    break;
1155                         case PROGRAM_2D_FLOAT_BIAS:             sampler = "sampler2D";                          lookup = "texture(u_sampler, v_texCoord, u_bias)";                                                                              break;
1156                         case PROGRAM_2D_INT_BIAS:               sampler = "isampler2D";                         lookup = "vec4(texture(u_sampler, v_texCoord, u_bias))";                                                                break;
1157                         case PROGRAM_2D_UINT_BIAS:              sampler = "usampler2D";                         lookup = "vec4(texture(u_sampler, v_texCoord, u_bias))";                                                                break;
1158                         case PROGRAM_2D_SHADOW_BIAS:    sampler = "sampler2DShadow";            lookup = "vec4(texture(u_sampler, vec3(v_texCoord, u_ref), u_bias), 0.0, 0.0, 1.0)";    break;
1159                         case PROGRAM_1D_FLOAT:                  sampler = "sampler1D";                          lookup = "texture(u_sampler, v_texCoord)";                                                                                              break;
1160                         case PROGRAM_1D_INT:                    sampler = "isampler1D";                         lookup = "vec4(texture(u_sampler, v_texCoord))";                                                                                break;
1161                         case PROGRAM_1D_UINT:                   sampler = "usampler1D";                         lookup = "vec4(texture(u_sampler, v_texCoord))";                                                                                break;
1162                         case PROGRAM_1D_SHADOW:                 sampler = "sampler1DShadow";            lookup = "vec4(texture(u_sampler, vec3(v_texCoord, u_ref)), 0.0, 0.0, 1.0)";                    break;
1163                         case PROGRAM_1D_FLOAT_BIAS:             sampler = "sampler1D";                          lookup = "texture(u_sampler, v_texCoord, u_bias)";                                                                              break;
1164                         case PROGRAM_1D_INT_BIAS:               sampler = "isampler1D";                         lookup = "vec4(texture(u_sampler, v_texCoord, u_bias))";                                                                break;
1165                         case PROGRAM_1D_UINT_BIAS:              sampler = "usampler1D";                         lookup = "vec4(texture(u_sampler, v_texCoord, u_bias))";                                                                break;
1166                         case PROGRAM_1D_SHADOW_BIAS:    sampler = "sampler1DShadow";            lookup = "vec4(texture(u_sampler, vec3(v_texCoord, u_ref), u_bias), 0.0, 0.0, 1.0)";    break;
1167                         case PROGRAM_CUBE_FLOAT:                sampler = "samplerCube";                        lookup = "texture(u_sampler, v_texCoord)";                                                                                              break;
1168                         case PROGRAM_CUBE_INT:                  sampler = "isamplerCube";                       lookup = "vec4(texture(u_sampler, v_texCoord))";                                                                                break;
1169                         case PROGRAM_CUBE_UINT:                 sampler = "usamplerCube";                       lookup = "vec4(texture(u_sampler, v_texCoord))";                                                                                break;
1170                         case PROGRAM_CUBE_SHADOW:               sampler = "samplerCubeShadow";          lookup = "vec4(texture(u_sampler, vec4(v_texCoord, u_ref)), 0.0, 0.0, 1.0)";                    break;
1171                         case PROGRAM_CUBE_FLOAT_BIAS:   sampler = "samplerCube";                        lookup = "texture(u_sampler, v_texCoord, u_bias)";                                                                              break;
1172                         case PROGRAM_CUBE_INT_BIAS:             sampler = "isamplerCube";                       lookup = "vec4(texture(u_sampler, v_texCoord, u_bias))";                                                                break;
1173                         case PROGRAM_CUBE_UINT_BIAS:    sampler = "usamplerCube";                       lookup = "vec4(texture(u_sampler, v_texCoord, u_bias))";                                                                break;
1174                         case PROGRAM_CUBE_SHADOW_BIAS:  sampler = "samplerCubeShadow";          lookup = "vec4(texture(u_sampler, vec4(v_texCoord, u_ref), u_bias), 0.0, 0.0, 1.0)";    break;
1175                         case PROGRAM_2D_ARRAY_FLOAT:    sampler = "sampler2DArray";                     lookup = "texture(u_sampler, v_texCoord)";                                                                                              break;
1176                         case PROGRAM_2D_ARRAY_INT:              sampler = "isampler2DArray";            lookup = "vec4(texture(u_sampler, v_texCoord))";                                                                                break;
1177                         case PROGRAM_2D_ARRAY_UINT:             sampler = "usampler2DArray";            lookup = "vec4(texture(u_sampler, v_texCoord))";                                                                                break;
1178                         case PROGRAM_2D_ARRAY_SHADOW:   sampler = "sampler2DArrayShadow";       lookup = "vec4(texture(u_sampler, vec4(v_texCoord, u_ref)), 0.0, 0.0, 1.0)";                    break;
1179                         case PROGRAM_3D_FLOAT:                  sampler = "sampler3D";                          lookup = "texture(u_sampler, v_texCoord)";                                                                                              break;
1180                         case PROGRAM_3D_INT:                    sampler = "isampler3D";                         lookup = "vec4(texture(u_sampler, v_texCoord))";                                                                                break;
1181                         case PROGRAM_3D_UINT:                   sampler =" usampler3D";                         lookup = "vec4(texture(u_sampler, v_texCoord))";                                                                                break;
1182                         case PROGRAM_3D_FLOAT_BIAS:             sampler = "sampler3D";                          lookup = "texture(u_sampler, v_texCoord, u_bias)";                                                                              break;
1183                         case PROGRAM_3D_INT_BIAS:               sampler = "isampler3D";                         lookup = "vec4(texture(u_sampler, v_texCoord, u_bias))";                                                                break;
1184                         case PROGRAM_3D_UINT_BIAS:              sampler =" usampler3D";                         lookup = "vec4(texture(u_sampler, v_texCoord, u_bias))";                                                                break;
1185                         case PROGRAM_CUBE_ARRAY_FLOAT:  sampler = "samplerCubeArray";           lookup = "texture(u_sampler, v_texCoord)";                                                                                              break;
1186                         case PROGRAM_CUBE_ARRAY_INT:    sampler = "isamplerCubeArray";          lookup = "vec4(texture(u_sampler, v_texCoord))";                                                                                break;
1187                         case PROGRAM_CUBE_ARRAY_UINT:   sampler = "usamplerCubeArray";          lookup = "vec4(texture(u_sampler, v_texCoord))";                                                                                break;
1188                         case PROGRAM_CUBE_ARRAY_SHADOW: sampler = "samplerCubeArrayShadow";     lookup = "vec4(texture(u_sampler, vec4(v_texCoord, u_ref)), 0.0, 0.0, 1.0)";                    break;
1189                         case PROGRAM_1D_ARRAY_FLOAT:    sampler = "sampler1DArray";                     lookup = "texture(u_sampler, v_texCoord)";                                                                                              break;
1190                         case PROGRAM_1D_ARRAY_INT:              sampler = "isampler1DArray";            lookup = "vec4(texture(u_sampler, v_texCoord))";                                                                                break;
1191                         case PROGRAM_1D_ARRAY_UINT:             sampler = "usampler1DArray";            lookup = "vec4(texture(u_sampler, v_texCoord))";                                                                                break;
1192                         case PROGRAM_1D_ARRAY_SHADOW:   sampler = "sampler1DArrayShadow";       lookup = "vec4(texture(u_sampler, vec4(v_texCoord, u_ref)), 0.0, 0.0, 1.0)";                    break;
1193                         case PROGRAM_BUFFER_FLOAT:              sampler = "samplerBuffer";                      lookup = "texelFetch(u_sampler, int(v_texCoord))";                                                                              break;
1194                         case PROGRAM_BUFFER_INT:                sampler = "isamplerBuffer";                     lookup = "vec4(texelFetch(u_sampler, int(v_texCoord)))";                                                                break;
1195                         case PROGRAM_BUFFER_UINT:               sampler = "usamplerBuffer";                     lookup = "vec4(texelFetch(u_sampler, int(v_texCoord)))";                                                                break;
1196                         default:
1197                                 DE_ASSERT(false);
1198                 }
1199         }
1200         else if (m_glslVersion == glu::GLSL_VERSION_100_ES)
1201         {
1202                 sampler = isCube ? "samplerCube" : "sampler2D";
1203
1204                 switch (program)
1205                 {
1206                         case PROGRAM_2D_FLOAT:                  lookup = "texture2D(u_sampler, v_texCoord)";                    break;
1207                         case PROGRAM_2D_FLOAT_BIAS:             lookup = "texture2D(u_sampler, v_texCoord, u_bias)";    break;
1208                         case PROGRAM_CUBE_FLOAT:                lookup = "textureCube(u_sampler, v_texCoord)";                  break;
1209                         case PROGRAM_CUBE_FLOAT_BIAS:   lookup = "textureCube(u_sampler, v_texCoord, u_bias)";  break;
1210                         default:
1211                                 DE_ASSERT(false);
1212                 }
1213         }
1214         else
1215                 DE_ASSERT(!"Unsupported version");
1216
1217         params["SAMPLER_TYPE"]  = sampler;
1218         params["LOOKUP"]                = lookup;
1219
1220         std::string vertSrc = tcu::StringTemplate(vertShaderTemplate).specialize(params);
1221         std::string fragSrc = tcu::StringTemplate(fragShaderTemplate).specialize(params);
1222
1223         glu::ShaderProgram* progObj = new glu::ShaderProgram(m_context, glu::makeVtxFragSources(vertSrc, fragSrc));
1224         if (!progObj->isOk())
1225         {
1226                 log << *progObj;
1227                 delete progObj;
1228                 TCU_FAIL("Failed to compile shader program");
1229         }
1230
1231         try
1232         {
1233                 m_programs[program] = progObj;
1234         }
1235         catch (...)
1236         {
1237                 delete progObj;
1238                 throw;
1239         }
1240
1241         return progObj;
1242 }
1243
1244 TextureRenderer::TextureRenderer (const glu::RenderContext& context, tcu::TestContext& testCtx, glu::GLSLVersion glslVersion, glu::Precision texCoordPrecision)
1245         : m_renderCtx           (context)
1246         , m_testCtx                     (testCtx)
1247         , m_programLibrary      (context, testCtx, glslVersion, texCoordPrecision)
1248 {
1249 }
1250
1251 TextureRenderer::~TextureRenderer (void)
1252 {
1253         clear();
1254 }
1255
1256 void TextureRenderer::clear (void)
1257 {
1258         m_programLibrary.clear();
1259 }
1260
1261 void TextureRenderer::renderQuad (int texUnit, const float* texCoord, TextureType texType)
1262 {
1263         renderQuad(texUnit, texCoord, RenderParams(texType));
1264 }
1265
1266 void TextureRenderer::renderQuad (int texUnit, const float* texCoord, const RenderParams& params)
1267 {
1268         const glw::Functions&   gl                      = m_renderCtx.getFunctions();
1269         tcu::Vec4                               wCoord          = params.flags & RenderParams::PROJECTED ? params.w : tcu::Vec4(1.0f);
1270         bool                                    useBias         = !!(params.flags & RenderParams::USE_BIAS);
1271         TestLog&                                log                     = m_testCtx.getLog();
1272         bool                                    logUniforms     = !!(params.flags & RenderParams::LOG_UNIFORMS);
1273
1274         // Render quad with texture.
1275         float position[] =
1276         {
1277                 -1.0f*wCoord.x(), -1.0f*wCoord.x(), 0.0f, wCoord.x(),
1278                 -1.0f*wCoord.y(), +1.0f*wCoord.y(), 0.0f, wCoord.y(),
1279                 +1.0f*wCoord.z(), -1.0f*wCoord.z(), 0.0f, wCoord.z(),
1280                 +1.0f*wCoord.w(), +1.0f*wCoord.w(), 0.0f, wCoord.w()
1281         };
1282         static const deUint16 indices[] = { 0, 1, 2, 2, 1, 3 };
1283
1284         Program progSpec        = PROGRAM_LAST;
1285         int             numComps        = 0;
1286         if (params.texType == TEXTURETYPE_2D)
1287         {
1288                 numComps = 2;
1289
1290                 switch (params.samplerType)
1291                 {
1292                         case SAMPLERTYPE_FLOAT:         progSpec = useBias ? PROGRAM_2D_FLOAT_BIAS      : PROGRAM_2D_FLOAT;             break;
1293                         case SAMPLERTYPE_INT:           progSpec = useBias ? PROGRAM_2D_INT_BIAS        : PROGRAM_2D_INT;               break;
1294                         case SAMPLERTYPE_UINT:          progSpec = useBias ? PROGRAM_2D_UINT_BIAS       : PROGRAM_2D_UINT;              break;
1295                         case SAMPLERTYPE_SHADOW:        progSpec = useBias ? PROGRAM_2D_SHADOW_BIAS     : PROGRAM_2D_SHADOW;    break;
1296                         default:                                        DE_ASSERT(false);
1297                 }
1298         }
1299         else if (params.texType == TEXTURETYPE_1D)
1300         {
1301                 numComps = 1;
1302
1303                 switch (params.samplerType)
1304                 {
1305                         case SAMPLERTYPE_FLOAT:         progSpec = useBias ? PROGRAM_1D_FLOAT_BIAS      : PROGRAM_1D_FLOAT;             break;
1306                         case SAMPLERTYPE_INT:           progSpec = useBias ? PROGRAM_1D_INT_BIAS        : PROGRAM_1D_INT;               break;
1307                         case SAMPLERTYPE_UINT:          progSpec = useBias ? PROGRAM_1D_UINT_BIAS       : PROGRAM_1D_UINT;              break;
1308                         case SAMPLERTYPE_SHADOW:        progSpec = useBias ? PROGRAM_1D_SHADOW_BIAS     : PROGRAM_1D_SHADOW;    break;
1309                         default:                                        DE_ASSERT(false);
1310                 }
1311         }
1312         else if (params.texType == TEXTURETYPE_CUBE)
1313         {
1314                 numComps = 3;
1315
1316                 switch (params.samplerType)
1317                 {
1318                         case SAMPLERTYPE_FLOAT:         progSpec = useBias ? PROGRAM_CUBE_FLOAT_BIAS    : PROGRAM_CUBE_FLOAT;   break;
1319                         case SAMPLERTYPE_INT:           progSpec = useBias ? PROGRAM_CUBE_INT_BIAS              : PROGRAM_CUBE_INT;             break;
1320                         case SAMPLERTYPE_UINT:          progSpec = useBias ? PROGRAM_CUBE_UINT_BIAS             : PROGRAM_CUBE_UINT;    break;
1321                         case SAMPLERTYPE_SHADOW:        progSpec = useBias ? PROGRAM_CUBE_SHADOW_BIAS   : PROGRAM_CUBE_SHADOW;  break;
1322                         default:                                        DE_ASSERT(false);
1323                 }
1324         }
1325         else if (params.texType == TEXTURETYPE_3D)
1326         {
1327                 numComps = 3;
1328
1329                 switch (params.samplerType)
1330                 {
1331                         case SAMPLERTYPE_FLOAT:         progSpec = useBias ? PROGRAM_3D_FLOAT_BIAS      : PROGRAM_3D_FLOAT;             break;
1332                         case SAMPLERTYPE_INT:           progSpec = useBias ? PROGRAM_3D_INT_BIAS        : PROGRAM_3D_INT;               break;
1333                         case SAMPLERTYPE_UINT:          progSpec = useBias ? PROGRAM_3D_UINT_BIAS       : PROGRAM_3D_UINT;              break;
1334                         default:                                        DE_ASSERT(false);
1335                 }
1336         }
1337         else if (params.texType == TEXTURETYPE_2D_ARRAY)
1338         {
1339                 DE_ASSERT(!useBias); // \todo [2012-02-17 pyry] Support bias.
1340
1341                 numComps = 3;
1342
1343                 switch (params.samplerType)
1344                 {
1345                         case SAMPLERTYPE_FLOAT:         progSpec = PROGRAM_2D_ARRAY_FLOAT;      break;
1346                         case SAMPLERTYPE_INT:           progSpec = PROGRAM_2D_ARRAY_INT;        break;
1347                         case SAMPLERTYPE_UINT:          progSpec = PROGRAM_2D_ARRAY_UINT;       break;
1348                         case SAMPLERTYPE_SHADOW:        progSpec = PROGRAM_2D_ARRAY_SHADOW;     break;
1349                         default:                                        DE_ASSERT(false);
1350                 }
1351         }
1352         else if (params.texType == TEXTURETYPE_CUBE_ARRAY)
1353         {
1354                 DE_ASSERT(!useBias);
1355
1356                 numComps = 4;
1357
1358                 switch (params.samplerType)
1359                 {
1360                         case SAMPLERTYPE_FLOAT:         progSpec = PROGRAM_CUBE_ARRAY_FLOAT;    break;
1361                         case SAMPLERTYPE_INT:           progSpec = PROGRAM_CUBE_ARRAY_INT;              break;
1362                         case SAMPLERTYPE_UINT:          progSpec = PROGRAM_CUBE_ARRAY_UINT;             break;
1363                         case SAMPLERTYPE_SHADOW:        progSpec = PROGRAM_CUBE_ARRAY_SHADOW;   break;
1364                         default:                                        DE_ASSERT(false);
1365                 }
1366         }
1367         else if (params.texType == TEXTURETYPE_1D_ARRAY)
1368         {
1369                 DE_ASSERT(!useBias); // \todo [2012-02-17 pyry] Support bias.
1370
1371                 numComps = 2;
1372
1373                 switch (params.samplerType)
1374                 {
1375                         case SAMPLERTYPE_FLOAT:         progSpec = PROGRAM_1D_ARRAY_FLOAT;      break;
1376                         case SAMPLERTYPE_INT:           progSpec = PROGRAM_1D_ARRAY_INT;        break;
1377                         case SAMPLERTYPE_UINT:          progSpec = PROGRAM_1D_ARRAY_UINT;       break;
1378                         case SAMPLERTYPE_SHADOW:        progSpec = PROGRAM_1D_ARRAY_SHADOW;     break;
1379                         default:                                        DE_ASSERT(false);
1380                 }
1381         }
1382         else if (params.texType == TEXTURETYPE_BUFFER)
1383         {
1384                 numComps = 1;
1385
1386                 switch (params.samplerType)
1387                 {
1388                         case SAMPLERTYPE_FETCH_FLOAT:   progSpec = PROGRAM_BUFFER_FLOAT;        break;
1389                         case SAMPLERTYPE_FETCH_INT:             progSpec = PROGRAM_BUFFER_INT;          break;
1390                         case SAMPLERTYPE_FETCH_UINT:    progSpec = PROGRAM_BUFFER_UINT;         break;
1391                         default:                                                DE_ASSERT(false);
1392                 }
1393         }
1394         else
1395                 DE_ASSERT(DE_FALSE);
1396
1397         glu::ShaderProgram* program = m_programLibrary.getProgram(progSpec);
1398
1399         // \todo [2012-09-26 pyry] Move to ProgramLibrary and log unique programs only(?)
1400         if (params.flags & RenderParams::LOG_PROGRAMS)
1401                 log << *program;
1402
1403         GLU_EXPECT_NO_ERROR(gl.getError(), "Set vertex attributes");
1404
1405         // Program and uniforms.
1406         deUint32 prog = program->getProgram();
1407         gl.useProgram(prog);
1408
1409         gl.uniform1i(gl.getUniformLocation(prog, "u_sampler"), texUnit);
1410         if (logUniforms)
1411                 log << TestLog::Message << "u_sampler = " << texUnit << TestLog::EndMessage;
1412
1413         if (useBias)
1414         {
1415                 gl.uniform1f(gl.getUniformLocation(prog, "u_bias"), params.bias);
1416                 if (logUniforms)
1417                         log << TestLog::Message << "u_bias = " << params.bias << TestLog::EndMessage;
1418         }
1419
1420         if (params.samplerType == SAMPLERTYPE_SHADOW)
1421         {
1422                 gl.uniform1f(gl.getUniformLocation(prog, "u_ref"), params.ref);
1423                 if (logUniforms)
1424                         log << TestLog::Message << "u_ref = " << params.ref << TestLog::EndMessage;
1425         }
1426
1427         gl.uniform4fv(gl.getUniformLocation(prog, "u_colorScale"),      1, params.colorScale.getPtr());
1428         gl.uniform4fv(gl.getUniformLocation(prog, "u_colorBias"),       1, params.colorBias.getPtr());
1429
1430         if (logUniforms)
1431         {
1432                 log << TestLog::Message << "u_colorScale = " << params.colorScale << TestLog::EndMessage;
1433                 log << TestLog::Message << "u_colorBias = " << params.colorBias << TestLog::EndMessage;
1434         }
1435
1436         GLU_EXPECT_NO_ERROR(gl.getError(), "Set program state");
1437
1438         {
1439                 const glu::VertexArrayBinding vertexArrays[] =
1440                 {
1441                         glu::va::Float("a_position",    4,                      4, 0, &position[0]),
1442                         glu::va::Float("a_texCoord",    numComps,       4, 0, texCoord)
1443                 };
1444                 glu::draw(m_renderCtx, prog, DE_LENGTH_OF_ARRAY(vertexArrays), &vertexArrays[0],
1445                                   glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indices), &indices[0]));
1446         }
1447 }
1448
1449 void computeQuadTexCoord1D (std::vector<float>& dst, float left, float right)
1450 {
1451         dst.resize(4);
1452
1453         dst[0] = left;
1454         dst[1] = left;
1455         dst[2] = right;
1456         dst[3] = right;
1457 }
1458
1459 void computeQuadTexCoord1DArray (std::vector<float>& dst, int layerNdx, float left, float right)
1460 {
1461         dst.resize(4*2);
1462
1463         dst[0] = left;  dst[1] = (float)layerNdx;
1464         dst[2] = left;  dst[3] = (float)layerNdx;
1465         dst[4] = right; dst[5] = (float)layerNdx;
1466         dst[6] = right; dst[7] = (float)layerNdx;
1467 }
1468
1469 void computeQuadTexCoord2D (std::vector<float>& dst, const tcu::Vec2& bottomLeft, const tcu::Vec2& topRight)
1470 {
1471         dst.resize(4*2);
1472
1473         dst[0] = bottomLeft.x();        dst[1] = bottomLeft.y();
1474         dst[2] = bottomLeft.x();        dst[3] = topRight.y();
1475         dst[4] = topRight.x();          dst[5] = bottomLeft.y();
1476         dst[6] = topRight.x();          dst[7] = topRight.y();
1477 }
1478
1479 void computeQuadTexCoord2DArray (std::vector<float>& dst, int layerNdx, const tcu::Vec2& bottomLeft, const tcu::Vec2& topRight)
1480 {
1481         dst.resize(4*3);
1482
1483         dst[0] = bottomLeft.x();        dst[ 1] = bottomLeft.y();       dst[ 2] = (float)layerNdx;
1484         dst[3] = bottomLeft.x();        dst[ 4] = topRight.y();         dst[ 5] = (float)layerNdx;
1485         dst[6] = topRight.x();          dst[ 7] = bottomLeft.y();       dst[ 8] = (float)layerNdx;
1486         dst[9] = topRight.x();          dst[10] = topRight.y();         dst[11] = (float)layerNdx;
1487 }
1488
1489 void computeQuadTexCoord3D (std::vector<float>& dst, const tcu::Vec3& p0, const tcu::Vec3& p1, const tcu::IVec3& dirSwz)
1490 {
1491         tcu::Vec3 f0 = tcu::Vec3(0.0f, 0.0f, 0.0f).swizzle(dirSwz[0], dirSwz[1], dirSwz[2]);
1492         tcu::Vec3 f1 = tcu::Vec3(0.0f, 1.0f, 0.0f).swizzle(dirSwz[0], dirSwz[1], dirSwz[2]);
1493         tcu::Vec3 f2 = tcu::Vec3(1.0f, 0.0f, 0.0f).swizzle(dirSwz[0], dirSwz[1], dirSwz[2]);
1494         tcu::Vec3 f3 = tcu::Vec3(1.0f, 1.0f, 0.0f).swizzle(dirSwz[0], dirSwz[1], dirSwz[2]);
1495
1496         tcu::Vec3 v0 = p0 + (p1-p0)*f0;
1497         tcu::Vec3 v1 = p0 + (p1-p0)*f1;
1498         tcu::Vec3 v2 = p0 + (p1-p0)*f2;
1499         tcu::Vec3 v3 = p0 + (p1-p0)*f3;
1500
1501         dst.resize(4*3);
1502
1503         dst[0] = v0.x(); dst[ 1] = v0.y(); dst[ 2] = v0.z();
1504         dst[3] = v1.x(); dst[ 4] = v1.y(); dst[ 5] = v1.z();
1505         dst[6] = v2.x(); dst[ 7] = v2.y(); dst[ 8] = v2.z();
1506         dst[9] = v3.x(); dst[10] = v3.y(); dst[11] = v3.z();
1507 }
1508
1509 void computeQuadTexCoordCube (std::vector<float>& dst, tcu::CubeFace face)
1510 {
1511         static const float texCoordNegX[] =
1512         {
1513                 -1.0f,  1.0f, -1.0f,
1514                 -1.0f, -1.0f, -1.0f,
1515                 -1.0f,  1.0f,  1.0f,
1516                 -1.0f, -1.0f,  1.0f
1517         };
1518         static const float texCoordPosX[] =
1519         {
1520                 +1.0f,  1.0f,  1.0f,
1521                 +1.0f, -1.0f,  1.0f,
1522                 +1.0f,  1.0f, -1.0f,
1523                 +1.0f, -1.0f, -1.0f
1524         };
1525         static const float texCoordNegY[] =
1526         {
1527                 -1.0f, -1.0f,  1.0f,
1528                 -1.0f, -1.0f, -1.0f,
1529                  1.0f, -1.0f,  1.0f,
1530                  1.0f, -1.0f, -1.0f
1531         };
1532         static const float texCoordPosY[] =
1533         {
1534                 -1.0f, +1.0f, -1.0f,
1535                 -1.0f, +1.0f,  1.0f,
1536                  1.0f, +1.0f, -1.0f,
1537                  1.0f, +1.0f,  1.0f
1538         };
1539         static const float texCoordNegZ[] =
1540         {
1541                  1.0f,  1.0f, -1.0f,
1542                  1.0f, -1.0f, -1.0f,
1543                 -1.0f,  1.0f, -1.0f,
1544                 -1.0f, -1.0f, -1.0f
1545         };
1546         static const float texCoordPosZ[] =
1547         {
1548                 -1.0f,  1.0f, +1.0f,
1549                 -1.0f, -1.0f, +1.0f,
1550                  1.0f,  1.0f, +1.0f,
1551                  1.0f, -1.0f, +1.0f
1552         };
1553
1554         const float*    texCoord                = DE_NULL;
1555         int                             texCoordSize    = DE_LENGTH_OF_ARRAY(texCoordNegX);
1556
1557         switch (face)
1558         {
1559                 case tcu::CUBEFACE_NEGATIVE_X: texCoord = texCoordNegX; break;
1560                 case tcu::CUBEFACE_POSITIVE_X: texCoord = texCoordPosX; break;
1561                 case tcu::CUBEFACE_NEGATIVE_Y: texCoord = texCoordNegY; break;
1562                 case tcu::CUBEFACE_POSITIVE_Y: texCoord = texCoordPosY; break;
1563                 case tcu::CUBEFACE_NEGATIVE_Z: texCoord = texCoordNegZ; break;
1564                 case tcu::CUBEFACE_POSITIVE_Z: texCoord = texCoordPosZ; break;
1565                 default:
1566                         DE_ASSERT(DE_FALSE);
1567                         return;
1568         }
1569
1570         dst.resize(texCoordSize);
1571         std::copy(texCoord, texCoord+texCoordSize, dst.begin());
1572 }
1573
1574 void computeQuadTexCoordCube (std::vector<float>& dst, tcu::CubeFace face, const tcu::Vec2& bottomLeft, const tcu::Vec2& topRight)
1575 {
1576         int             sRow            = 0;
1577         int             tRow            = 0;
1578         int             mRow            = 0;
1579         float   sSign           = 1.0f;
1580         float   tSign           = 1.0f;
1581         float   mSign           = 1.0f;
1582
1583         switch (face)
1584         {
1585                 case tcu::CUBEFACE_NEGATIVE_X: mRow = 0; sRow = 2; tRow = 1; mSign = -1.0f;                                tSign = -1.0f;       break;
1586                 case tcu::CUBEFACE_POSITIVE_X: mRow = 0; sRow = 2; tRow = 1;                            sSign = -1.0f; tSign = -1.0f;   break;
1587                 case tcu::CUBEFACE_NEGATIVE_Y: mRow = 1; sRow = 0; tRow = 2; mSign = -1.0f;                                tSign = -1.0f;       break;
1588                 case tcu::CUBEFACE_POSITIVE_Y: mRow = 1; sRow = 0; tRow = 2;                                                                                            break;
1589                 case tcu::CUBEFACE_NEGATIVE_Z: mRow = 2; sRow = 0; tRow = 1; mSign = -1.0f; sSign = -1.0f; tSign = -1.0f;       break;
1590                 case tcu::CUBEFACE_POSITIVE_Z: mRow = 2; sRow = 0; tRow = 1;                                                       tSign = -1.0f;       break;
1591                 default:
1592                         DE_ASSERT(DE_FALSE);
1593                         return;
1594         }
1595
1596         dst.resize(3*4);
1597
1598         dst[0+mRow] = mSign;
1599         dst[3+mRow] = mSign;
1600         dst[6+mRow] = mSign;
1601         dst[9+mRow] = mSign;
1602
1603         dst[0+sRow] = sSign * bottomLeft.x();
1604         dst[3+sRow] = sSign * bottomLeft.x();
1605         dst[6+sRow] = sSign * topRight.x();
1606         dst[9+sRow] = sSign * topRight.x();
1607
1608         dst[0+tRow] = tSign * bottomLeft.y();
1609         dst[3+tRow] = tSign * topRight.y();
1610         dst[6+tRow] = tSign * bottomLeft.y();
1611         dst[9+tRow] = tSign * topRight.y();
1612 }
1613
1614 void computeQuadTexCoordCubeArray (std::vector<float>& dst, tcu::CubeFace face, const tcu::Vec2& bottomLeft, const tcu::Vec2& topRight, const tcu::Vec2& layerRange)
1615 {
1616         int                     sRow    = 0;
1617         int                     tRow    = 0;
1618         int                     mRow    = 0;
1619         const int       qRow    = 3;
1620         float           sSign   = 1.0f;
1621         float           tSign   = 1.0f;
1622         float           mSign   = 1.0f;
1623         const float     l0              = layerRange.x();
1624         const float     l1              = layerRange.y();
1625
1626         switch (face)
1627         {
1628                 case tcu::CUBEFACE_NEGATIVE_X: mRow = 0; sRow = 2; tRow = 1; mSign = -1.0f;                                tSign = -1.0f;       break;
1629                 case tcu::CUBEFACE_POSITIVE_X: mRow = 0; sRow = 2; tRow = 1;                            sSign = -1.0f; tSign = -1.0f;   break;
1630                 case tcu::CUBEFACE_NEGATIVE_Y: mRow = 1; sRow = 0; tRow = 2; mSign = -1.0f;                                tSign = -1.0f;       break;
1631                 case tcu::CUBEFACE_POSITIVE_Y: mRow = 1; sRow = 0; tRow = 2;                                                                                            break;
1632                 case tcu::CUBEFACE_NEGATIVE_Z: mRow = 2; sRow = 0; tRow = 1; mSign = -1.0f; sSign = -1.0f; tSign = -1.0f;       break;
1633                 case tcu::CUBEFACE_POSITIVE_Z: mRow = 2; sRow = 0; tRow = 1;                                                       tSign = -1.0f;       break;
1634                 default:
1635                         DE_ASSERT(DE_FALSE);
1636                         return;
1637         }
1638
1639         dst.resize(4*4);
1640
1641         dst[ 0+mRow] = mSign;
1642         dst[ 4+mRow] = mSign;
1643         dst[ 8+mRow] = mSign;
1644         dst[12+mRow] = mSign;
1645
1646         dst[ 0+sRow] = sSign * bottomLeft.x();
1647         dst[ 4+sRow] = sSign * bottomLeft.x();
1648         dst[ 8+sRow] = sSign * topRight.x();
1649         dst[12+sRow] = sSign * topRight.x();
1650
1651         dst[ 0+tRow] = tSign * bottomLeft.y();
1652         dst[ 4+tRow] = tSign * topRight.y();
1653         dst[ 8+tRow] = tSign * bottomLeft.y();
1654         dst[12+tRow] = tSign * topRight.y();
1655
1656         if (l0 != l1)
1657         {
1658                 dst[ 0+qRow] = l0;
1659                 dst[ 4+qRow] = l0*0.5f + l1*0.5f;
1660                 dst[ 8+qRow] = l0*0.5f + l1*0.5f;
1661                 dst[12+qRow] = l1;
1662         }
1663         else
1664         {
1665                 dst[ 0+qRow] = l0;
1666                 dst[ 4+qRow] = l0;
1667                 dst[ 8+qRow] = l0;
1668                 dst[12+qRow] = l0;
1669         }
1670 }
1671
1672 // Texture result verification
1673
1674 //! Verifies texture lookup results and returns number of failed pixels.
1675 int computeTextureLookupDiff (const tcu::ConstPixelBufferAccess&        result,
1676                                                           const tcu::ConstPixelBufferAccess&    reference,
1677                                                           const tcu::PixelBufferAccess&                 errorMask,
1678                                                           const tcu::Texture1DView&                             baseView,
1679                                                           const float*                                                  texCoord,
1680                                                           const ReferenceParams&                                sampleParams,
1681                                                           const tcu::LookupPrecision&                   lookupPrec,
1682                                                           const tcu::LodPrecision&                              lodPrec,
1683                                                           qpWatchDog*                                                   watchDog)
1684 {
1685         DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
1686         DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
1687
1688         const tcu::Texture1DView        src             = getSubView(baseView, sampleParams.baseLevel, sampleParams.maxLevel);
1689
1690         const tcu::Vec4         sq                              = tcu::Vec4(texCoord[0], texCoord[1], texCoord[2], texCoord[3]);
1691
1692         const tcu::IVec2        dstSize                 = tcu::IVec2(result.getWidth(), result.getHeight());
1693         const float                     dstW                    = float(dstSize.x());
1694         const float                     dstH                    = float(dstSize.y());
1695         const int                       srcSize                 = src.getWidth();
1696
1697         // Coordinates and lod per triangle.
1698         const tcu::Vec3         triS[2]                 = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
1699         const tcu::Vec3         triW[2]                 = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
1700
1701         const tcu::Vec2         lodBias                 ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
1702
1703         int                                     numFailed               = 0;
1704
1705         const tcu::Vec2 lodOffsets[] =
1706         {
1707                 tcu::Vec2(-1,  0),
1708                 tcu::Vec2(+1,  0),
1709                 tcu::Vec2( 0, -1),
1710                 tcu::Vec2( 0, +1),
1711         };
1712
1713         tcu::clear(errorMask, tcu::RGBA::green.toVec());
1714
1715         for (int py = 0; py < result.getHeight(); py++)
1716         {
1717                 // Ugly hack, validation can take way too long at the moment.
1718                 if (watchDog)
1719                         qpWatchDog_touch(watchDog);
1720
1721                 for (int px = 0; px < result.getWidth(); px++)
1722                 {
1723                         const tcu::Vec4 resPix  = (result.getPixel(px, py)              - sampleParams.colorBias) / sampleParams.colorScale;
1724                         const tcu::Vec4 refPix  = (reference.getPixel(px, py)   - sampleParams.colorBias) / sampleParams.colorScale;
1725
1726                         // Try comparison to ideal reference first, and if that fails use slower verificator.
1727                         if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
1728                         {
1729                                 const float             wx              = (float)px + 0.5f;
1730                                 const float             wy              = (float)py + 0.5f;
1731                                 const float             nx              = wx / dstW;
1732                                 const float             ny              = wy / dstH;
1733
1734                                 const int               triNdx  = nx + ny >= 1.0f ? 1 : 0;
1735                                 const float             triWx   = triNdx ? dstW - wx : wx;
1736                                 const float             triWy   = triNdx ? dstH - wy : wy;
1737                                 const float             triNx   = triNdx ? 1.0f - nx : nx;
1738                                 const float             triNy   = triNdx ? 1.0f - ny : ny;
1739
1740                                 const float             coord           = projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy);
1741                                 const float             coordDx         = triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy) * float(srcSize);
1742                                 const float     coordDy         = triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx) * float(srcSize);
1743
1744                                 tcu::Vec2               lodBounds       = tcu::computeLodBoundsFromDerivates(coordDx, coordDy, lodPrec);
1745
1746                                 // Compute lod bounds across lodOffsets range.
1747                                 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
1748                                 {
1749                                         const float             wxo             = triWx + lodOffsets[lodOffsNdx].x();
1750                                         const float             wyo             = triWy + lodOffsets[lodOffsNdx].y();
1751                                         const float             nxo             = wxo/dstW;
1752                                         const float             nyo             = wyo/dstH;
1753
1754                                         const float     coordDxo        = triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo) * float(srcSize);
1755                                         const float     coordDyo        = triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo) * float(srcSize);
1756                                         const tcu::Vec2 lodO    = tcu::computeLodBoundsFromDerivates(coordDxo, coordDyo, lodPrec);
1757
1758                                         lodBounds.x() = de::min(lodBounds.x(), lodO.x());
1759                                         lodBounds.y() = de::max(lodBounds.y(), lodO.y());
1760                                 }
1761
1762                                 const tcu::Vec2 clampedLod      = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
1763                                 const bool              isOk            = tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix);
1764
1765                                 if (!isOk)
1766                                 {
1767                                         errorMask.setPixel(tcu::RGBA::red.toVec(), px, py);
1768                                         numFailed += 1;
1769                                 }
1770                         }
1771                 }
1772         }
1773
1774         return numFailed;
1775 }
1776
1777 int computeTextureLookupDiff (const tcu::ConstPixelBufferAccess&        result,
1778                                                           const tcu::ConstPixelBufferAccess&    reference,
1779                                                           const tcu::PixelBufferAccess&                 errorMask,
1780                                                           const tcu::Texture2DView&                             baseView,
1781                                                           const float*                                                  texCoord,
1782                                                           const ReferenceParams&                                        sampleParams,
1783                                                           const tcu::LookupPrecision&                   lookupPrec,
1784                                                           const tcu::LodPrecision&                              lodPrec,
1785                                                           qpWatchDog*                                                   watchDog)
1786 {
1787         DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
1788         DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
1789
1790         const tcu::Texture2DView        src             = getSubView(baseView, sampleParams.baseLevel, sampleParams.maxLevel);
1791
1792         const tcu::Vec4         sq                              = tcu::Vec4(texCoord[0+0], texCoord[2+0], texCoord[4+0], texCoord[6+0]);
1793         const tcu::Vec4         tq                              = tcu::Vec4(texCoord[0+1], texCoord[2+1], texCoord[4+1], texCoord[6+1]);
1794
1795         const tcu::IVec2        dstSize                 = tcu::IVec2(result.getWidth(), result.getHeight());
1796         const float                     dstW                    = float(dstSize.x());
1797         const float                     dstH                    = float(dstSize.y());
1798         const tcu::IVec2        srcSize                 = tcu::IVec2(src.getWidth(), src.getHeight());
1799
1800         // Coordinates and lod per triangle.
1801         const tcu::Vec3         triS[2]                 = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
1802         const tcu::Vec3         triT[2]                 = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
1803         const tcu::Vec3         triW[2]                 = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
1804
1805         const tcu::Vec2         lodBias                 ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
1806
1807         int                                     numFailed               = 0;
1808
1809         const tcu::Vec2 lodOffsets[] =
1810         {
1811                 tcu::Vec2(-1,  0),
1812                 tcu::Vec2(+1,  0),
1813                 tcu::Vec2( 0, -1),
1814                 tcu::Vec2( 0, +1),
1815         };
1816
1817         tcu::clear(errorMask, tcu::RGBA::green.toVec());
1818
1819         for (int py = 0; py < result.getHeight(); py++)
1820         {
1821                 // Ugly hack, validation can take way too long at the moment.
1822                 if (watchDog)
1823                         qpWatchDog_touch(watchDog);
1824
1825                 for (int px = 0; px < result.getWidth(); px++)
1826                 {
1827                         const tcu::Vec4 resPix  = (result.getPixel(px, py)              - sampleParams.colorBias) / sampleParams.colorScale;
1828                         const tcu::Vec4 refPix  = (reference.getPixel(px, py)   - sampleParams.colorBias) / sampleParams.colorScale;
1829
1830                         // Try comparison to ideal reference first, and if that fails use slower verificator.
1831                         if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
1832                         {
1833                                 const float             wx              = (float)px + 0.5f;
1834                                 const float             wy              = (float)py + 0.5f;
1835                                 const float             nx              = wx / dstW;
1836                                 const float             ny              = wy / dstH;
1837
1838                                 const int               triNdx  = nx + ny >= 1.0f ? 1 : 0;
1839                                 const float             triWx   = triNdx ? dstW - wx : wx;
1840                                 const float             triWy   = triNdx ? dstH - wy : wy;
1841                                 const float             triNx   = triNdx ? 1.0f - nx : nx;
1842                                 const float             triNy   = triNdx ? 1.0f - ny : ny;
1843
1844                                 const tcu::Vec2 coord           (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
1845                                                                                          projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy));
1846                                 const tcu::Vec2 coordDx         = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
1847                                                                                                                 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy)) * srcSize.asFloat();
1848                                 const tcu::Vec2 coordDy         = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
1849                                                                                                                 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx)) * srcSize.asFloat();
1850
1851                                 tcu::Vec2               lodBounds       = tcu::computeLodBoundsFromDerivates(coordDx.x(), coordDx.y(), coordDy.x(), coordDy.y(), lodPrec);
1852
1853                                 // Compute lod bounds across lodOffsets range.
1854                                 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
1855                                 {
1856                                         const float             wxo             = triWx + lodOffsets[lodOffsNdx].x();
1857                                         const float             wyo             = triWy + lodOffsets[lodOffsNdx].y();
1858                                         const float             nxo             = wxo/dstW;
1859                                         const float             nyo             = wyo/dstH;
1860
1861                                         const tcu::Vec2 coordO          (projectedTriInterpolate(triS[triNdx], triW[triNdx], nxo, nyo),
1862                                                                                                  projectedTriInterpolate(triT[triNdx], triW[triNdx], nxo, nyo));
1863                                         const tcu::Vec2 coordDxo        = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
1864                                                                                                                         triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo)) * srcSize.asFloat();
1865                                         const tcu::Vec2 coordDyo        = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
1866                                                                                                                         triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo)) * srcSize.asFloat();
1867                                         const tcu::Vec2 lodO            = tcu::computeLodBoundsFromDerivates(coordDxo.x(), coordDxo.y(), coordDyo.x(), coordDyo.y(), lodPrec);
1868
1869                                         lodBounds.x() = de::min(lodBounds.x(), lodO.x());
1870                                         lodBounds.y() = de::max(lodBounds.y(), lodO.y());
1871                                 }
1872
1873                                 const tcu::Vec2 clampedLod      = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
1874                                 const bool              isOk            = tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix);
1875
1876                                 if (!isOk)
1877                                 {
1878                                         errorMask.setPixel(tcu::RGBA::red.toVec(), px, py);
1879                                         numFailed += 1;
1880                                 }
1881                         }
1882                 }
1883         }
1884
1885         return numFailed;
1886 }
1887
1888 bool verifyTextureResult (tcu::TestContext&                                             testCtx,
1889                                                   const tcu::ConstPixelBufferAccess&    result,
1890                                                   const tcu::Texture1DView&                             src,
1891                                                   const float*                                                  texCoord,
1892                                                   const ReferenceParams&                                sampleParams,
1893                                                   const tcu::LookupPrecision&                   lookupPrec,
1894                                                   const tcu::LodPrecision&                              lodPrec,
1895                                                   const tcu::PixelFormat&                               pixelFormat)
1896 {
1897         tcu::TestLog&   log                             = testCtx.getLog();
1898         tcu::Surface    reference               (result.getWidth(), result.getHeight());
1899         tcu::Surface    errorMask               (result.getWidth(), result.getHeight());
1900         int                             numFailedPixels;
1901
1902         DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
1903
1904         sampleTexture(SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
1905         numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog());
1906
1907         if (numFailedPixels > 0)
1908                 log << TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
1909
1910         log << TestLog::ImageSet("VerifyResult", "Verification result")
1911                 << TestLog::Image("Rendered", "Rendered image", result);
1912
1913         if (numFailedPixels > 0)
1914         {
1915                 log << TestLog::Image("Reference", "Ideal reference image", reference)
1916                         << TestLog::Image("ErrorMask", "Error mask", errorMask);
1917         }
1918
1919         log << TestLog::EndImageSet;
1920
1921         return numFailedPixels == 0;
1922 }
1923
1924 bool verifyTextureResult (tcu::TestContext&                                             testCtx,
1925                                                   const tcu::ConstPixelBufferAccess&    result,
1926                                                   const tcu::Texture2DView&                             src,
1927                                                   const float*                                                  texCoord,
1928                                                   const ReferenceParams&                                sampleParams,
1929                                                   const tcu::LookupPrecision&                   lookupPrec,
1930                                                   const tcu::LodPrecision&                              lodPrec,
1931                                                   const tcu::PixelFormat&                               pixelFormat)
1932 {
1933         tcu::TestLog&   log                             = testCtx.getLog();
1934         tcu::Surface    reference               (result.getWidth(), result.getHeight());
1935         tcu::Surface    errorMask               (result.getWidth(), result.getHeight());
1936         int                             numFailedPixels;
1937
1938         DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
1939
1940         sampleTexture(SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
1941         numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog());
1942
1943         if (numFailedPixels > 0)
1944                 log << TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
1945
1946         log << TestLog::ImageSet("VerifyResult", "Verification result")
1947                 << TestLog::Image("Rendered", "Rendered image", result);
1948
1949         if (numFailedPixels > 0)
1950         {
1951                 log << TestLog::Image("Reference", "Ideal reference image", reference)
1952                         << TestLog::Image("ErrorMask", "Error mask", errorMask);
1953         }
1954
1955         log << TestLog::EndImageSet;
1956
1957         return numFailedPixels == 0;
1958 }
1959
1960 //! Verifies texture lookup results and returns number of failed pixels.
1961 int computeTextureLookupDiff (const tcu::ConstPixelBufferAccess&        result,
1962                                                           const tcu::ConstPixelBufferAccess&    reference,
1963                                                           const tcu::PixelBufferAccess&                 errorMask,
1964                                                           const tcu::TextureCubeView&                   baseView,
1965                                                           const float*                                                  texCoord,
1966                                                           const ReferenceParams&                                sampleParams,
1967                                                           const tcu::LookupPrecision&                   lookupPrec,
1968                                                           const tcu::LodPrecision&                              lodPrec,
1969                                                           qpWatchDog*                                                   watchDog)
1970 {
1971         DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
1972         DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
1973
1974         const tcu::TextureCubeView      src             = getSubView(baseView, sampleParams.baseLevel, sampleParams.maxLevel);
1975
1976         const tcu::Vec4         sq                              = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
1977         const tcu::Vec4         tq                              = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
1978         const tcu::Vec4         rq                              = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
1979
1980         const tcu::IVec2        dstSize                 = tcu::IVec2(result.getWidth(), result.getHeight());
1981         const float                     dstW                    = float(dstSize.x());
1982         const float                     dstH                    = float(dstSize.y());
1983         const int                       srcSize                 = src.getSize();
1984
1985         // Coordinates per triangle.
1986         const tcu::Vec3         triS[2]                 = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
1987         const tcu::Vec3         triT[2]                 = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
1988         const tcu::Vec3         triR[2]                 = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
1989         const tcu::Vec3         triW[2]                 = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
1990
1991         const tcu::Vec2         lodBias                 ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
1992
1993         const float                     posEps                  = 1.0f / float(1<<MIN_SUBPIXEL_BITS);
1994
1995         int                                     numFailed               = 0;
1996
1997         const tcu::Vec2 lodOffsets[] =
1998         {
1999                 tcu::Vec2(-1,  0),
2000                 tcu::Vec2(+1,  0),
2001                 tcu::Vec2( 0, -1),
2002                 tcu::Vec2( 0, +1),
2003
2004                 // \note Not strictly allowed by spec, but implementations do this in practice.
2005                 tcu::Vec2(-1, -1),
2006                 tcu::Vec2(-1, +1),
2007                 tcu::Vec2(+1, -1),
2008                 tcu::Vec2(+1, +1),
2009         };
2010
2011         tcu::clear(errorMask, tcu::RGBA::green.toVec());
2012
2013         for (int py = 0; py < result.getHeight(); py++)
2014         {
2015                 // Ugly hack, validation can take way too long at the moment.
2016                 if (watchDog)
2017                         qpWatchDog_touch(watchDog);
2018
2019                 for (int px = 0; px < result.getWidth(); px++)
2020                 {
2021                         const tcu::Vec4 resPix  = (result.getPixel(px, py)              - sampleParams.colorBias) / sampleParams.colorScale;
2022                         const tcu::Vec4 refPix  = (reference.getPixel(px, py)   - sampleParams.colorBias) / sampleParams.colorScale;
2023
2024                         // Try comparison to ideal reference first, and if that fails use slower verificator.
2025                         if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
2026                         {
2027                                 const float             wx              = (float)px + 0.5f;
2028                                 const float             wy              = (float)py + 0.5f;
2029                                 const float             nx              = wx / dstW;
2030                                 const float             ny              = wy / dstH;
2031
2032                                 const bool              tri0    = (wx-posEps)/dstW + (wy-posEps)/dstH <= 1.0f;
2033                                 const bool              tri1    = (wx+posEps)/dstW + (wy+posEps)/dstH >= 1.0f;
2034
2035                                 bool                    isOk    = false;
2036
2037                                 DE_ASSERT(tri0 || tri1);
2038
2039                                 // Pixel can belong to either of the triangles if it lies close enough to the edge.
2040                                 for (int triNdx = (tri0?0:1); triNdx <= (tri1?1:0); triNdx++)
2041                                 {
2042                                         const float             triWx   = triNdx ? dstW - wx : wx;
2043                                         const float             triWy   = triNdx ? dstH - wy : wy;
2044                                         const float             triNx   = triNdx ? 1.0f - nx : nx;
2045                                         const float             triNy   = triNdx ? 1.0f - ny : ny;
2046
2047                                         const tcu::Vec3 coord           (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
2048                                                                                                  projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
2049                                                                                                  projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy));
2050                                         const tcu::Vec3 coordDx         (triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
2051                                                                                                  triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy),
2052                                                                                                  triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy));
2053                                         const tcu::Vec3 coordDy         (triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
2054                                                                                                  triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx),
2055                                                                                                  triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx));
2056
2057                                         tcu::Vec2               lodBounds       = tcu::computeCubeLodBoundsFromDerivates(coord, coordDx, coordDy, srcSize, lodPrec);
2058
2059                                         // Compute lod bounds across lodOffsets range.
2060                                         for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
2061                                         {
2062                                                 const float             wxo             = triWx + lodOffsets[lodOffsNdx].x();
2063                                                 const float             wyo             = triWy + lodOffsets[lodOffsNdx].y();
2064                                                 const float             nxo             = wxo/dstW;
2065                                                 const float             nyo             = wyo/dstH;
2066
2067                                                 const tcu::Vec3 coordO          (projectedTriInterpolate(triS[triNdx], triW[triNdx], nxo, nyo),
2068                                                                                                          projectedTriInterpolate(triT[triNdx], triW[triNdx], nxo, nyo),
2069                                                                                                          projectedTriInterpolate(triR[triNdx], triW[triNdx], nxo, nyo));
2070                                                 const tcu::Vec3 coordDxo        (triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
2071                                                                                                          triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo),
2072                                                                                                          triDerivateX(triR[triNdx], triW[triNdx], wxo, dstW, nyo));
2073                                                 const tcu::Vec3 coordDyo        (triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
2074                                                                                                          triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo),
2075                                                                                                          triDerivateY(triR[triNdx], triW[triNdx], wyo, dstH, nxo));
2076                                                 const tcu::Vec2 lodO            = tcu::computeCubeLodBoundsFromDerivates(coordO, coordDxo, coordDyo, srcSize, lodPrec);
2077
2078                                                 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
2079                                                 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
2080                                         }
2081
2082                                         const tcu::Vec2 clampedLod      = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
2083
2084                                         if (tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix))
2085                                         {
2086                                                 isOk = true;
2087                                                 break;
2088                                         }
2089                                 }
2090
2091                                 if (!isOk)
2092                                 {
2093                                         errorMask.setPixel(tcu::RGBA::red.toVec(), px, py);
2094                                         numFailed += 1;
2095                                 }
2096                         }
2097                 }
2098         }
2099
2100         return numFailed;
2101 }
2102
2103 bool verifyTextureResult (tcu::TestContext&                                             testCtx,
2104                                                   const tcu::ConstPixelBufferAccess&    result,
2105                                                   const tcu::TextureCubeView&                   src,
2106                                                   const float*                                                  texCoord,
2107                                                   const ReferenceParams&                                sampleParams,
2108                                                   const tcu::LookupPrecision&                   lookupPrec,
2109                                                   const tcu::LodPrecision&                              lodPrec,
2110                                                   const tcu::PixelFormat&                               pixelFormat)
2111 {
2112         tcu::TestLog&   log                             = testCtx.getLog();
2113         tcu::Surface    reference               (result.getWidth(), result.getHeight());
2114         tcu::Surface    errorMask               (result.getWidth(), result.getHeight());
2115         int                             numFailedPixels;
2116
2117         DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
2118
2119         sampleTextureMultiFace(SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
2120         numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog());
2121
2122         if (numFailedPixels > 0)
2123                 log << TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
2124
2125         log << TestLog::ImageSet("VerifyResult", "Verification result")
2126                 << TestLog::Image("Rendered", "Rendered image", result);
2127
2128         if (numFailedPixels > 0)
2129         {
2130                 log << TestLog::Image("Reference", "Ideal reference image", reference)
2131                         << TestLog::Image("ErrorMask", "Error mask", errorMask);
2132         }
2133
2134         log << TestLog::EndImageSet;
2135
2136         return numFailedPixels == 0;
2137 }
2138
2139 //! Verifies texture lookup results and returns number of failed pixels.
2140 int computeTextureLookupDiff (const tcu::ConstPixelBufferAccess&        result,
2141                                                           const tcu::ConstPixelBufferAccess&    reference,
2142                                                           const tcu::PixelBufferAccess&                 errorMask,
2143                                                           const tcu::Texture3DView&                             baseView,
2144                                                           const float*                                                  texCoord,
2145                                                           const ReferenceParams&                                sampleParams,
2146                                                           const tcu::LookupPrecision&                   lookupPrec,
2147                                                           const tcu::LodPrecision&                              lodPrec,
2148                                                           qpWatchDog*                                                   watchDog)
2149 {
2150         DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
2151         DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
2152
2153         const tcu::Texture3DView        src             = getSubView(baseView, sampleParams.baseLevel, sampleParams.maxLevel);
2154
2155         const tcu::Vec4         sq                              = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
2156         const tcu::Vec4         tq                              = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
2157         const tcu::Vec4         rq                              = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
2158
2159         const tcu::IVec2        dstSize                 = tcu::IVec2(result.getWidth(), result.getHeight());
2160         const float                     dstW                    = float(dstSize.x());
2161         const float                     dstH                    = float(dstSize.y());
2162         const tcu::IVec3        srcSize                 = tcu::IVec3(src.getWidth(), src.getHeight(), src.getDepth());
2163
2164         // Coordinates and lod per triangle.
2165         const tcu::Vec3         triS[2]                 = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
2166         const tcu::Vec3         triT[2]                 = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
2167         const tcu::Vec3         triR[2]                 = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
2168         const tcu::Vec3         triW[2]                 = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
2169
2170         const tcu::Vec2         lodBias                 ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
2171
2172         const float                     posEps                  = 1.0f / float(1<<MIN_SUBPIXEL_BITS);
2173
2174         int                                     numFailed               = 0;
2175
2176         const tcu::Vec2 lodOffsets[] =
2177         {
2178                 tcu::Vec2(-1,  0),
2179                 tcu::Vec2(+1,  0),
2180                 tcu::Vec2( 0, -1),
2181                 tcu::Vec2( 0, +1),
2182         };
2183
2184         tcu::clear(errorMask, tcu::RGBA::green.toVec());
2185
2186         for (int py = 0; py < result.getHeight(); py++)
2187         {
2188                 // Ugly hack, validation can take way too long at the moment.
2189                 if (watchDog)
2190                         qpWatchDog_touch(watchDog);
2191
2192                 for (int px = 0; px < result.getWidth(); px++)
2193                 {
2194                         const tcu::Vec4 resPix  = (result.getPixel(px, py)              - sampleParams.colorBias) / sampleParams.colorScale;
2195                         const tcu::Vec4 refPix  = (reference.getPixel(px, py)   - sampleParams.colorBias) / sampleParams.colorScale;
2196
2197                         // Try comparison to ideal reference first, and if that fails use slower verificator.
2198                         if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
2199                         {
2200                                 const float             wx              = (float)px + 0.5f;
2201                                 const float             wy              = (float)py + 0.5f;
2202                                 const float             nx              = wx / dstW;
2203                                 const float             ny              = wy / dstH;
2204
2205                                 const bool              tri0    = (wx-posEps)/dstW + (wy-posEps)/dstH <= 1.0f;
2206                                 const bool              tri1    = (wx+posEps)/dstW + (wy+posEps)/dstH >= 1.0f;
2207
2208                                 bool                    isOk    = false;
2209
2210                                 DE_ASSERT(tri0 || tri1);
2211
2212                                 // Pixel can belong to either of the triangles if it lies close enough to the edge.
2213                                 for (int triNdx = (tri0?0:1); triNdx <= (tri1?1:0); triNdx++)
2214                                 {
2215                                         const float             triWx   = triNdx ? dstW - wx : wx;
2216                                         const float             triWy   = triNdx ? dstH - wy : wy;
2217                                         const float             triNx   = triNdx ? 1.0f - nx : nx;
2218                                         const float             triNy   = triNdx ? 1.0f - ny : ny;
2219
2220                                         const tcu::Vec3 coord           (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
2221                                                                                                  projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
2222                                                                                                  projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy));
2223                                         const tcu::Vec3 coordDx         = tcu::Vec3(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
2224                                                                                                                         triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy),
2225                                                                                                                         triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy)) * srcSize.asFloat();
2226                                         const tcu::Vec3 coordDy         = tcu::Vec3(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
2227                                                                                                                         triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx),
2228                                                                                                                         triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx)) * srcSize.asFloat();
2229
2230                                         tcu::Vec2               lodBounds       = tcu::computeLodBoundsFromDerivates(coordDx.x(), coordDx.y(), coordDx.z(), coordDy.x(), coordDy.y(), coordDy.z(), lodPrec);
2231
2232                                         // Compute lod bounds across lodOffsets range.
2233                                         for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
2234                                         {
2235                                                 const float             wxo             = triWx + lodOffsets[lodOffsNdx].x();
2236                                                 const float             wyo             = triWy + lodOffsets[lodOffsNdx].y();
2237                                                 const float             nxo             = wxo/dstW;
2238                                                 const float             nyo             = wyo/dstH;
2239
2240                                                 const tcu::Vec3 coordO          (projectedTriInterpolate(triS[triNdx], triW[triNdx], nxo, nyo),
2241                                                                                                          projectedTriInterpolate(triT[triNdx], triW[triNdx], nxo, nyo),
2242                                                                                                          projectedTriInterpolate(triR[triNdx], triW[triNdx], nxo, nyo));
2243                                                 const tcu::Vec3 coordDxo        = tcu::Vec3(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
2244                                                                                                                                 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo),
2245                                                                                                                                 triDerivateX(triR[triNdx], triW[triNdx], wxo, dstW, nyo)) * srcSize.asFloat();
2246                                                 const tcu::Vec3 coordDyo        = tcu::Vec3(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
2247                                                                                                                                 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo),
2248                                                                                                                                 triDerivateY(triR[triNdx], triW[triNdx], wyo, dstH, nxo)) * srcSize.asFloat();
2249                                                 const tcu::Vec2 lodO            = tcu::computeLodBoundsFromDerivates(coordDxo.x(), coordDxo.y(), coordDxo.z(), coordDyo.x(), coordDyo.y(), coordDyo.z(), lodPrec);
2250
2251                                                 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
2252                                                 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
2253                                         }
2254
2255                                         const tcu::Vec2 clampedLod      = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
2256
2257                                         if (tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix))
2258                                         {
2259                                                 isOk = true;
2260                                                 break;
2261                                         }
2262                                 }
2263
2264                                 if (!isOk)
2265                                 {
2266                                         errorMask.setPixel(tcu::RGBA::red.toVec(), px, py);
2267                                         numFailed += 1;
2268                                 }
2269                         }
2270                 }
2271         }
2272
2273         return numFailed;
2274 }
2275
2276 bool verifyTextureResult (tcu::TestContext&                                             testCtx,
2277                                                   const tcu::ConstPixelBufferAccess&    result,
2278                                                   const tcu::Texture3DView&                             src,
2279                                                   const float*                                                  texCoord,
2280                                                   const ReferenceParams&                                sampleParams,
2281                                                   const tcu::LookupPrecision&                   lookupPrec,
2282                                                   const tcu::LodPrecision&                              lodPrec,
2283                                                   const tcu::PixelFormat&                               pixelFormat)
2284 {
2285         tcu::TestLog&   log                             = testCtx.getLog();
2286         tcu::Surface    reference               (result.getWidth(), result.getHeight());
2287         tcu::Surface    errorMask               (result.getWidth(), result.getHeight());
2288         int                             numFailedPixels;
2289
2290         DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
2291
2292         sampleTexture(SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
2293         numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog());
2294
2295         if (numFailedPixels > 0)
2296                 log << TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
2297
2298         log << TestLog::ImageSet("VerifyResult", "Verification result")
2299                 << TestLog::Image("Rendered", "Rendered image", result);
2300
2301         if (numFailedPixels > 0)
2302         {
2303                 log << TestLog::Image("Reference", "Ideal reference image", reference)
2304                         << TestLog::Image("ErrorMask", "Error mask", errorMask);
2305         }
2306
2307         log << TestLog::EndImageSet;
2308
2309         return numFailedPixels == 0;
2310 }
2311
2312 //! Verifies texture lookup results and returns number of failed pixels.
2313 int computeTextureLookupDiff (const tcu::ConstPixelBufferAccess&        result,
2314                                                           const tcu::ConstPixelBufferAccess&    reference,
2315                                                           const tcu::PixelBufferAccess&                 errorMask,
2316                                                           const tcu::Texture1DArrayView&                src,
2317                                                           const float*                                                  texCoord,
2318                                                           const ReferenceParams&                                sampleParams,
2319                                                           const tcu::LookupPrecision&                   lookupPrec,
2320                                                           const tcu::LodPrecision&                              lodPrec,
2321                                                           qpWatchDog*                                                   watchDog)
2322 {
2323         DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
2324         DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
2325
2326         const tcu::Vec4         sq                              = tcu::Vec4(texCoord[0+0], texCoord[2+0], texCoord[4+0], texCoord[6+0]);
2327         const tcu::Vec4         tq                              = tcu::Vec4(texCoord[0+1], texCoord[2+1], texCoord[4+1], texCoord[6+1]);
2328
2329         const tcu::IVec2        dstSize                 = tcu::IVec2(result.getWidth(), result.getHeight());
2330         const float                     dstW                    = float(dstSize.x());
2331         const float                     dstH                    = float(dstSize.y());
2332         const float                     srcSize                 = float(src.getWidth()); // For lod computation, thus #layers is ignored.
2333
2334         // Coordinates and lod per triangle.
2335         const tcu::Vec3         triS[2]                 = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
2336         const tcu::Vec3         triT[2]                 = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
2337         const tcu::Vec3         triW[2]                 = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
2338
2339         const tcu::Vec2         lodBias                 ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
2340
2341         int                                     numFailed               = 0;
2342
2343         const tcu::Vec2 lodOffsets[] =
2344         {
2345                 tcu::Vec2(-1,  0),
2346                 tcu::Vec2(+1,  0),
2347                 tcu::Vec2( 0, -1),
2348                 tcu::Vec2( 0, +1),
2349         };
2350
2351         tcu::clear(errorMask, tcu::RGBA::green.toVec());
2352
2353         for (int py = 0; py < result.getHeight(); py++)
2354         {
2355                 // Ugly hack, validation can take way too long at the moment.
2356                 if (watchDog)
2357                         qpWatchDog_touch(watchDog);
2358
2359                 for (int px = 0; px < result.getWidth(); px++)
2360                 {
2361                         const tcu::Vec4 resPix  = (result.getPixel(px, py)              - sampleParams.colorBias) / sampleParams.colorScale;
2362                         const tcu::Vec4 refPix  = (reference.getPixel(px, py)   - sampleParams.colorBias) / sampleParams.colorScale;
2363
2364                         // Try comparison to ideal reference first, and if that fails use slower verificator.
2365                         if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
2366                         {
2367                                 const float             wx              = (float)px + 0.5f;
2368                                 const float             wy              = (float)py + 0.5f;
2369                                 const float             nx              = wx / dstW;
2370                                 const float             ny              = wy / dstH;
2371
2372                                 const int               triNdx  = nx + ny >= 1.0f ? 1 : 0;
2373                                 const float             triWx   = triNdx ? dstW - wx : wx;
2374                                 const float             triWy   = triNdx ? dstH - wy : wy;
2375                                 const float             triNx   = triNdx ? 1.0f - nx : nx;
2376                                 const float             triNy   = triNdx ? 1.0f - ny : ny;
2377
2378                                 const tcu::Vec2 coord   (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
2379                                                                                  projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy));
2380                                 const float     coordDx         = triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy) * srcSize;
2381                                 const float     coordDy         = triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx) * srcSize;
2382
2383                                 tcu::Vec2               lodBounds       = tcu::computeLodBoundsFromDerivates(coordDx, coordDy, lodPrec);
2384
2385                                 // Compute lod bounds across lodOffsets range.
2386                                 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
2387                                 {
2388                                         const float             wxo             = triWx + lodOffsets[lodOffsNdx].x();
2389                                         const float             wyo             = triWy + lodOffsets[lodOffsNdx].y();
2390                                         const float             nxo             = wxo/dstW;
2391                                         const float             nyo             = wyo/dstH;
2392
2393                                         const tcu::Vec2 coordO          (projectedTriInterpolate(triS[triNdx], triW[triNdx], nxo, nyo),
2394                                                                                                  projectedTriInterpolate(triT[triNdx], triW[triNdx], nxo, nyo));
2395                                         const float     coordDxo                = triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo) * srcSize;
2396                                         const float     coordDyo                = triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo) * srcSize;
2397                                         const tcu::Vec2 lodO            = tcu::computeLodBoundsFromDerivates(coordDxo, coordDyo, lodPrec);
2398
2399                                         lodBounds.x() = de::min(lodBounds.x(), lodO.x());
2400                                         lodBounds.y() = de::max(lodBounds.y(), lodO.y());
2401                                 }
2402
2403                                 const tcu::Vec2 clampedLod      = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
2404                                 const bool              isOk            = tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix);
2405
2406                                 if (!isOk)
2407                                 {
2408                                         errorMask.setPixel(tcu::RGBA::red.toVec(), px, py);
2409                                         numFailed += 1;
2410                                 }
2411                         }
2412                 }
2413         }
2414
2415         return numFailed;
2416 }
2417
2418 //! Verifies texture lookup results and returns number of failed pixels.
2419 int computeTextureLookupDiff (const tcu::ConstPixelBufferAccess&        result,
2420                                                           const tcu::ConstPixelBufferAccess&    reference,
2421                                                           const tcu::PixelBufferAccess&                 errorMask,
2422                                                           const tcu::Texture2DArrayView&                src,
2423                                                           const float*                                                  texCoord,
2424                                                           const ReferenceParams&                                sampleParams,
2425                                                           const tcu::LookupPrecision&                   lookupPrec,
2426                                                           const tcu::LodPrecision&                              lodPrec,
2427                                                           qpWatchDog*                                                   watchDog)
2428 {
2429         DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
2430         DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
2431
2432         const tcu::Vec4         sq                              = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
2433         const tcu::Vec4         tq                              = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
2434         const tcu::Vec4         rq                              = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
2435
2436         const tcu::IVec2        dstSize                 = tcu::IVec2(result.getWidth(), result.getHeight());
2437         const float                     dstW                    = float(dstSize.x());
2438         const float                     dstH                    = float(dstSize.y());
2439         const tcu::Vec2         srcSize                 = tcu::IVec2(src.getWidth(), src.getHeight()).asFloat(); // For lod computation, thus #layers is ignored.
2440
2441         // Coordinates and lod per triangle.
2442         const tcu::Vec3         triS[2]                 = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
2443         const tcu::Vec3         triT[2]                 = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
2444         const tcu::Vec3         triR[2]                 = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
2445         const tcu::Vec3         triW[2]                 = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
2446
2447         const tcu::Vec2         lodBias                 ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
2448
2449         int                                     numFailed               = 0;
2450
2451         const tcu::Vec2 lodOffsets[] =
2452         {
2453                 tcu::Vec2(-1,  0),
2454                 tcu::Vec2(+1,  0),
2455                 tcu::Vec2( 0, -1),
2456                 tcu::Vec2( 0, +1),
2457         };
2458
2459         tcu::clear(errorMask, tcu::RGBA::green.toVec());
2460
2461         for (int py = 0; py < result.getHeight(); py++)
2462         {
2463                 // Ugly hack, validation can take way too long at the moment.
2464                 if (watchDog)
2465                         qpWatchDog_touch(watchDog);
2466
2467                 for (int px = 0; px < result.getWidth(); px++)
2468                 {
2469                         const tcu::Vec4 resPix  = (result.getPixel(px, py)              - sampleParams.colorBias) / sampleParams.colorScale;
2470                         const tcu::Vec4 refPix  = (reference.getPixel(px, py)   - sampleParams.colorBias) / sampleParams.colorScale;
2471
2472                         // Try comparison to ideal reference first, and if that fails use slower verificator.
2473                         if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
2474                         {
2475                                 const float             wx              = (float)px + 0.5f;
2476                                 const float             wy              = (float)py + 0.5f;
2477                                 const float             nx              = wx / dstW;
2478                                 const float             ny              = wy / dstH;
2479
2480                                 const int               triNdx  = nx + ny >= 1.0f ? 1 : 0;
2481                                 const float             triWx   = triNdx ? dstW - wx : wx;
2482                                 const float             triWy   = triNdx ? dstH - wy : wy;
2483                                 const float             triNx   = triNdx ? 1.0f - nx : nx;
2484                                 const float             triNy   = triNdx ? 1.0f - ny : ny;
2485
2486                                 const tcu::Vec3 coord           (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
2487                                                                                          projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
2488                                                                                          projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy));
2489                                 const tcu::Vec2 coordDx         = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
2490                                                                                                                 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy)) * srcSize;
2491                                 const tcu::Vec2 coordDy         = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
2492                                                                                                                 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx)) * srcSize;
2493
2494                                 tcu::Vec2               lodBounds       = tcu::computeLodBoundsFromDerivates(coordDx.x(), coordDx.y(), coordDy.x(), coordDy.y(), lodPrec);
2495
2496                                 // Compute lod bounds across lodOffsets range.
2497                                 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
2498                                 {
2499                                         const float             wxo             = triWx + lodOffsets[lodOffsNdx].x();
2500                                         const float             wyo             = triWy + lodOffsets[lodOffsNdx].y();
2501                                         const float             nxo             = wxo/dstW;
2502                                         const float             nyo             = wyo/dstH;
2503
2504                                         const tcu::Vec3 coordO          (projectedTriInterpolate(triS[triNdx], triW[triNdx], nxo, nyo),
2505                                                                                                  projectedTriInterpolate(triT[triNdx], triW[triNdx], nxo, nyo),
2506                                                                                                  projectedTriInterpolate(triR[triNdx], triW[triNdx], nxo, nyo));
2507                                         const tcu::Vec2 coordDxo        = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
2508                                                                                                                         triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo)) * srcSize;
2509                                         const tcu::Vec2 coordDyo        = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
2510                                                                                                                         triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo)) * srcSize;
2511                                         const tcu::Vec2 lodO            = tcu::computeLodBoundsFromDerivates(coordDxo.x(), coordDxo.y(), coordDyo.x(), coordDyo.y(), lodPrec);
2512
2513                                         lodBounds.x() = de::min(lodBounds.x(), lodO.x());
2514                                         lodBounds.y() = de::max(lodBounds.y(), lodO.y());
2515                                 }
2516
2517                                 const tcu::Vec2 clampedLod      = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
2518                                 const bool              isOk            = tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix);
2519
2520                                 if (!isOk)
2521                                 {
2522                                         errorMask.setPixel(tcu::RGBA::red.toVec(), px, py);
2523                                         numFailed += 1;
2524                                 }
2525                         }
2526                 }
2527         }
2528
2529         return numFailed;
2530 }
2531
2532 bool verifyTextureResult (tcu::TestContext&                                             testCtx,
2533                                                   const tcu::ConstPixelBufferAccess&    result,
2534                                                   const tcu::Texture1DArrayView&                src,
2535                                                   const float*                                                  texCoord,
2536                                                   const ReferenceParams&                                sampleParams,
2537                                                   const tcu::LookupPrecision&                   lookupPrec,
2538                                                   const tcu::LodPrecision&                              lodPrec,
2539                                                   const tcu::PixelFormat&                               pixelFormat)
2540 {
2541         tcu::TestLog&   log                             = testCtx.getLog();
2542         tcu::Surface    reference               (result.getWidth(), result.getHeight());
2543         tcu::Surface    errorMask               (result.getWidth(), result.getHeight());
2544         int                             numFailedPixels;
2545
2546         DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
2547
2548         sampleTexture(SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
2549         numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog());
2550
2551         if (numFailedPixels > 0)
2552                 log << TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
2553
2554         log << TestLog::ImageSet("VerifyResult", "Verification result")
2555                 << TestLog::Image("Rendered", "Rendered image", result);
2556
2557         if (numFailedPixels > 0)
2558         {
2559                 log << TestLog::Image("Reference", "Ideal reference image", reference)
2560                         << TestLog::Image("ErrorMask", "Error mask", errorMask);
2561         }
2562
2563         log << TestLog::EndImageSet;
2564
2565         return numFailedPixels == 0;
2566 }
2567
2568 bool verifyTextureResult (tcu::TestContext&                                             testCtx,
2569                                                   const tcu::ConstPixelBufferAccess&    result,
2570                                                   const tcu::Texture2DArrayView&                src,
2571                                                   const float*                                                  texCoord,
2572                                                   const ReferenceParams&                                sampleParams,
2573                                                   const tcu::LookupPrecision&                   lookupPrec,
2574                                                   const tcu::LodPrecision&                              lodPrec,
2575                                                   const tcu::PixelFormat&                               pixelFormat)
2576 {
2577         tcu::TestLog&   log                             = testCtx.getLog();
2578         tcu::Surface    reference               (result.getWidth(), result.getHeight());
2579         tcu::Surface    errorMask               (result.getWidth(), result.getHeight());
2580         int                             numFailedPixels;
2581
2582         DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
2583
2584         sampleTexture(SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
2585         numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog());
2586
2587         if (numFailedPixels > 0)
2588                 log << TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
2589
2590         log << TestLog::ImageSet("VerifyResult", "Verification result")
2591                 << TestLog::Image("Rendered", "Rendered image", result);
2592
2593         if (numFailedPixels > 0)
2594         {
2595                 log << TestLog::Image("Reference", "Ideal reference image", reference)
2596                         << TestLog::Image("ErrorMask", "Error mask", errorMask);
2597         }
2598
2599         log << TestLog::EndImageSet;
2600
2601         return numFailedPixels == 0;
2602 }
2603
2604 //! Verifies texture lookup results and returns number of failed pixels.
2605 int computeTextureLookupDiff (const tcu::ConstPixelBufferAccess&        result,
2606                                                           const tcu::ConstPixelBufferAccess&    reference,
2607                                                           const tcu::PixelBufferAccess&                 errorMask,
2608                                                           const tcu::TextureCubeArrayView&              baseView,
2609                                                           const float*                                                  texCoord,
2610                                                           const ReferenceParams&                                sampleParams,
2611                                                           const tcu::LookupPrecision&                   lookupPrec,
2612                                                           const tcu::IVec4&                                             coordBits,
2613                                                           const tcu::LodPrecision&                              lodPrec,
2614                                                           qpWatchDog*                                                   watchDog)
2615 {
2616         DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
2617         DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
2618
2619         const tcu::TextureCubeArrayView src     = getSubView(baseView, sampleParams.baseLevel, sampleParams.maxLevel);
2620
2621         // What is the 'q' in all these names? Also a two char name for something that is in scope for ~120 lines and only used twice each seems excessive
2622         const tcu::Vec4         sq                              = tcu::Vec4(texCoord[0+0], texCoord[4+0], texCoord[8+0], texCoord[12+0]);
2623         const tcu::Vec4         tq                              = tcu::Vec4(texCoord[0+1], texCoord[4+1], texCoord[8+1], texCoord[12+1]);
2624         const tcu::Vec4         rq                              = tcu::Vec4(texCoord[0+2], texCoord[4+2], texCoord[8+2], texCoord[12+2]);
2625         const tcu::Vec4         qq                              = tcu::Vec4(texCoord[0+3], texCoord[4+3], texCoord[8+3], texCoord[12+3]);
2626
2627         const tcu::IVec2        dstSize                 = tcu::IVec2(result.getWidth(), result.getHeight());
2628         const float                     dstW                    = float(dstSize.x());
2629         const float                     dstH                    = float(dstSize.y());
2630         const int                       srcSize                 = src.getSize();
2631
2632         // Coordinates per triangle.
2633         const tcu::Vec3         triS[2]                 = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
2634         const tcu::Vec3         triT[2]                 = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
2635         const tcu::Vec3         triR[2]                 = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
2636         const tcu::Vec3         triQ[2]                 = { qq.swizzle(0, 1, 2), qq.swizzle(3, 2, 1) };
2637         const tcu::Vec3         triW[2]                 = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
2638
2639         const tcu::Vec2         lodBias                 ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
2640
2641         const float                     posEps                  = 1.0f / float((1<<4) + 1); // ES3 requires at least 4 subpixel bits.
2642
2643         int                                     numFailed               = 0;
2644
2645         const tcu::Vec2 lodOffsets[] =
2646         {
2647                 tcu::Vec2(-1,  0),
2648                 tcu::Vec2(+1,  0),
2649                 tcu::Vec2( 0, -1),
2650                 tcu::Vec2( 0, +1),
2651
2652                 // \note Not strictly allowed by spec, but implementations do this in practice.
2653                 tcu::Vec2(-1, -1),
2654                 tcu::Vec2(-1, +1),
2655                 tcu::Vec2(+1, -1),
2656                 tcu::Vec2(+1, +1),
2657         };
2658
2659         tcu::clear(errorMask, tcu::RGBA::green.toVec());
2660
2661         for (int py = 0; py < result.getHeight(); py++)
2662         {
2663                 // Ugly hack, validation can take way too long at the moment.
2664                 if (watchDog)
2665                         qpWatchDog_touch(watchDog);
2666
2667                 for (int px = 0; px < result.getWidth(); px++)
2668                 {
2669                         const tcu::Vec4 resPix  = (result.getPixel(px, py)              - sampleParams.colorBias) / sampleParams.colorScale;
2670                         const tcu::Vec4 refPix  = (reference.getPixel(px, py)   - sampleParams.colorBias) / sampleParams.colorScale;
2671
2672                         // Try comparison to ideal reference first, and if that fails use slower verificator.
2673                         if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
2674                         {
2675                                 const float             wx              = (float)px + 0.5f;
2676                                 const float             wy              = (float)py + 0.5f;
2677                                 const float             nx              = wx / dstW;
2678                                 const float             ny              = wy / dstH;
2679
2680                                 const bool              tri0    = nx + ny - posEps <= 1.0f;
2681                                 const bool              tri1    = nx + ny + posEps >= 1.0f;
2682
2683                                 bool                    isOk    = false;
2684
2685                                 DE_ASSERT(tri0 || tri1);
2686
2687                                 // Pixel can belong to either of the triangles if it lies close enough to the edge.
2688                                 for (int triNdx = (tri0?0:1); triNdx <= (tri1?1:0); triNdx++)
2689                                 {
2690                                         const float             triWx           = triNdx ? dstW - wx : wx;
2691                                         const float             triWy           = triNdx ? dstH - wy : wy;
2692                                         const float             triNx           = triNdx ? 1.0f - nx : nx;
2693                                         const float             triNy           = triNdx ? 1.0f - ny : ny;
2694
2695                                         const tcu::Vec4 coord           (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
2696                                                                                                  projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
2697                                                                                                  projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy),
2698                                                                                                  projectedTriInterpolate(triQ[triNdx], triW[triNdx], triNx, triNy));
2699                                         const tcu::Vec3 coordDx         (triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
2700                                                                                                  triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy),
2701                                                                                                  triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy));
2702                                         const tcu::Vec3 coordDy         (triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
2703                                                                                                  triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx),
2704                                                                                                  triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx));
2705
2706                                         tcu::Vec2               lodBounds       = tcu::computeCubeLodBoundsFromDerivates(coord.toWidth<3>(), coordDx, coordDy, srcSize, lodPrec);
2707
2708                                         // Compute lod bounds across lodOffsets range.
2709                                         for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
2710                                         {
2711                                                 const float             wxo                     = triWx + lodOffsets[lodOffsNdx].x();
2712                                                 const float             wyo                     = triWy + lodOffsets[lodOffsNdx].y();
2713                                                 const float             nxo                     = wxo/dstW;
2714                                                 const float             nyo                     = wyo/dstH;
2715
2716                                                 const tcu::Vec3 coordO          (projectedTriInterpolate(triS[triNdx], triW[triNdx], nxo, nyo),
2717                                                                                                          projectedTriInterpolate(triT[triNdx], triW[triNdx], nxo, nyo),
2718                                                                                                          projectedTriInterpolate(triR[triNdx], triW[triNdx], nxo, nyo));
2719                                                 const tcu::Vec3 coordDxo        (triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
2720                                                                                                          triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo),
2721                                                                                                          triDerivateX(triR[triNdx], triW[triNdx], wxo, dstW, nyo));
2722                                                 const tcu::Vec3 coordDyo        (triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
2723                                                                                                          triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo),
2724                                                                                                          triDerivateY(triR[triNdx], triW[triNdx], wyo, dstH, nxo));
2725                                                 const tcu::Vec2 lodO            = tcu::computeCubeLodBoundsFromDerivates(coordO, coordDxo, coordDyo, srcSize, lodPrec);
2726
2727                                                 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
2728                                                 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
2729                                         }
2730
2731                                         const tcu::Vec2 clampedLod      = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
2732
2733                                         if (tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coordBits, coord, clampedLod, resPix))
2734                                         {
2735                                                 isOk = true;
2736                                                 break;
2737                                         }
2738                                 }
2739
2740                                 if (!isOk)
2741                                 {
2742                                         errorMask.setPixel(tcu::RGBA::red.toVec(), px, py);
2743                                         numFailed += 1;
2744                                 }
2745                         }
2746                 }
2747         }
2748
2749         return numFailed;
2750 }
2751
2752 bool verifyTextureResult (tcu::TestContext&                                             testCtx,
2753                                                   const tcu::ConstPixelBufferAccess&    result,
2754                                                   const tcu::TextureCubeArrayView&              src,
2755                                                   const float*                                                  texCoord,
2756                                                   const ReferenceParams&                                sampleParams,
2757                                                   const tcu::LookupPrecision&                   lookupPrec,
2758                                                   const tcu::IVec4&                                             coordBits,
2759                                                   const tcu::LodPrecision&                              lodPrec,
2760                                                   const tcu::PixelFormat&                               pixelFormat)
2761 {
2762         tcu::TestLog&   log                             = testCtx.getLog();
2763         tcu::Surface    reference               (result.getWidth(), result.getHeight());
2764         tcu::Surface    errorMask               (result.getWidth(), result.getHeight());
2765         int                             numFailedPixels;
2766
2767         DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
2768
2769         sampleTexture(SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
2770         numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, coordBits, lodPrec, testCtx.getWatchDog());
2771
2772         if (numFailedPixels > 0)
2773                 log << TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
2774
2775         log << TestLog::ImageSet("VerifyResult", "Verification result")
2776                 << TestLog::Image("Rendered", "Rendered image", result);
2777
2778         if (numFailedPixels > 0)
2779         {
2780                 log << TestLog::Image("Reference", "Ideal reference image", reference)
2781                         << TestLog::Image("ErrorMask", "Error mask", errorMask);
2782         }
2783
2784         log << TestLog::EndImageSet;
2785
2786         return numFailedPixels == 0;
2787 }
2788
2789 // Shadow lookup verification
2790
2791 int computeTextureCompareDiff (const tcu::ConstPixelBufferAccess&       result,
2792                                                            const tcu::ConstPixelBufferAccess&   reference,
2793                                                            const tcu::PixelBufferAccess&                errorMask,
2794                                                            const tcu::Texture2DView&                    src,
2795                                                            const float*                                                 texCoord,
2796                                                            const ReferenceParams&                               sampleParams,
2797                                                            const tcu::TexComparePrecision&              comparePrec,
2798                                                            const tcu::LodPrecision&                             lodPrec,
2799                                                            const tcu::Vec3&                                             nonShadowThreshold)
2800 {
2801         DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
2802         DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
2803
2804         const tcu::Vec4         sq                              = tcu::Vec4(texCoord[0+0], texCoord[2+0], texCoord[4+0], texCoord[6+0]);
2805         const tcu::Vec4         tq                              = tcu::Vec4(texCoord[0+1], texCoord[2+1], texCoord[4+1], texCoord[6+1]);
2806
2807         const tcu::IVec2        dstSize                 = tcu::IVec2(result.getWidth(), result.getHeight());
2808         const float                     dstW                    = float(dstSize.x());
2809         const float                     dstH                    = float(dstSize.y());
2810         const tcu::IVec2        srcSize                 = tcu::IVec2(src.getWidth(), src.getHeight());
2811
2812         // Coordinates and lod per triangle.
2813         const tcu::Vec3         triS[2]                 = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
2814         const tcu::Vec3         triT[2]                 = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
2815         const tcu::Vec3         triW[2]                 = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
2816
2817         const tcu::Vec2         lodBias                 ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
2818
2819         int                                     numFailed               = 0;
2820
2821         const tcu::Vec2 lodOffsets[] =
2822         {
2823                 tcu::Vec2(-1,  0),
2824                 tcu::Vec2(+1,  0),
2825                 tcu::Vec2( 0, -1),
2826                 tcu::Vec2( 0, +1),
2827         };
2828
2829         tcu::clear(errorMask, tcu::RGBA::green.toVec());
2830
2831         for (int py = 0; py < result.getHeight(); py++)
2832         {
2833                 for (int px = 0; px < result.getWidth(); px++)
2834                 {
2835                         const tcu::Vec4 resPix  = result.getPixel(px, py);
2836                         const tcu::Vec4 refPix  = reference.getPixel(px, py);
2837
2838                         // Other channels should trivially match to reference.
2839                         if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(refPix.swizzle(1,2,3) - resPix.swizzle(1,2,3)), nonShadowThreshold)))
2840                         {
2841                                 errorMask.setPixel(tcu::RGBA::red.toVec(), px, py);
2842                                 numFailed += 1;
2843                                 continue;
2844                         }
2845
2846                         {
2847                                 const float             wx              = (float)px + 0.5f;
2848                                 const float             wy              = (float)py + 0.5f;
2849                                 const float             nx              = wx / dstW;
2850                                 const float             ny              = wy / dstH;
2851
2852                                 const int               triNdx  = nx + ny >= 1.0f ? 1 : 0;
2853                                 const float             triWx   = triNdx ? dstW - wx : wx;
2854                                 const float             triWy   = triNdx ? dstH - wy : wy;
2855                                 const float             triNx   = triNdx ? 1.0f - nx : nx;
2856                                 const float             triNy   = triNdx ? 1.0f - ny : ny;
2857
2858                                 const tcu::Vec2 coord           (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
2859                                                                                          projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy));
2860                                 const tcu::Vec2 coordDx         = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
2861                                                                                                                 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy)) * srcSize.asFloat();
2862                                 const tcu::Vec2 coordDy         = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
2863                                                                                                                 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx)) * srcSize.asFloat();
2864
2865                                 tcu::Vec2               lodBounds       = tcu::computeLodBoundsFromDerivates(coordDx.x(), coordDx.y(), coordDy.x(), coordDy.y(), lodPrec);
2866
2867                                 // Compute lod bounds across lodOffsets range.
2868                                 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
2869                                 {
2870                                         const float             wxo             = triWx + lodOffsets[lodOffsNdx].x();
2871                                         const float             wyo             = triWy + lodOffsets[lodOffsNdx].y();
2872                                         const float             nxo             = wxo/dstW;
2873                                         const float             nyo             = wyo/dstH;
2874
2875                                         const tcu::Vec2 coordO          (projectedTriInterpolate(triS[triNdx], triW[triNdx], nxo, nyo),
2876                                                                                                  projectedTriInterpolate(triT[triNdx], triW[triNdx], nxo, nyo));
2877                                         const tcu::Vec2 coordDxo        = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
2878                                                                                                                         triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo)) * srcSize.asFloat();
2879                                         const tcu::Vec2 coordDyo        = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
2880                                                                                                                         triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo)) * srcSize.asFloat();
2881                                         const tcu::Vec2 lodO            = tcu::computeLodBoundsFromDerivates(coordDxo.x(), coordDxo.y(), coordDyo.x(), coordDyo.y(), lodPrec);
2882
2883                                         lodBounds.x() = de::min(lodBounds.x(), lodO.x());
2884                                         lodBounds.y() = de::max(lodBounds.y(), lodO.y());
2885                                 }
2886
2887                                 const tcu::Vec2 clampedLod      = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
2888                                 const bool              isOk            = tcu::isTexCompareResultValid(src, sampleParams.sampler, comparePrec, coord, clampedLod, sampleParams.ref, resPix.x());
2889
2890                                 if (!isOk)
2891                                 {
2892                                         errorMask.setPixel(tcu::RGBA::red.toVec(), px, py);
2893                                         numFailed += 1;
2894                                 }
2895                         }
2896                 }
2897         }
2898
2899         return numFailed;
2900 }
2901
2902 int computeTextureCompareDiff (const tcu::ConstPixelBufferAccess&       result,
2903                                                            const tcu::ConstPixelBufferAccess&   reference,
2904                                                            const tcu::PixelBufferAccess&                errorMask,
2905                                                            const tcu::TextureCubeView&                  src,
2906                                                            const float*                                                 texCoord,
2907                                                            const ReferenceParams&                               sampleParams,
2908                                                            const tcu::TexComparePrecision&              comparePrec,
2909                                                            const tcu::LodPrecision&                             lodPrec,
2910                                                            const tcu::Vec3&                                             nonShadowThreshold)
2911 {
2912         DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
2913         DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
2914
2915         const tcu::Vec4         sq                              = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
2916         const tcu::Vec4         tq                              = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
2917         const tcu::Vec4         rq                              = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
2918
2919         const tcu::IVec2        dstSize                 = tcu::IVec2(result.getWidth(), result.getHeight());
2920         const float                     dstW                    = float(dstSize.x());
2921         const float                     dstH                    = float(dstSize.y());
2922         const int                       srcSize                 = src.getSize();
2923
2924         // Coordinates per triangle.
2925         const tcu::Vec3         triS[2]                 = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
2926         const tcu::Vec3         triT[2]                 = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
2927         const tcu::Vec3         triR[2]                 = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
2928         const tcu::Vec3         triW[2]                 = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
2929
2930         const tcu::Vec2         lodBias                 ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
2931
2932         int                                     numFailed               = 0;
2933
2934         const tcu::Vec2 lodOffsets[] =
2935         {
2936                 tcu::Vec2(-1,  0),
2937                 tcu::Vec2(+1,  0),
2938                 tcu::Vec2( 0, -1),
2939                 tcu::Vec2( 0, +1),
2940         };
2941
2942         tcu::clear(errorMask, tcu::RGBA::green.toVec());
2943
2944         for (int py = 0; py < result.getHeight(); py++)
2945         {
2946                 for (int px = 0; px < result.getWidth(); px++)
2947                 {
2948                         const tcu::Vec4 resPix  = result.getPixel(px, py);
2949                         const tcu::Vec4 refPix  = reference.getPixel(px, py);
2950
2951                         if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(refPix.swizzle(1,2,3) - resPix.swizzle(1,2,3)), nonShadowThreshold)))
2952                         {
2953                                 errorMask.setPixel(tcu::RGBA::red.toVec(), px, py);
2954                                 numFailed += 1;
2955                                 continue;
2956                         }
2957
2958                         {
2959                                 const float             wx              = (float)px + 0.5f;
2960                                 const float             wy              = (float)py + 0.5f;
2961                                 const float             nx              = wx / dstW;
2962                                 const float             ny              = wy / dstH;
2963
2964                                 const int               triNdx  = nx + ny >= 1.0f ? 1 : 0;
2965                                 const float             triWx   = triNdx ? dstW - wx : wx;
2966                                 const float             triWy   = triNdx ? dstH - wy : wy;
2967                                 const float             triNx   = triNdx ? 1.0f - nx : nx;
2968                                 const float             triNy   = triNdx ? 1.0f - ny : ny;
2969
2970                                 const tcu::Vec3 coord           (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
2971                                                                                          projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
2972                                                                                          projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy));
2973                                 const tcu::Vec3 coordDx         (triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
2974                                                                                          triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy),
2975                                                                                          triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy));
2976                                 const tcu::Vec3 coordDy         (triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
2977                                                                                          triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx),
2978                                                                                          triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx));
2979
2980                                 tcu::Vec2               lodBounds       = tcu::computeCubeLodBoundsFromDerivates(coord, coordDx, coordDy, srcSize, lodPrec);
2981
2982                                 // Compute lod bounds across lodOffsets range.
2983                                 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
2984                                 {
2985                                         const float             wxo             = triWx + lodOffsets[lodOffsNdx].x();
2986                                         const float             wyo             = triWy + lodOffsets[lodOffsNdx].y();
2987                                         const float             nxo             = wxo/dstW;
2988                                         const float             nyo             = wyo/dstH;
2989
2990                                         const tcu::Vec3 coordO          (projectedTriInterpolate(triS[triNdx], triW[triNdx], nxo, nyo),
2991                                                                                                  projectedTriInterpolate(triT[triNdx], triW[triNdx], nxo, nyo),
2992                                                                                                  projectedTriInterpolate(triR[triNdx], triW[triNdx], nxo, nyo));
2993                                         const tcu::Vec3 coordDxo        (triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
2994                                                                                                  triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo),
2995                                                                                                  triDerivateX(triR[triNdx], triW[triNdx], wxo, dstW, nyo));
2996                                         const tcu::Vec3 coordDyo        (triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
2997                                                                                                  triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo),
2998                                                                                                  triDerivateY(triR[triNdx], triW[triNdx], wyo, dstH, nxo));
2999                                         const tcu::Vec2 lodO            = tcu::computeCubeLodBoundsFromDerivates(coordO, coordDxo, coordDyo, srcSize, lodPrec);
3000
3001                                         lodBounds.x() = de::min(lodBounds.x(), lodO.x());
3002                                         lodBounds.y() = de::max(lodBounds.y(), lodO.y());
3003                                 }
3004
3005                                 const tcu::Vec2 clampedLod      = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
3006                                 const bool              isOk            = tcu::isTexCompareResultValid(src, sampleParams.sampler, comparePrec, coord, clampedLod, sampleParams.ref, resPix.x());
3007
3008                                 if (!isOk)
3009                                 {
3010                                         errorMask.setPixel(tcu::RGBA::red.toVec(), px, py);
3011                                         numFailed += 1;
3012                                 }
3013                         }
3014                 }
3015         }
3016
3017         return numFailed;
3018 }
3019
3020 int computeTextureCompareDiff (const tcu::ConstPixelBufferAccess&       result,
3021                                                            const tcu::ConstPixelBufferAccess&   reference,
3022                                                            const tcu::PixelBufferAccess&                errorMask,
3023                                                            const tcu::Texture2DArrayView&               src,
3024                                                            const float*                                                 texCoord,
3025                                                            const ReferenceParams&                               sampleParams,
3026                                                            const tcu::TexComparePrecision&              comparePrec,
3027                                                            const tcu::LodPrecision&                             lodPrec,
3028                                                            const tcu::Vec3&                                             nonShadowThreshold)
3029 {
3030         DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
3031         DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
3032
3033         const tcu::Vec4         sq                              = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
3034         const tcu::Vec4         tq                              = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
3035         const tcu::Vec4         rq                              = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
3036
3037         const tcu::IVec2        dstSize                 = tcu::IVec2(result.getWidth(), result.getHeight());
3038         const float                     dstW                    = float(dstSize.x());
3039         const float                     dstH                    = float(dstSize.y());
3040         const tcu::IVec2        srcSize                 = tcu::IVec2(src.getWidth(), src.getHeight());
3041
3042         // Coordinates and lod per triangle.
3043         const tcu::Vec3         triS[2]                 = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
3044         const tcu::Vec3         triT[2]                 = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
3045         const tcu::Vec3         triR[2]                 = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
3046         const tcu::Vec3         triW[2]                 = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
3047
3048         const tcu::Vec2         lodBias                 ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
3049
3050         int                                     numFailed               = 0;
3051
3052         const tcu::Vec2 lodOffsets[] =
3053         {
3054                 tcu::Vec2(-1,  0),
3055                 tcu::Vec2(+1,  0),
3056                 tcu::Vec2( 0, -1),
3057                 tcu::Vec2( 0, +1),
3058         };
3059
3060         tcu::clear(errorMask, tcu::RGBA::green.toVec());
3061
3062         for (int py = 0; py < result.getHeight(); py++)
3063         {
3064                 for (int px = 0; px < result.getWidth(); px++)
3065                 {
3066                         const tcu::Vec4 resPix  = result.getPixel(px, py);
3067                         const tcu::Vec4 refPix  = reference.getPixel(px, py);
3068
3069                         if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(refPix.swizzle(1,2,3) - resPix.swizzle(1,2,3)), nonShadowThreshold)))
3070                         {
3071                                 errorMask.setPixel(tcu::RGBA::red.toVec(), px, py);
3072                                 numFailed += 1;
3073                                 continue;
3074                         }
3075
3076                         {
3077                                 const float             wx              = (float)px + 0.5f;
3078                                 const float             wy              = (float)py + 0.5f;
3079                                 const float             nx              = wx / dstW;
3080                                 const float             ny              = wy / dstH;
3081
3082                                 const int               triNdx  = nx + ny >= 1.0f ? 1 : 0;
3083                                 const float             triWx   = triNdx ? dstW - wx : wx;
3084                                 const float             triWy   = triNdx ? dstH - wy : wy;
3085                                 const float             triNx   = triNdx ? 1.0f - nx : nx;
3086                                 const float             triNy   = triNdx ? 1.0f - ny : ny;
3087
3088                                 const tcu::Vec3 coord           (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
3089                                                                                          projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
3090                                                                                          projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy));
3091                                 const tcu::Vec2 coordDx         = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
3092                                                                                                                 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy)) * srcSize.asFloat();
3093                                 const tcu::Vec2 coordDy         = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
3094                                                                                                                 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx)) * srcSize.asFloat();
3095
3096                                 tcu::Vec2               lodBounds       = tcu::computeLodBoundsFromDerivates(coordDx.x(), coordDx.y(), coordDy.x(), coordDy.y(), lodPrec);
3097
3098                                 // Compute lod bounds across lodOffsets range.
3099                                 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
3100                                 {
3101                                         const float             wxo             = triWx + lodOffsets[lodOffsNdx].x();
3102                                         const float             wyo             = triWy + lodOffsets[lodOffsNdx].y();
3103                                         const float             nxo             = wxo/dstW;
3104                                         const float             nyo             = wyo/dstH;
3105
3106                                         const tcu::Vec2 coordO          (projectedTriInterpolate(triS[triNdx], triW[triNdx], nxo, nyo),
3107                                                                                                  projectedTriInterpolate(triT[triNdx], triW[triNdx], nxo, nyo));
3108                                         const tcu::Vec2 coordDxo        = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
3109                                                                                                                         triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo)) * srcSize.asFloat();
3110                                         const tcu::Vec2 coordDyo        = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
3111                                                                                                                         triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo)) * srcSize.asFloat();
3112                                         const tcu::Vec2 lodO            = tcu::computeLodBoundsFromDerivates(coordDxo.x(), coordDxo.y(), coordDyo.x(), coordDyo.y(), lodPrec);
3113
3114                                         lodBounds.x() = de::min(lodBounds.x(), lodO.x());
3115                                         lodBounds.y() = de::max(lodBounds.y(), lodO.y());
3116                                 }
3117
3118                                 const tcu::Vec2 clampedLod      = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
3119                                 const bool              isOk            = tcu::isTexCompareResultValid(src, sampleParams.sampler, comparePrec, coord, clampedLod, sampleParams.ref, resPix.x());
3120
3121                                 if (!isOk)
3122                                 {
3123                                         errorMask.setPixel(tcu::RGBA::red.toVec(), px, py);
3124                                         numFailed += 1;
3125                                 }
3126                         }
3127                 }
3128         }
3129
3130         return numFailed;
3131 }
3132
3133 // Mipmap generation comparison.
3134
3135 static int compareGenMipmapBilinear (const tcu::ConstPixelBufferAccess& dst, const tcu::ConstPixelBufferAccess& src, const tcu::PixelBufferAccess& errorMask, const GenMipmapPrecision& precision)
3136 {
3137         DE_ASSERT(dst.getDepth() == 1 && src.getDepth() == 1); // \todo [2013-10-29 pyry] 3D textures.
3138
3139         const float             dstW            = float(dst.getWidth());
3140         const float             dstH            = float(dst.getHeight());
3141         const float             srcW            = float(src.getWidth());
3142         const float             srcH            = float(src.getHeight());
3143         int                             numFailed       = 0;
3144
3145         // Translation to lookup verification parameters.
3146         const tcu::Sampler              sampler         (tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE,
3147                                                                                  tcu::Sampler::LINEAR, tcu::Sampler::LINEAR, 0.0f, false /* non-normalized coords */);
3148         tcu::LookupPrecision    lookupPrec;
3149
3150         lookupPrec.colorThreshold       = precision.colorThreshold;
3151         lookupPrec.colorMask            = precision.colorMask;
3152         lookupPrec.coordBits            = tcu::IVec3(22);
3153         lookupPrec.uvwBits                      = precision.filterBits;
3154
3155         for (int y = 0; y < dst.getHeight(); y++)
3156         for (int x = 0; x < dst.getWidth(); x++)
3157         {
3158                 const tcu::Vec4 result  = dst.getPixel(x, y);
3159                 const float             cx              = (float(x)+0.5f) / dstW * srcW;
3160                 const float             cy              = (float(y)+0.5f) / dstH * srcH;
3161                 const bool              isOk    = tcu::isLinearSampleResultValid(src, sampler, lookupPrec, tcu::Vec2(cx, cy), 0, result);
3162
3163                 errorMask.setPixel(isOk ? tcu::RGBA::green.toVec() : tcu::RGBA::red.toVec(), x, y);
3164                 if (!isOk)
3165                         numFailed += 1;
3166         }
3167
3168         return numFailed;
3169 }
3170
3171 static int compareGenMipmapBox (const tcu::ConstPixelBufferAccess& dst, const tcu::ConstPixelBufferAccess& src, const tcu::PixelBufferAccess& errorMask, const GenMipmapPrecision& precision)
3172 {
3173         DE_ASSERT(dst.getDepth() == 1 && src.getDepth() == 1); // \todo [2013-10-29 pyry] 3D textures.
3174
3175         const float             dstW            = float(dst.getWidth());
3176         const float             dstH            = float(dst.getHeight());
3177         const float             srcW            = float(src.getWidth());
3178         const float             srcH            = float(src.getHeight());
3179         int                             numFailed       = 0;
3180
3181         // Translation to lookup verification parameters.
3182         const tcu::Sampler              sampler         (tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE,
3183                                                                                  tcu::Sampler::LINEAR, tcu::Sampler::LINEAR, 0.0f, false /* non-normalized coords */);
3184         tcu::LookupPrecision    lookupPrec;
3185
3186         lookupPrec.colorThreshold       = precision.colorThreshold;
3187         lookupPrec.colorMask            = precision.colorMask;
3188         lookupPrec.coordBits            = tcu::IVec3(22);
3189         lookupPrec.uvwBits                      = precision.filterBits;
3190
3191         for (int y = 0; y < dst.getHeight(); y++)
3192         for (int x = 0; x < dst.getWidth(); x++)
3193         {
3194                 const tcu::Vec4 result  = dst.getPixel(x, y);
3195                 const float             cx              = deFloatFloor(float(x) / dstW * srcW) + 1.0f;
3196                 const float             cy              = deFloatFloor(float(y) / dstH * srcH) + 1.0f;
3197                 const bool              isOk    = tcu::isLinearSampleResultValid(src, sampler, lookupPrec, tcu::Vec2(cx, cy), 0, result);
3198
3199                 errorMask.setPixel(isOk ? tcu::RGBA::green.toVec() : tcu::RGBA::red.toVec(), x, y);
3200                 if (!isOk)
3201                         numFailed += 1;
3202         }
3203
3204         return numFailed;
3205 }
3206
3207 static int compareGenMipmapVeryLenient (const tcu::ConstPixelBufferAccess& dst, const tcu::ConstPixelBufferAccess& src, const tcu::PixelBufferAccess& errorMask, const GenMipmapPrecision& precision)
3208 {
3209         DE_ASSERT(dst.getDepth() == 1 && src.getDepth() == 1); // \todo [2013-10-29 pyry] 3D textures.
3210         DE_UNREF(precision);
3211
3212         const float             dstW            = float(dst.getWidth());
3213         const float             dstH            = float(dst.getHeight());
3214         const float             srcW            = float(src.getWidth());
3215         const float             srcH            = float(src.getHeight());
3216         int                             numFailed       = 0;
3217
3218         for (int y = 0; y < dst.getHeight(); y++)
3219         for (int x = 0; x < dst.getWidth(); x++)
3220         {
3221                 const tcu::Vec4 result  = dst.getPixel(x, y);
3222                 const int               minX            = deFloorFloatToInt32(float(x-0.5f) / dstW * srcW);
3223                 const int               minY            = deFloorFloatToInt32(float(y-0.5f) / dstH * srcH);
3224                 const int               maxX            = deCeilFloatToInt32(float(x+1.5f) / dstW * srcW);
3225                 const int               maxY            = deCeilFloatToInt32(float(y+1.5f) / dstH * srcH);
3226                 tcu::Vec4               minVal, maxVal;
3227                 bool                    isOk;
3228
3229                 DE_ASSERT(minX < maxX && minY < maxY);
3230
3231                 for (int ky = minY; ky <= maxY; ky++)
3232                 {
3233                         for (int kx = minX; kx <= maxX; kx++)
3234                         {
3235                                 const int               sx              = de::clamp(kx, 0, src.getWidth()-1);
3236                                 const int               sy              = de::clamp(ky, 0, src.getHeight()-1);
3237                                 const tcu::Vec4 sample  = src.getPixel(sx, sy);
3238
3239                                 if (ky == minY && kx == minX)
3240                                 {
3241                                         minVal = sample;
3242                                         maxVal = sample;
3243                                 }
3244                                 else
3245                                 {
3246                                         minVal = min(sample, minVal);
3247                                         maxVal = max(sample, maxVal);
3248                                 }
3249                         }
3250                 }
3251
3252                 isOk = boolAll(logicalAnd(lessThanEqual(minVal, result), lessThanEqual(result, maxVal)));
3253
3254                 errorMask.setPixel(isOk ? tcu::RGBA::green.toVec() : tcu::RGBA::red.toVec(), x, y);
3255                 if (!isOk)
3256                         numFailed += 1;
3257         }
3258
3259         return numFailed;
3260 }
3261
3262 qpTestResult compareGenMipmapResult (tcu::TestLog& log, const tcu::Texture2D& resultTexture, const tcu::Texture2D& level0Reference, const GenMipmapPrecision& precision)
3263 {
3264         qpTestResult result = QP_TEST_RESULT_PASS;
3265
3266         // Special comparison for level 0.
3267         {
3268                 const tcu::Vec4         threshold       = select(precision.colorThreshold, tcu::Vec4(1.0f), precision.colorMask);
3269                 const bool                      level0Ok        = tcu::floatThresholdCompare(log, "Level0", "Level 0", level0Reference.getLevel(0), resultTexture.getLevel(0), threshold, tcu::COMPARE_LOG_RESULT);
3270
3271                 if (!level0Ok)
3272                 {
3273                         log << TestLog::Message << "ERROR: Level 0 comparison failed!" << TestLog::EndMessage;
3274                         result = QP_TEST_RESULT_FAIL;
3275                 }
3276         }
3277
3278         for (int levelNdx = 1; levelNdx < resultTexture.getNumLevels(); levelNdx++)
3279         {
3280                 const tcu::ConstPixelBufferAccess       src                     = resultTexture.getLevel(levelNdx-1);
3281                 const tcu::ConstPixelBufferAccess       dst                     = resultTexture.getLevel(levelNdx);
3282                 tcu::Surface                                            errorMask       (dst.getWidth(), dst.getHeight());
3283                 bool                                                            levelOk         = false;
3284
3285                 // Try different comparisons in quality order.
3286
3287                 if (!levelOk)
3288                 {
3289                         const int numFailed = compareGenMipmapBilinear(dst, src, errorMask.getAccess(), precision);
3290                         if (numFailed == 0)
3291                                 levelOk = true;
3292                         else
3293                                 log << TestLog::Message << "WARNING: Level " << levelNdx << " comparison to bilinear method failed, found " << numFailed << " invalid pixels." << TestLog::EndMessage;
3294                 }
3295
3296                 if (!levelOk)
3297                 {
3298                         const int numFailed = compareGenMipmapBox(dst, src, errorMask.getAccess(), precision);
3299                         if (numFailed == 0)
3300                                 levelOk = true;
3301                         else
3302                                 log << TestLog::Message << "WARNING: Level " << levelNdx << " comparison to box method failed, found " << numFailed << " invalid pixels." << TestLog::EndMessage;
3303                 }
3304
3305                 // At this point all high-quality methods have been used.
3306                 if (!levelOk && result == QP_TEST_RESULT_PASS)
3307                         result = QP_TEST_RESULT_QUALITY_WARNING;
3308
3309                 if (!levelOk)
3310                 {
3311                         const int numFailed = compareGenMipmapVeryLenient(dst, src, errorMask.getAccess(), precision);
3312                         if (numFailed == 0)
3313                                 levelOk = true;
3314                         else
3315                                 log << TestLog::Message << "ERROR: Level " << levelNdx << " appears to contain " << numFailed << " completely wrong pixels, failing case!" << TestLog::EndMessage;
3316                 }
3317
3318                 if (!levelOk)
3319                         result = QP_TEST_RESULT_FAIL;
3320
3321                 log << TestLog::ImageSet(string("Level") + de::toString(levelNdx), string("Level ") + de::toString(levelNdx) + " result")
3322                         << TestLog::Image("Result", "Result", dst);
3323
3324                 if (!levelOk)
3325                         log << TestLog::Image("ErrorMask", "Error mask", errorMask);
3326
3327                 log << TestLog::EndImageSet;
3328         }
3329
3330         return result;
3331 }
3332
3333 qpTestResult compareGenMipmapResult (tcu::TestLog& log, const tcu::TextureCube& resultTexture, const tcu::TextureCube& level0Reference, const GenMipmapPrecision& precision)
3334 {
3335         qpTestResult result = QP_TEST_RESULT_PASS;
3336
3337         static const char* s_faceNames[] = { "-X", "+X", "-Y", "+Y", "-Z", "+Z" };
3338         DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_faceNames) == tcu::CUBEFACE_LAST);
3339
3340         // Special comparison for level 0.
3341         for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; faceNdx++)
3342         {
3343                 const tcu::CubeFace     face            = tcu::CubeFace(faceNdx);
3344                 const tcu::Vec4         threshold       = select(precision.colorThreshold, tcu::Vec4(1.0f), precision.colorMask);
3345                 const bool                      level0Ok        = tcu::floatThresholdCompare(log,
3346                                                                                                                                          ("Level0Face" + de::toString(faceNdx)).c_str(),
3347                                                                                                                                          (string("Level 0, face ") + s_faceNames[face]).c_str(),
3348                                                                                                                                          level0Reference.getLevelFace(0, face),
3349                                                                                                                                          resultTexture.getLevelFace(0, face),
3350                                                                                                                                          threshold, tcu::COMPARE_LOG_RESULT);
3351
3352                 if (!level0Ok)
3353                 {
3354                         log << TestLog::Message << "ERROR: Level 0, face " << s_faceNames[face] << " comparison failed!" << TestLog::EndMessage;
3355                         result = QP_TEST_RESULT_FAIL;
3356                 }
3357         }
3358
3359         for (int levelNdx = 1; levelNdx < resultTexture.getNumLevels(); levelNdx++)
3360         {
3361                 for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; faceNdx++)
3362                 {
3363                         const tcu::CubeFace                                     face            = tcu::CubeFace(faceNdx);
3364                         const char*                                                     faceName        = s_faceNames[face];
3365                         const tcu::ConstPixelBufferAccess       src                     = resultTexture.getLevelFace(levelNdx-1,        face);
3366                         const tcu::ConstPixelBufferAccess       dst                     = resultTexture.getLevelFace(levelNdx,          face);
3367                         tcu::Surface                                            errorMask       (dst.getWidth(), dst.getHeight());
3368                         bool                                                            levelOk         = false;
3369
3370                         // Try different comparisons in quality order.
3371
3372                         if (!levelOk)
3373                         {
3374                                 const int numFailed = compareGenMipmapBilinear(dst, src, errorMask.getAccess(), precision);
3375                                 if (numFailed == 0)
3376                                         levelOk = true;
3377                                 else
3378                                         log << TestLog::Message << "WARNING: Level " << levelNdx << ", face " << faceName << " comparison to bilinear method failed, found " << numFailed << " invalid pixels." << TestLog::EndMessage;
3379                         }
3380
3381                         if (!levelOk)
3382                         {
3383                                 const int numFailed = compareGenMipmapBox(dst, src, errorMask.getAccess(), precision);
3384                                 if (numFailed == 0)
3385                                         levelOk = true;
3386                                 else
3387                                         log << TestLog::Message << "WARNING: Level " << levelNdx << ", face " << faceName <<" comparison to box method failed, found " << numFailed << " invalid pixels." << TestLog::EndMessage;
3388                         }
3389
3390                         // At this point all high-quality methods have been used.
3391                         if (!levelOk && result == QP_TEST_RESULT_PASS)
3392                                 result = QP_TEST_RESULT_QUALITY_WARNING;
3393
3394                         if (!levelOk)
3395                         {
3396                                 const int numFailed = compareGenMipmapVeryLenient(dst, src, errorMask.getAccess(), precision);
3397                                 if (numFailed == 0)
3398                                         levelOk = true;
3399                                 else
3400                                         log << TestLog::Message << "ERROR: Level " << levelNdx << ", face " << faceName << " appears to contain " << numFailed << " completely wrong pixels, failing case!" << TestLog::EndMessage;
3401                         }
3402
3403                         if (!levelOk)
3404                                 result = QP_TEST_RESULT_FAIL;
3405
3406                         log << TestLog::ImageSet(string("Level") + de::toString(levelNdx) + "Face" + de::toString(faceNdx), string("Level ") + de::toString(levelNdx) + ", face " + string(faceName) + " result")
3407                                 << TestLog::Image("Result", "Result", dst);
3408
3409                         if (!levelOk)
3410                                 log << TestLog::Image("ErrorMask", "Error mask", errorMask);
3411
3412                         log << TestLog::EndImageSet;
3413                 }
3414         }
3415
3416         return result;
3417 }
3418
3419 // Logging utilities.
3420
3421 std::ostream& operator<< (std::ostream& str, const LogGradientFmt& fmt)
3422 {
3423         return str << "(R: " << fmt.valueMin->x() << " -> " << fmt.valueMax->x() << ", "
3424                            <<  "G: " << fmt.valueMin->y() << " -> " << fmt.valueMax->y() << ", "
3425                            <<  "B: " << fmt.valueMin->z() << " -> " << fmt.valueMax->z() << ", "
3426                            <<  "A: " << fmt.valueMin->w() << " -> " << fmt.valueMax->w() << ")";
3427 }
3428
3429 } // TextureTestUtil
3430 } // gls
3431 } // deqp