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