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