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