Merge vk-gl-cts/vulkan-cts-1.0.1 into vk-gl-cts/vulkan-cts-1.0.2
[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         int                                                                                     numFailed                       = 0;
1360
1361         const tcu::Vec2 lodOffsets[] =
1362         {
1363                 tcu::Vec2(-1,  0),
1364                 tcu::Vec2(+1,  0),
1365                 tcu::Vec2( 0, -1),
1366                 tcu::Vec2( 0, +1),
1367         };
1368
1369         tcu::clear(errorMask, tcu::RGBA::green().toVec());
1370
1371         for (int py = 0; py < result.getHeight(); py++)
1372         {
1373                 // Ugly hack, validation can take way too long at the moment.
1374                 if (watchDog)
1375                         qpWatchDog_touch(watchDog);
1376
1377                 for (int px = 0; px < result.getWidth(); px++)
1378                 {
1379                         const tcu::Vec4 resPix  = (result.getPixel(px, py)              - sampleParams.colorBias) / sampleParams.colorScale;
1380                         const tcu::Vec4 refPix  = (reference.getPixel(px, py)   - sampleParams.colorBias) / sampleParams.colorScale;
1381
1382                         // Try comparison to ideal reference first, and if that fails use slower verificator.
1383                         if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
1384                         {
1385                                 const float             wx              = (float)px + 0.5f;
1386                                 const float             wy              = (float)py + 0.5f;
1387                                 const float             nx              = wx / dstW;
1388                                 const float             ny              = wy / dstH;
1389
1390                                 const int               triNdx  = nx + ny >= 1.0f ? 1 : 0;
1391                                 const float             triWx   = triNdx ? dstW - wx : wx;
1392                                 const float             triWy   = triNdx ? dstH - wy : wy;
1393                                 const float             triNx   = triNdx ? 1.0f - nx : nx;
1394                                 const float             triNy   = triNdx ? 1.0f - ny : ny;
1395
1396                                 const tcu::Vec2 coord           (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
1397                                                                                          projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy));
1398                                 const tcu::Vec2 coordDx         = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
1399                                                                                                                 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy)) * srcSize.asFloat();
1400                                 const tcu::Vec2 coordDy         = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
1401                                                                                                                 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx)) * srcSize.asFloat();
1402
1403                                 tcu::Vec2               lodBounds       = tcu::computeLodBoundsFromDerivates(coordDx.x(), coordDx.y(), coordDy.x(), coordDy.y(), lodPrec);
1404
1405                                 // Compute lod bounds across lodOffsets range.
1406                                 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
1407                                 {
1408                                         const float             wxo             = triWx + lodOffsets[lodOffsNdx].x();
1409                                         const float             wyo             = triWy + lodOffsets[lodOffsNdx].y();
1410                                         const float             nxo             = wxo/dstW;
1411                                         const float             nyo             = wyo/dstH;
1412
1413                                         const tcu::Vec2 coordDxo        = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
1414                                                                                                                         triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo)) * srcSize.asFloat();
1415                                         const tcu::Vec2 coordDyo        = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
1416                                                                                                                         triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo)) * srcSize.asFloat();
1417                                         const tcu::Vec2 lodO            = tcu::computeLodBoundsFromDerivates(coordDxo.x(), coordDxo.y(), coordDyo.x(), coordDyo.y(), lodPrec);
1418
1419                                         lodBounds.x() = de::min(lodBounds.x(), lodO.x());
1420                                         lodBounds.y() = de::max(lodBounds.y(), lodO.y());
1421                                 }
1422
1423                                 const tcu::Vec2 clampedLod      = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
1424                                 const bool              isOk            = tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix);
1425
1426                                 if (!isOk)
1427                                 {
1428                                         errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
1429                                         numFailed += 1;
1430                                 }
1431                         }
1432                 }
1433         }
1434
1435         return numFailed;
1436 }
1437
1438 bool verifyTextureResult (tcu::TestContext&                                             testCtx,
1439                                                   const tcu::ConstPixelBufferAccess&    result,
1440                                                   const tcu::Texture1DView&                             src,
1441                                                   const float*                                                  texCoord,
1442                                                   const ReferenceParams&                                sampleParams,
1443                                                   const tcu::LookupPrecision&                   lookupPrec,
1444                                                   const tcu::LodPrecision&                              lodPrec,
1445                                                   const tcu::PixelFormat&                               pixelFormat)
1446 {
1447         tcu::TestLog&   log                             = testCtx.getLog();
1448         tcu::Surface    reference               (result.getWidth(), result.getHeight());
1449         tcu::Surface    errorMask               (result.getWidth(), result.getHeight());
1450         int                             numFailedPixels;
1451
1452         DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
1453
1454         sampleTexture(tcu::SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
1455         numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog());
1456
1457         if (numFailedPixels > 0)
1458                 log << tcu::TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << tcu::TestLog::EndMessage;
1459
1460         log << tcu::TestLog::ImageSet("VerifyResult", "Verification result")
1461                 << tcu::TestLog::Image("Rendered", "Rendered image", result);
1462
1463         if (numFailedPixels > 0)
1464         {
1465                 log << tcu::TestLog::Image("Reference", "Ideal reference image", reference)
1466                         << tcu::TestLog::Image("ErrorMask", "Error mask", errorMask);
1467         }
1468
1469         log << tcu::TestLog::EndImageSet;
1470
1471         return numFailedPixels == 0;
1472 }
1473
1474 bool verifyTextureResult (tcu::TestContext&                                             testCtx,
1475                                                   const tcu::ConstPixelBufferAccess&    result,
1476                                                   const tcu::Texture2DView&                             src,
1477                                                   const float*                                                  texCoord,
1478                                                   const ReferenceParams&                                sampleParams,
1479                                                   const tcu::LookupPrecision&                   lookupPrec,
1480                                                   const tcu::LodPrecision&                              lodPrec,
1481                                                   const tcu::PixelFormat&                               pixelFormat)
1482 {
1483         tcu::TestLog&   log                             = testCtx.getLog();
1484         tcu::Surface    reference               (result.getWidth(), result.getHeight());
1485         tcu::Surface    errorMask               (result.getWidth(), result.getHeight());
1486         int                             numFailedPixels;
1487
1488         DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
1489
1490         sampleTexture(tcu::SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
1491         numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog());
1492
1493         if (numFailedPixels > 0)
1494                 log << tcu::TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << tcu::TestLog::EndMessage;
1495
1496         log << tcu::TestLog::ImageSet("VerifyResult", "Verification result")
1497                 << tcu::TestLog::Image("Rendered", "Rendered image", result);
1498
1499         if (numFailedPixels > 0)
1500         {
1501                 log << tcu::TestLog::Image("Reference", "Ideal reference image", reference)
1502                         << tcu::TestLog::Image("ErrorMask", "Error mask", errorMask);
1503         }
1504
1505         log << tcu::TestLog::EndImageSet;
1506
1507         return numFailedPixels == 0;
1508 }
1509
1510 //! Verifies texture lookup results and returns number of failed pixels.
1511 int computeTextureLookupDiff (const tcu::ConstPixelBufferAccess&        result,
1512                                                           const tcu::ConstPixelBufferAccess&    reference,
1513                                                           const tcu::PixelBufferAccess&                 errorMask,
1514                                                           const tcu::TextureCubeView&                   baseView,
1515                                                           const float*                                                  texCoord,
1516                                                           const ReferenceParams&                                sampleParams,
1517                                                           const tcu::LookupPrecision&                   lookupPrec,
1518                                                           const tcu::LodPrecision&                              lodPrec,
1519                                                           qpWatchDog*                                                   watchDog)
1520 {
1521         DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
1522         DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
1523
1524         std::vector<tcu::ConstPixelBufferAccess>        srcLevelStorage;
1525         const tcu::TextureCubeView                                      src                                     = getEffectiveTextureView(getSubView(baseView, sampleParams.baseLevel, sampleParams.maxLevel), srcLevelStorage, sampleParams.sampler);
1526
1527         const tcu::Vec4                                                         sq                                      = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
1528         const tcu::Vec4                                                         tq                                      = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
1529         const tcu::Vec4                                                         rq                                      = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
1530
1531         const tcu::IVec2                                                        dstSize                         = tcu::IVec2(result.getWidth(), result.getHeight());
1532         const float                                                                     dstW                            = float(dstSize.x());
1533         const float                                                                     dstH                            = float(dstSize.y());
1534         const int                                                                       srcSize                         = src.getSize();
1535
1536         // Coordinates per triangle.
1537         const tcu::Vec3                                                         triS[2]                         = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
1538         const tcu::Vec3                                                         triT[2]                         = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
1539         const tcu::Vec3                                                         triR[2]                         = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
1540         const tcu::Vec3                                                         triW[2]                         = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
1541
1542         const tcu::Vec2                                                         lodBias                         ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
1543
1544         const float                                                                     posEps                          = 1.0f / float(1<<MIN_SUBPIXEL_BITS);
1545
1546         int                                                                                     numFailed                       = 0;
1547
1548         const tcu::Vec2 lodOffsets[] =
1549         {
1550                 tcu::Vec2(-1,  0),
1551                 tcu::Vec2(+1,  0),
1552                 tcu::Vec2( 0, -1),
1553                 tcu::Vec2( 0, +1),
1554
1555                 // \note Not strictly allowed by spec, but implementations do this in practice.
1556                 tcu::Vec2(-1, -1),
1557                 tcu::Vec2(-1, +1),
1558                 tcu::Vec2(+1, -1),
1559                 tcu::Vec2(+1, +1),
1560         };
1561
1562         tcu::clear(errorMask, tcu::RGBA::green().toVec());
1563
1564         for (int py = 0; py < result.getHeight(); py++)
1565         {
1566                 // Ugly hack, validation can take way too long at the moment.
1567                 if (watchDog)
1568                         qpWatchDog_touch(watchDog);
1569
1570                 for (int px = 0; px < result.getWidth(); px++)
1571                 {
1572                         const tcu::Vec4 resPix  = (result.getPixel(px, py)              - sampleParams.colorBias) / sampleParams.colorScale;
1573                         const tcu::Vec4 refPix  = (reference.getPixel(px, py)   - sampleParams.colorBias) / sampleParams.colorScale;
1574
1575                         // Try comparison to ideal reference first, and if that fails use slower verificator.
1576                         if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
1577                         {
1578                                 const float             wx              = (float)px + 0.5f;
1579                                 const float             wy              = (float)py + 0.5f;
1580                                 const float             nx              = wx / dstW;
1581                                 const float             ny              = wy / dstH;
1582
1583                                 const bool              tri0    = (wx-posEps)/dstW + (wy-posEps)/dstH <= 1.0f;
1584                                 const bool              tri1    = (wx+posEps)/dstW + (wy+posEps)/dstH >= 1.0f;
1585
1586                                 bool                    isOk    = false;
1587
1588                                 DE_ASSERT(tri0 || tri1);
1589
1590                                 // Pixel can belong to either of the triangles if it lies close enough to the edge.
1591                                 for (int triNdx = (tri0?0:1); triNdx <= (tri1?1:0); triNdx++)
1592                                 {
1593                                         const float             triWx   = triNdx ? dstW - wx : wx;
1594                                         const float             triWy   = triNdx ? dstH - wy : wy;
1595                                         const float             triNx   = triNdx ? 1.0f - nx : nx;
1596                                         const float             triNy   = triNdx ? 1.0f - ny : ny;
1597
1598                                         const tcu::Vec3 coord           (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
1599                                                                                                  projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
1600                                                                                                  projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy));
1601                                         const tcu::Vec3 coordDx         (triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
1602                                                                                                  triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy),
1603                                                                                                  triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy));
1604                                         const tcu::Vec3 coordDy         (triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
1605                                                                                                  triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx),
1606                                                                                                  triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx));
1607
1608                                         tcu::Vec2               lodBounds       = tcu::computeCubeLodBoundsFromDerivates(coord, coordDx, coordDy, srcSize, lodPrec);
1609
1610                                         // Compute lod bounds across lodOffsets range.
1611                                         for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
1612                                         {
1613                                                 const float             wxo             = triWx + lodOffsets[lodOffsNdx].x();
1614                                                 const float             wyo             = triWy + lodOffsets[lodOffsNdx].y();
1615                                                 const float             nxo             = wxo/dstW;
1616                                                 const float             nyo             = wyo/dstH;
1617
1618                                                 const tcu::Vec3 coordO          (projectedTriInterpolate(triS[triNdx], triW[triNdx], nxo, nyo),
1619                                                                                                          projectedTriInterpolate(triT[triNdx], triW[triNdx], nxo, nyo),
1620                                                                                                          projectedTriInterpolate(triR[triNdx], triW[triNdx], nxo, nyo));
1621                                                 const tcu::Vec3 coordDxo        (triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
1622                                                                                                          triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo),
1623                                                                                                          triDerivateX(triR[triNdx], triW[triNdx], wxo, dstW, nyo));
1624                                                 const tcu::Vec3 coordDyo        (triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
1625                                                                                                          triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo),
1626                                                                                                          triDerivateY(triR[triNdx], triW[triNdx], wyo, dstH, nxo));
1627                                                 const tcu::Vec2 lodO            = tcu::computeCubeLodBoundsFromDerivates(coordO, coordDxo, coordDyo, srcSize, lodPrec);
1628
1629                                                 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
1630                                                 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
1631                                         }
1632
1633                                         const tcu::Vec2 clampedLod      = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
1634
1635                                         if (tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix))
1636                                         {
1637                                                 isOk = true;
1638                                                 break;
1639                                         }
1640                                 }
1641
1642                                 if (!isOk)
1643                                 {
1644                                         errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
1645                                         numFailed += 1;
1646                                 }
1647                         }
1648                 }
1649         }
1650
1651         return numFailed;
1652 }
1653
1654 bool verifyTextureResult (tcu::TestContext&                                             testCtx,
1655                                                   const tcu::ConstPixelBufferAccess&    result,
1656                                                   const tcu::TextureCubeView&                   src,
1657                                                   const float*                                                  texCoord,
1658                                                   const ReferenceParams&                                sampleParams,
1659                                                   const tcu::LookupPrecision&                   lookupPrec,
1660                                                   const tcu::LodPrecision&                              lodPrec,
1661                                                   const tcu::PixelFormat&                               pixelFormat)
1662 {
1663         tcu::TestLog&   log                             = testCtx.getLog();
1664         tcu::Surface    reference               (result.getWidth(), result.getHeight());
1665         tcu::Surface    errorMask               (result.getWidth(), result.getHeight());
1666         int                             numFailedPixels;
1667
1668         DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
1669
1670         sampleTexture(tcu::SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
1671         numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog());
1672
1673         if (numFailedPixels > 0)
1674                 log << tcu::TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << tcu::TestLog::EndMessage;
1675
1676         log << tcu::TestLog::ImageSet("VerifyResult", "Verification result")
1677                 << tcu::TestLog::Image("Rendered", "Rendered image", result);
1678
1679         if (numFailedPixels > 0)
1680         {
1681                 log << tcu::TestLog::Image("Reference", "Ideal reference image", reference)
1682                         << tcu::TestLog::Image("ErrorMask", "Error mask", errorMask);
1683         }
1684
1685         log << tcu::TestLog::EndImageSet;
1686
1687         return numFailedPixels == 0;
1688 }
1689
1690 //! Verifies texture lookup results and returns number of failed pixels.
1691 int computeTextureLookupDiff (const tcu::ConstPixelBufferAccess&        result,
1692                                                           const tcu::ConstPixelBufferAccess&    reference,
1693                                                           const tcu::PixelBufferAccess&                 errorMask,
1694                                                           const tcu::Texture3DView&                             baseView,
1695                                                           const float*                                                  texCoord,
1696                                                           const ReferenceParams&                                sampleParams,
1697                                                           const tcu::LookupPrecision&                   lookupPrec,
1698                                                           const tcu::LodPrecision&                              lodPrec,
1699                                                           qpWatchDog*                                                   watchDog)
1700 {
1701         DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
1702         DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
1703
1704         std::vector<tcu::ConstPixelBufferAccess>        srcLevelStorage;
1705         const tcu::Texture3DView                                        src                                     = getEffectiveTextureView(getSubView(baseView, sampleParams.baseLevel, sampleParams.maxLevel), srcLevelStorage, sampleParams.sampler);
1706
1707         const tcu::Vec4                                                         sq                                      = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
1708         const tcu::Vec4                                                         tq                                      = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
1709         const tcu::Vec4                                                         rq                                      = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
1710
1711         const tcu::IVec2                                                        dstSize                         = tcu::IVec2(result.getWidth(), result.getHeight());
1712         const float                                                                     dstW                            = float(dstSize.x());
1713         const float                                                                     dstH                            = float(dstSize.y());
1714         const tcu::IVec3                                                        srcSize                         = tcu::IVec3(src.getWidth(), src.getHeight(), src.getDepth());
1715
1716         // Coordinates and lod per triangle.
1717         const tcu::Vec3                                                         triS[2]                         = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
1718         const tcu::Vec3                                                         triT[2]                         = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
1719         const tcu::Vec3                                                         triR[2]                         = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
1720         const tcu::Vec3                                                         triW[2]                         = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
1721
1722         const tcu::Vec2                                                         lodBias                         ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
1723
1724         const float                                                                     posEps                          = 1.0f / float(1<<MIN_SUBPIXEL_BITS);
1725
1726         int                                                                                     numFailed                       = 0;
1727
1728         const tcu::Vec2 lodOffsets[] =
1729         {
1730                 tcu::Vec2(-1,  0),
1731                 tcu::Vec2(+1,  0),
1732                 tcu::Vec2( 0, -1),
1733                 tcu::Vec2( 0, +1),
1734         };
1735
1736         tcu::clear(errorMask, tcu::RGBA::green().toVec());
1737
1738         for (int py = 0; py < result.getHeight(); py++)
1739         {
1740                 // Ugly hack, validation can take way too long at the moment.
1741                 if (watchDog)
1742                         qpWatchDog_touch(watchDog);
1743
1744                 for (int px = 0; px < result.getWidth(); px++)
1745                 {
1746                         const tcu::Vec4 resPix  = (result.getPixel(px, py)              - sampleParams.colorBias) / sampleParams.colorScale;
1747                         const tcu::Vec4 refPix  = (reference.getPixel(px, py)   - sampleParams.colorBias) / sampleParams.colorScale;
1748
1749                         // Try comparison to ideal reference first, and if that fails use slower verificator.
1750                         if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
1751                         {
1752                                 const float             wx              = (float)px + 0.5f;
1753                                 const float             wy              = (float)py + 0.5f;
1754                                 const float             nx              = wx / dstW;
1755                                 const float             ny              = wy / dstH;
1756
1757                                 const bool              tri0    = (wx-posEps)/dstW + (wy-posEps)/dstH <= 1.0f;
1758                                 const bool              tri1    = (wx+posEps)/dstW + (wy+posEps)/dstH >= 1.0f;
1759
1760                                 bool                    isOk    = false;
1761
1762                                 DE_ASSERT(tri0 || tri1);
1763
1764                                 // Pixel can belong to either of the triangles if it lies close enough to the edge.
1765                                 for (int triNdx = (tri0?0:1); triNdx <= (tri1?1:0); triNdx++)
1766                                 {
1767                                         const float             triWx   = triNdx ? dstW - wx : wx;
1768                                         const float             triWy   = triNdx ? dstH - wy : wy;
1769                                         const float             triNx   = triNdx ? 1.0f - nx : nx;
1770                                         const float             triNy   = triNdx ? 1.0f - ny : ny;
1771
1772                                         const tcu::Vec3 coord           (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
1773                                                                                                  projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
1774                                                                                                  projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy));
1775                                         const tcu::Vec3 coordDx         = tcu::Vec3(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
1776                                                                                                                         triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy),
1777                                                                                                                         triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy)) * srcSize.asFloat();
1778                                         const tcu::Vec3 coordDy         = tcu::Vec3(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
1779                                                                                                                         triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx),
1780                                                                                                                         triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx)) * srcSize.asFloat();
1781
1782                                         tcu::Vec2               lodBounds       = tcu::computeLodBoundsFromDerivates(coordDx.x(), coordDx.y(), coordDx.z(), coordDy.x(), coordDy.y(), coordDy.z(), lodPrec);
1783
1784                                         // Compute lod bounds across lodOffsets range.
1785                                         for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
1786                                         {
1787                                                 const float             wxo             = triWx + lodOffsets[lodOffsNdx].x();
1788                                                 const float             wyo             = triWy + lodOffsets[lodOffsNdx].y();
1789                                                 const float             nxo             = wxo/dstW;
1790                                                 const float             nyo             = wyo/dstH;
1791
1792                                                 const tcu::Vec3 coordDxo        = tcu::Vec3(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
1793                                                                                                                                 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo),
1794                                                                                                                                 triDerivateX(triR[triNdx], triW[triNdx], wxo, dstW, nyo)) * srcSize.asFloat();
1795                                                 const tcu::Vec3 coordDyo        = tcu::Vec3(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
1796                                                                                                                                 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo),
1797                                                                                                                                 triDerivateY(triR[triNdx], triW[triNdx], wyo, dstH, nxo)) * srcSize.asFloat();
1798                                                 const tcu::Vec2 lodO            = tcu::computeLodBoundsFromDerivates(coordDxo.x(), coordDxo.y(), coordDxo.z(), coordDyo.x(), coordDyo.y(), coordDyo.z(), lodPrec);
1799
1800                                                 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
1801                                                 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
1802                                         }
1803
1804                                         const tcu::Vec2 clampedLod      = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
1805
1806                                         if (tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix))
1807                                         {
1808                                                 isOk = true;
1809                                                 break;
1810                                         }
1811                                 }
1812
1813                                 if (!isOk)
1814                                 {
1815                                         errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
1816                                         numFailed += 1;
1817                                 }
1818                         }
1819                 }
1820         }
1821
1822         return numFailed;
1823 }
1824
1825 bool verifyTextureResult (tcu::TestContext&                                             testCtx,
1826                                                   const tcu::ConstPixelBufferAccess&    result,
1827                                                   const tcu::Texture3DView&                             src,
1828                                                   const float*                                                  texCoord,
1829                                                   const ReferenceParams&                                sampleParams,
1830                                                   const tcu::LookupPrecision&                   lookupPrec,
1831                                                   const tcu::LodPrecision&                              lodPrec,
1832                                                   const tcu::PixelFormat&                               pixelFormat)
1833 {
1834         tcu::TestLog&   log                             = testCtx.getLog();
1835         tcu::Surface    reference               (result.getWidth(), result.getHeight());
1836         tcu::Surface    errorMask               (result.getWidth(), result.getHeight());
1837         int                             numFailedPixels;
1838
1839         DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
1840
1841         sampleTexture(tcu::SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
1842         numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog());
1843
1844         if (numFailedPixels > 0)
1845                 log << tcu::TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << tcu::TestLog::EndMessage;
1846
1847         log << tcu::TestLog::ImageSet("VerifyResult", "Verification result")
1848                 << tcu::TestLog::Image("Rendered", "Rendered image", result);
1849
1850         if (numFailedPixels > 0)
1851         {
1852                 log << tcu::TestLog::Image("Reference", "Ideal reference image", reference)
1853                         << tcu::TestLog::Image("ErrorMask", "Error mask", errorMask);
1854         }
1855
1856         log << tcu::TestLog::EndImageSet;
1857
1858         return numFailedPixels == 0;
1859 }
1860
1861 //! Verifies texture lookup results and returns number of failed pixels.
1862 int computeTextureLookupDiff (const tcu::ConstPixelBufferAccess&        result,
1863                                                           const tcu::ConstPixelBufferAccess&    reference,
1864                                                           const tcu::PixelBufferAccess&                 errorMask,
1865                                                           const tcu::Texture1DArrayView&                baseView,
1866                                                           const float*                                                  texCoord,
1867                                                           const ReferenceParams&                                sampleParams,
1868                                                           const tcu::LookupPrecision&                   lookupPrec,
1869                                                           const tcu::LodPrecision&                              lodPrec,
1870                                                           qpWatchDog*                                                   watchDog)
1871 {
1872         DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
1873         DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
1874
1875         std::vector<tcu::ConstPixelBufferAccess>        srcLevelStorage;
1876         const tcu::Texture1DArrayView                           src                                     = getEffectiveTextureView(baseView, srcLevelStorage, sampleParams.sampler);
1877
1878         const tcu::Vec4                                                         sq                                      = tcu::Vec4(texCoord[0+0], texCoord[2+0], texCoord[4+0], texCoord[6+0]);
1879         const tcu::Vec4                                                         tq                                      = tcu::Vec4(texCoord[0+1], texCoord[2+1], texCoord[4+1], texCoord[6+1]);
1880
1881         const tcu::IVec2                                                        dstSize                         = tcu::IVec2(result.getWidth(), result.getHeight());
1882         const float                                                                     dstW                            = float(dstSize.x());
1883         const float                                                                     dstH                            = float(dstSize.y());
1884         const float                                                                     srcSize                         = float(src.getWidth()); // For lod computation, thus #layers is ignored.
1885
1886         // Coordinates and lod per triangle.
1887         const tcu::Vec3                                                         triS[2]                         = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
1888         const tcu::Vec3                                                         triT[2]                         = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
1889         const tcu::Vec3                                                         triW[2]                         = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
1890
1891         const tcu::Vec2                                                         lodBias                         ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
1892
1893         int                                                                                     numFailed                       = 0;
1894
1895         const tcu::Vec2 lodOffsets[] =
1896         {
1897                 tcu::Vec2(-1,  0),
1898                 tcu::Vec2(+1,  0),
1899                 tcu::Vec2( 0, -1),
1900                 tcu::Vec2( 0, +1),
1901         };
1902
1903         tcu::clear(errorMask, tcu::RGBA::green().toVec());
1904
1905         for (int py = 0; py < result.getHeight(); py++)
1906         {
1907                 // Ugly hack, validation can take way too long at the moment.
1908                 if (watchDog)
1909                         qpWatchDog_touch(watchDog);
1910
1911                 for (int px = 0; px < result.getWidth(); px++)
1912                 {
1913                         const tcu::Vec4 resPix  = (result.getPixel(px, py)              - sampleParams.colorBias) / sampleParams.colorScale;
1914                         const tcu::Vec4 refPix  = (reference.getPixel(px, py)   - sampleParams.colorBias) / sampleParams.colorScale;
1915
1916                         // Try comparison to ideal reference first, and if that fails use slower verificator.
1917                         if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
1918                         {
1919                                 const float             wx              = (float)px + 0.5f;
1920                                 const float             wy              = (float)py + 0.5f;
1921                                 const float             nx              = wx / dstW;
1922                                 const float             ny              = wy / dstH;
1923
1924                                 const int               triNdx  = nx + ny >= 1.0f ? 1 : 0;
1925                                 const float             triWx   = triNdx ? dstW - wx : wx;
1926                                 const float             triWy   = triNdx ? dstH - wy : wy;
1927                                 const float             triNx   = triNdx ? 1.0f - nx : nx;
1928                                 const float             triNy   = triNdx ? 1.0f - ny : ny;
1929
1930                                 const tcu::Vec2 coord   (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
1931                                                                                  projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy));
1932                                 const float     coordDx         = triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy) * srcSize;
1933                                 const float     coordDy         = triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx) * srcSize;
1934
1935                                 tcu::Vec2               lodBounds       = tcu::computeLodBoundsFromDerivates(coordDx, coordDy, lodPrec);
1936
1937                                 // Compute lod bounds across lodOffsets range.
1938                                 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
1939                                 {
1940                                         const float             wxo             = triWx + lodOffsets[lodOffsNdx].x();
1941                                         const float             wyo             = triWy + lodOffsets[lodOffsNdx].y();
1942                                         const float             nxo             = wxo/dstW;
1943                                         const float             nyo             = wyo/dstH;
1944
1945                                         const float     coordDxo                = triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo) * srcSize;
1946                                         const float     coordDyo                = triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo) * srcSize;
1947                                         const tcu::Vec2 lodO            = tcu::computeLodBoundsFromDerivates(coordDxo, coordDyo, lodPrec);
1948
1949                                         lodBounds.x() = de::min(lodBounds.x(), lodO.x());
1950                                         lodBounds.y() = de::max(lodBounds.y(), lodO.y());
1951                                 }
1952
1953                                 const tcu::Vec2 clampedLod      = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
1954                                 const bool              isOk            = tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix);
1955
1956                                 if (!isOk)
1957                                 {
1958                                         errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
1959                                         numFailed += 1;
1960                                 }
1961                         }
1962                 }
1963         }
1964
1965         return numFailed;
1966 }
1967
1968 //! Verifies texture lookup results and returns number of failed pixels.
1969 int computeTextureLookupDiff (const tcu::ConstPixelBufferAccess&        result,
1970                                                           const tcu::ConstPixelBufferAccess&    reference,
1971                                                           const tcu::PixelBufferAccess&                 errorMask,
1972                                                           const tcu::Texture2DArrayView&                baseView,
1973                                                           const float*                                                  texCoord,
1974                                                           const ReferenceParams&                                sampleParams,
1975                                                           const tcu::LookupPrecision&                   lookupPrec,
1976                                                           const tcu::LodPrecision&                              lodPrec,
1977                                                           qpWatchDog*                                                   watchDog)
1978 {
1979         DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
1980         DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
1981
1982         std::vector<tcu::ConstPixelBufferAccess>        srcLevelStorage;
1983         const tcu::Texture2DArrayView                           src                                     = getEffectiveTextureView(baseView, srcLevelStorage, sampleParams.sampler);
1984
1985         const tcu::Vec4                                                         sq                                      = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
1986         const tcu::Vec4                                                         tq                                      = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
1987         const tcu::Vec4                                                         rq                                      = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
1988
1989         const tcu::IVec2                                                        dstSize                         = tcu::IVec2(result.getWidth(), result.getHeight());
1990         const float                                                                     dstW                            = float(dstSize.x());
1991         const float                                                                     dstH                            = float(dstSize.y());
1992         const tcu::Vec2                                                         srcSize                         = tcu::IVec2(src.getWidth(), src.getHeight()).asFloat(); // For lod computation, thus #layers is ignored.
1993
1994         // Coordinates and lod per triangle.
1995         const tcu::Vec3                                                         triS[2]                         = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
1996         const tcu::Vec3                                                         triT[2]                         = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
1997         const tcu::Vec3                                                         triR[2]                         = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
1998         const tcu::Vec3                                                         triW[2]                         = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
1999
2000         const tcu::Vec2                                                         lodBias                         ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
2001
2002         int                                                                                     numFailed                       = 0;
2003
2004         const tcu::Vec2 lodOffsets[] =
2005         {
2006                 tcu::Vec2(-1,  0),
2007                 tcu::Vec2(+1,  0),
2008                 tcu::Vec2( 0, -1),
2009                 tcu::Vec2( 0, +1),
2010         };
2011
2012         tcu::clear(errorMask, tcu::RGBA::green().toVec());
2013
2014         for (int py = 0; py < result.getHeight(); py++)
2015         {
2016                 // Ugly hack, validation can take way too long at the moment.
2017                 if (watchDog)
2018                         qpWatchDog_touch(watchDog);
2019
2020                 for (int px = 0; px < result.getWidth(); px++)
2021                 {
2022                         const tcu::Vec4 resPix  = (result.getPixel(px, py)              - sampleParams.colorBias) / sampleParams.colorScale;
2023                         const tcu::Vec4 refPix  = (reference.getPixel(px, py)   - sampleParams.colorBias) / sampleParams.colorScale;
2024
2025                         // Try comparison to ideal reference first, and if that fails use slower verificator.
2026                         if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
2027                         {
2028                                 const float             wx              = (float)px + 0.5f;
2029                                 const float             wy              = (float)py + 0.5f;
2030                                 const float             nx              = wx / dstW;
2031                                 const float             ny              = wy / dstH;
2032
2033                                 const int               triNdx  = nx + ny >= 1.0f ? 1 : 0;
2034                                 const float             triWx   = triNdx ? dstW - wx : wx;
2035                                 const float             triWy   = triNdx ? dstH - wy : wy;
2036                                 const float             triNx   = triNdx ? 1.0f - nx : nx;
2037                                 const float             triNy   = triNdx ? 1.0f - ny : ny;
2038
2039                                 const tcu::Vec3 coord           (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
2040                                                                                          projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
2041                                                                                          projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy));
2042                                 const tcu::Vec2 coordDx         = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
2043                                                                                                                 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy)) * srcSize;
2044                                 const tcu::Vec2 coordDy         = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
2045                                                                                                                 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx)) * srcSize;
2046
2047                                 tcu::Vec2               lodBounds       = tcu::computeLodBoundsFromDerivates(coordDx.x(), coordDx.y(), coordDy.x(), coordDy.y(), lodPrec);
2048
2049                                 // Compute lod bounds across lodOffsets range.
2050                                 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
2051                                 {
2052                                         const float             wxo             = triWx + lodOffsets[lodOffsNdx].x();
2053                                         const float             wyo             = triWy + lodOffsets[lodOffsNdx].y();
2054                                         const float             nxo             = wxo/dstW;
2055                                         const float             nyo             = wyo/dstH;
2056
2057                                         const tcu::Vec2 coordDxo        = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
2058                                                                                                                         triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo)) * srcSize;
2059                                         const tcu::Vec2 coordDyo        = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
2060                                                                                                                         triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo)) * srcSize;
2061                                         const tcu::Vec2 lodO            = tcu::computeLodBoundsFromDerivates(coordDxo.x(), coordDxo.y(), coordDyo.x(), coordDyo.y(), lodPrec);
2062
2063                                         lodBounds.x() = de::min(lodBounds.x(), lodO.x());
2064                                         lodBounds.y() = de::max(lodBounds.y(), lodO.y());
2065                                 }
2066
2067                                 const tcu::Vec2 clampedLod      = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
2068                                 const bool              isOk            = tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix);
2069
2070                                 if (!isOk)
2071                                 {
2072                                         errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
2073                                         numFailed += 1;
2074                                 }
2075                         }
2076                 }
2077         }
2078
2079         return numFailed;
2080 }
2081
2082 bool verifyTextureResult (tcu::TestContext&                                             testCtx,
2083                                                   const tcu::ConstPixelBufferAccess&    result,
2084                                                   const tcu::Texture1DArrayView&                src,
2085                                                   const float*                                                  texCoord,
2086                                                   const ReferenceParams&                                sampleParams,
2087                                                   const tcu::LookupPrecision&                   lookupPrec,
2088                                                   const tcu::LodPrecision&                              lodPrec,
2089                                                   const tcu::PixelFormat&                               pixelFormat)
2090 {
2091         tcu::TestLog&   log                             = testCtx.getLog();
2092         tcu::Surface    reference               (result.getWidth(), result.getHeight());
2093         tcu::Surface    errorMask               (result.getWidth(), result.getHeight());
2094         int                             numFailedPixels;
2095
2096         DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
2097
2098         sampleTexture(tcu::SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
2099         numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog());
2100
2101         if (numFailedPixels > 0)
2102                 log << tcu::TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << tcu::TestLog::EndMessage;
2103
2104         log << tcu::TestLog::ImageSet("VerifyResult", "Verification result")
2105                 << tcu::TestLog::Image("Rendered", "Rendered image", result);
2106
2107         if (numFailedPixels > 0)
2108         {
2109                 log << tcu::TestLog::Image("Reference", "Ideal reference image", reference)
2110                         << tcu::TestLog::Image("ErrorMask", "Error mask", errorMask);
2111         }
2112
2113         log << tcu::TestLog::EndImageSet;
2114
2115         return numFailedPixels == 0;
2116 }
2117
2118 bool verifyTextureResult (tcu::TestContext&                                             testCtx,
2119                                                   const tcu::ConstPixelBufferAccess&    result,
2120                                                   const tcu::Texture2DArrayView&                src,
2121                                                   const float*                                                  texCoord,
2122                                                   const ReferenceParams&                                sampleParams,
2123                                                   const tcu::LookupPrecision&                   lookupPrec,
2124                                                   const tcu::LodPrecision&                              lodPrec,
2125                                                   const tcu::PixelFormat&                               pixelFormat)
2126 {
2127         tcu::TestLog&   log                             = testCtx.getLog();
2128         tcu::Surface    reference               (result.getWidth(), result.getHeight());
2129         tcu::Surface    errorMask               (result.getWidth(), result.getHeight());
2130         int                             numFailedPixels;
2131
2132         DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
2133
2134         sampleTexture(tcu::SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
2135         numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog());
2136
2137         if (numFailedPixels > 0)
2138                 log << tcu::TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << tcu::TestLog::EndMessage;
2139
2140         log << tcu::TestLog::ImageSet("VerifyResult", "Verification result")
2141                 << tcu::TestLog::Image("Rendered", "Rendered image", result);
2142
2143         if (numFailedPixels > 0)
2144         {
2145                 log << tcu::TestLog::Image("Reference", "Ideal reference image", reference)
2146                         << tcu::TestLog::Image("ErrorMask", "Error mask", errorMask);
2147         }
2148
2149         log << tcu::TestLog::EndImageSet;
2150
2151         return numFailedPixels == 0;
2152 }
2153
2154 //! Verifies texture lookup results and returns number of failed pixels.
2155 int computeTextureLookupDiff (const tcu::ConstPixelBufferAccess&        result,
2156                                                           const tcu::ConstPixelBufferAccess&    reference,
2157                                                           const tcu::PixelBufferAccess&                 errorMask,
2158                                                           const tcu::TextureCubeArrayView&              baseView,
2159                                                           const float*                                                  texCoord,
2160                                                           const ReferenceParams&                                sampleParams,
2161                                                           const tcu::LookupPrecision&                   lookupPrec,
2162                                                           const tcu::IVec4&                                             coordBits,
2163                                                           const tcu::LodPrecision&                              lodPrec,
2164                                                           qpWatchDog*                                                   watchDog)
2165 {
2166         DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
2167         DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
2168
2169         std::vector<tcu::ConstPixelBufferAccess>        srcLevelStorage;
2170         const tcu::TextureCubeArrayView                         src                                     = getEffectiveTextureView(getSubView(baseView, sampleParams.baseLevel, sampleParams.maxLevel), srcLevelStorage, sampleParams.sampler);
2171
2172         const tcu::Vec4                                                         sq                                      = tcu::Vec4(texCoord[0+0], texCoord[4+0], texCoord[8+0], texCoord[12+0]);
2173         const tcu::Vec4                                                         tq                                      = tcu::Vec4(texCoord[0+1], texCoord[4+1], texCoord[8+1], texCoord[12+1]);
2174         const tcu::Vec4                                                         rq                                      = tcu::Vec4(texCoord[0+2], texCoord[4+2], texCoord[8+2], texCoord[12+2]);
2175         const tcu::Vec4                                                         qq                                      = tcu::Vec4(texCoord[0+3], texCoord[4+3], texCoord[8+3], texCoord[12+3]);
2176
2177         const tcu::IVec2                                                        dstSize                         = tcu::IVec2(result.getWidth(), result.getHeight());
2178         const float                                                                     dstW                            = float(dstSize.x());
2179         const float                                                                     dstH                            = float(dstSize.y());
2180         const int                                                                       srcSize                         = src.getSize();
2181
2182         // Coordinates per triangle.
2183         const tcu::Vec3                                                         triS[2]                         = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
2184         const tcu::Vec3                                                         triT[2]                         = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
2185         const tcu::Vec3                                                         triR[2]                         = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
2186         const tcu::Vec3                                                         triQ[2]                         = { qq.swizzle(0, 1, 2), qq.swizzle(3, 2, 1) };
2187         const tcu::Vec3                                                         triW[2]                         = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
2188
2189         const tcu::Vec2                                                         lodBias                         ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
2190
2191         const float                                                                     posEps                          = 1.0f / float((1<<4) + 1); // ES3 requires at least 4 subpixel bits.
2192
2193         int                                                                                     numFailed                       = 0;
2194
2195         const tcu::Vec2 lodOffsets[] =
2196         {
2197                 tcu::Vec2(-1,  0),
2198                 tcu::Vec2(+1,  0),
2199                 tcu::Vec2( 0, -1),
2200                 tcu::Vec2( 0, +1),
2201
2202                 // \note Not strictly allowed by spec, but implementations do this in practice.
2203                 tcu::Vec2(-1, -1),
2204                 tcu::Vec2(-1, +1),
2205                 tcu::Vec2(+1, -1),
2206                 tcu::Vec2(+1, +1),
2207         };
2208
2209         tcu::clear(errorMask, tcu::RGBA::green().toVec());
2210
2211         for (int py = 0; py < result.getHeight(); py++)
2212         {
2213                 // Ugly hack, validation can take way too long at the moment.
2214                 if (watchDog)
2215                         qpWatchDog_touch(watchDog);
2216
2217                 for (int px = 0; px < result.getWidth(); px++)
2218                 {
2219                         const tcu::Vec4 resPix  = (result.getPixel(px, py)              - sampleParams.colorBias) / sampleParams.colorScale;
2220                         const tcu::Vec4 refPix  = (reference.getPixel(px, py)   - sampleParams.colorBias) / sampleParams.colorScale;
2221
2222                         // Try comparison to ideal reference first, and if that fails use slower verificator.
2223                         if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
2224                         {
2225                                 const float             wx              = (float)px + 0.5f;
2226                                 const float             wy              = (float)py + 0.5f;
2227                                 const float             nx              = wx / dstW;
2228                                 const float             ny              = wy / dstH;
2229
2230                                 const bool              tri0    = nx + ny - posEps <= 1.0f;
2231                                 const bool              tri1    = nx + ny + posEps >= 1.0f;
2232
2233                                 bool                    isOk    = false;
2234
2235                                 DE_ASSERT(tri0 || tri1);
2236
2237                                 // Pixel can belong to either of the triangles if it lies close enough to the edge.
2238                                 for (int triNdx = (tri0?0:1); triNdx <= (tri1?1:0); triNdx++)
2239                                 {
2240                                         const float             triWx           = triNdx ? dstW - wx : wx;
2241                                         const float             triWy           = triNdx ? dstH - wy : wy;
2242                                         const float             triNx           = triNdx ? 1.0f - nx : nx;
2243                                         const float             triNy           = triNdx ? 1.0f - ny : ny;
2244
2245                                         const tcu::Vec4 coord           (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
2246                                                                                                  projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
2247                                                                                                  projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy),
2248                                                                                                  projectedTriInterpolate(triQ[triNdx], triW[triNdx], triNx, triNy));
2249                                         const tcu::Vec3 coordDx         (triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
2250                                                                                                  triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy),
2251                                                                                                  triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy));
2252                                         const tcu::Vec3 coordDy         (triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
2253                                                                                                  triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx),
2254                                                                                                  triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx));
2255
2256                                         tcu::Vec2               lodBounds       = tcu::computeCubeLodBoundsFromDerivates(coord.toWidth<3>(), coordDx, coordDy, srcSize, lodPrec);
2257
2258                                         // Compute lod bounds across lodOffsets range.
2259                                         for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
2260                                         {
2261                                                 const float             wxo                     = triWx + lodOffsets[lodOffsNdx].x();
2262                                                 const float             wyo                     = triWy + lodOffsets[lodOffsNdx].y();
2263                                                 const float             nxo                     = wxo/dstW;
2264                                                 const float             nyo                     = wyo/dstH;
2265
2266                                                 const tcu::Vec3 coordO          (projectedTriInterpolate(triS[triNdx], triW[triNdx], nxo, nyo),
2267                                                                                                          projectedTriInterpolate(triT[triNdx], triW[triNdx], nxo, nyo),
2268                                                                                                          projectedTriInterpolate(triR[triNdx], triW[triNdx], nxo, nyo));
2269                                                 const tcu::Vec3 coordDxo        (triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
2270                                                                                                          triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo),
2271                                                                                                          triDerivateX(triR[triNdx], triW[triNdx], wxo, dstW, nyo));
2272                                                 const tcu::Vec3 coordDyo        (triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
2273                                                                                                          triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo),
2274                                                                                                          triDerivateY(triR[triNdx], triW[triNdx], wyo, dstH, nxo));
2275                                                 const tcu::Vec2 lodO            = tcu::computeCubeLodBoundsFromDerivates(coordO, coordDxo, coordDyo, srcSize, lodPrec);
2276
2277                                                 lodBounds.x() = de::min(lodBounds.x(), lodO.x());
2278                                                 lodBounds.y() = de::max(lodBounds.y(), lodO.y());
2279                                         }
2280
2281                                         const tcu::Vec2 clampedLod      = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
2282
2283                                         if (tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coordBits, coord, clampedLod, resPix))
2284                                         {
2285                                                 isOk = true;
2286                                                 break;
2287                                         }
2288                                 }
2289
2290                                 if (!isOk)
2291                                 {
2292                                         errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
2293                                         numFailed += 1;
2294                                 }
2295                         }
2296                 }
2297         }
2298
2299         return numFailed;
2300 }
2301
2302 bool verifyTextureResult (tcu::TestContext&                                             testCtx,
2303                                                   const tcu::ConstPixelBufferAccess&    result,
2304                                                   const tcu::TextureCubeArrayView&              src,
2305                                                   const float*                                                  texCoord,
2306                                                   const ReferenceParams&                                sampleParams,
2307                                                   const tcu::LookupPrecision&                   lookupPrec,
2308                                                   const tcu::IVec4&                                             coordBits,
2309                                                   const tcu::LodPrecision&                              lodPrec,
2310                                                   const tcu::PixelFormat&                               pixelFormat)
2311 {
2312         tcu::TestLog&   log                             = testCtx.getLog();
2313         tcu::Surface    reference               (result.getWidth(), result.getHeight());
2314         tcu::Surface    errorMask               (result.getWidth(), result.getHeight());
2315         int                             numFailedPixels;
2316
2317         DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
2318
2319         sampleTexture(tcu::SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
2320         numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, coordBits, lodPrec, testCtx.getWatchDog());
2321
2322         if (numFailedPixels > 0)
2323                 log << tcu::TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << tcu::TestLog::EndMessage;
2324
2325         log << tcu::TestLog::ImageSet("VerifyResult", "Verification result")
2326                 << tcu::TestLog::Image("Rendered", "Rendered image", result);
2327
2328         if (numFailedPixels > 0)
2329         {
2330                 log << tcu::TestLog::Image("Reference", "Ideal reference image", reference)
2331                         << tcu::TestLog::Image("ErrorMask", "Error mask", errorMask);
2332         }
2333
2334         log << tcu::TestLog::EndImageSet;
2335
2336         return numFailedPixels == 0;
2337 }
2338
2339 // Shadow lookup verification
2340
2341 int computeTextureCompareDiff (const tcu::ConstPixelBufferAccess&       result,
2342                                                            const tcu::ConstPixelBufferAccess&   reference,
2343                                                            const tcu::PixelBufferAccess&                errorMask,
2344                                                            const tcu::Texture2DView&                    src,
2345                                                            const float*                                                 texCoord,
2346                                                            const ReferenceParams&                               sampleParams,
2347                                                            const tcu::TexComparePrecision&              comparePrec,
2348                                                            const tcu::LodPrecision&                             lodPrec,
2349                                                            const tcu::Vec3&                                             nonShadowThreshold)
2350 {
2351         DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
2352         DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
2353
2354         const tcu::Vec4         sq                              = tcu::Vec4(texCoord[0+0], texCoord[2+0], texCoord[4+0], texCoord[6+0]);
2355         const tcu::Vec4         tq                              = tcu::Vec4(texCoord[0+1], texCoord[2+1], texCoord[4+1], texCoord[6+1]);
2356
2357         const tcu::IVec2        dstSize                 = tcu::IVec2(result.getWidth(), result.getHeight());
2358         const float                     dstW                    = float(dstSize.x());
2359         const float                     dstH                    = float(dstSize.y());
2360         const tcu::IVec2        srcSize                 = tcu::IVec2(src.getWidth(), src.getHeight());
2361
2362         // Coordinates and lod per triangle.
2363         const tcu::Vec3         triS[2]                 = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
2364         const tcu::Vec3         triT[2]                 = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
2365         const tcu::Vec3         triW[2]                 = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
2366
2367         const tcu::Vec2         lodBias                 ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
2368
2369         int                                     numFailed               = 0;
2370
2371         const tcu::Vec2 lodOffsets[] =
2372         {
2373                 tcu::Vec2(-1,  0),
2374                 tcu::Vec2(+1,  0),
2375                 tcu::Vec2( 0, -1),
2376                 tcu::Vec2( 0, +1),
2377         };
2378
2379         tcu::clear(errorMask, tcu::RGBA::green().toVec());
2380
2381         for (int py = 0; py < result.getHeight(); py++)
2382         {
2383                 for (int px = 0; px < result.getWidth(); px++)
2384                 {
2385                         const tcu::Vec4 resPix  = result.getPixel(px, py);
2386                         const tcu::Vec4 refPix  = reference.getPixel(px, py);
2387
2388                         // Other channels should trivially match to reference.
2389                         if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(refPix.swizzle(1,2,3) - resPix.swizzle(1,2,3)), nonShadowThreshold)))
2390                         {
2391                                 errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
2392                                 numFailed += 1;
2393                                 continue;
2394                         }
2395
2396                         // Reference result is known to be a valid result, we can
2397                         // skip verification if thes results are equal
2398                         if (resPix.x() != refPix.x())
2399                         {
2400                                 const float             wx              = (float)px + 0.5f;
2401                                 const float             wy              = (float)py + 0.5f;
2402                                 const float             nx              = wx / dstW;
2403                                 const float             ny              = wy / dstH;
2404
2405                                 const int               triNdx  = nx + ny >= 1.0f ? 1 : 0;
2406                                 const float             triWx   = triNdx ? dstW - wx : wx;
2407                                 const float             triWy   = triNdx ? dstH - wy : wy;
2408                                 const float             triNx   = triNdx ? 1.0f - nx : nx;
2409                                 const float             triNy   = triNdx ? 1.0f - ny : ny;
2410
2411                                 const tcu::Vec2 coord           (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
2412                                                                                          projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy));
2413                                 const tcu::Vec2 coordDx         = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
2414                                                                                                                 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy)) * srcSize.asFloat();
2415                                 const tcu::Vec2 coordDy         = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
2416                                                                                                                 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx)) * srcSize.asFloat();
2417
2418                                 tcu::Vec2               lodBounds       = tcu::computeLodBoundsFromDerivates(coordDx.x(), coordDx.y(), coordDy.x(), coordDy.y(), lodPrec);
2419
2420                                 // Compute lod bounds across lodOffsets range.
2421                                 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
2422                                 {
2423                                         const float             wxo             = triWx + lodOffsets[lodOffsNdx].x();
2424                                         const float             wyo             = triWy + lodOffsets[lodOffsNdx].y();
2425                                         const float             nxo             = wxo/dstW;
2426                                         const float             nyo             = wyo/dstH;
2427
2428                                         const tcu::Vec2 coordDxo        = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
2429                                                                                                                         triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo)) * srcSize.asFloat();
2430                                         const tcu::Vec2 coordDyo        = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
2431                                                                                                                         triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo)) * srcSize.asFloat();
2432                                         const tcu::Vec2 lodO            = tcu::computeLodBoundsFromDerivates(coordDxo.x(), coordDxo.y(), coordDyo.x(), coordDyo.y(), lodPrec);
2433
2434                                         lodBounds.x() = de::min(lodBounds.x(), lodO.x());
2435                                         lodBounds.y() = de::max(lodBounds.y(), lodO.y());
2436                                 }
2437
2438                                 const tcu::Vec2 clampedLod      = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
2439                                 const bool              isOk            = tcu::isTexCompareResultValid(src, sampleParams.sampler, comparePrec, coord, clampedLod, sampleParams.ref, resPix.x());
2440
2441                                 if (!isOk)
2442                                 {
2443                                         errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
2444                                         numFailed += 1;
2445                                 }
2446                         }
2447                 }
2448         }
2449
2450         return numFailed;
2451 }
2452
2453 int computeTextureCompareDiff (const tcu::ConstPixelBufferAccess&       result,
2454                                                            const tcu::ConstPixelBufferAccess&   reference,
2455                                                            const tcu::PixelBufferAccess&                errorMask,
2456                                                            const tcu::TextureCubeView&                  src,
2457                                                            const float*                                                 texCoord,
2458                                                            const ReferenceParams&                               sampleParams,
2459                                                            const tcu::TexComparePrecision&              comparePrec,
2460                                                            const tcu::LodPrecision&                             lodPrec,
2461                                                            const tcu::Vec3&                                             nonShadowThreshold)
2462 {
2463         DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
2464         DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
2465
2466         const tcu::Vec4         sq                              = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
2467         const tcu::Vec4         tq                              = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
2468         const tcu::Vec4         rq                              = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
2469
2470         const tcu::IVec2        dstSize                 = tcu::IVec2(result.getWidth(), result.getHeight());
2471         const float                     dstW                    = float(dstSize.x());
2472         const float                     dstH                    = float(dstSize.y());
2473         const int                       srcSize                 = src.getSize();
2474
2475         // Coordinates per triangle.
2476         const tcu::Vec3         triS[2]                 = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
2477         const tcu::Vec3         triT[2]                 = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
2478         const tcu::Vec3         triR[2]                 = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
2479         const tcu::Vec3         triW[2]                 = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
2480
2481         const tcu::Vec2         lodBias                 ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
2482
2483         int                                     numFailed               = 0;
2484
2485         const tcu::Vec2 lodOffsets[] =
2486         {
2487                 tcu::Vec2(-1,  0),
2488                 tcu::Vec2(+1,  0),
2489                 tcu::Vec2( 0, -1),
2490                 tcu::Vec2( 0, +1),
2491         };
2492
2493         tcu::clear(errorMask, tcu::RGBA::green().toVec());
2494
2495         for (int py = 0; py < result.getHeight(); py++)
2496         {
2497                 for (int px = 0; px < result.getWidth(); px++)
2498                 {
2499                         const tcu::Vec4 resPix  = result.getPixel(px, py);
2500                         const tcu::Vec4 refPix  = reference.getPixel(px, py);
2501
2502                         // Other channels should trivially match to reference.
2503                         if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(refPix.swizzle(1,2,3) - resPix.swizzle(1,2,3)), nonShadowThreshold)))
2504                         {
2505                                 errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
2506                                 numFailed += 1;
2507                                 continue;
2508                         }
2509
2510                         // Reference result is known to be a valid result, we can
2511                         // skip verification if thes results are equal
2512                         if (resPix.x() != refPix.x())
2513                         {
2514                                 const float             wx              = (float)px + 0.5f;
2515                                 const float             wy              = (float)py + 0.5f;
2516                                 const float             nx              = wx / dstW;
2517                                 const float             ny              = wy / dstH;
2518
2519                                 const int               triNdx  = nx + ny >= 1.0f ? 1 : 0;
2520                                 const float             triWx   = triNdx ? dstW - wx : wx;
2521                                 const float             triWy   = triNdx ? dstH - wy : wy;
2522                                 const float             triNx   = triNdx ? 1.0f - nx : nx;
2523                                 const float             triNy   = triNdx ? 1.0f - ny : ny;
2524
2525                                 const tcu::Vec3 coord           (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
2526                                                                                          projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
2527                                                                                          projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy));
2528                                 const tcu::Vec3 coordDx         (triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
2529                                                                                          triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy),
2530                                                                                          triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy));
2531                                 const tcu::Vec3 coordDy         (triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
2532                                                                                          triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx),
2533                                                                                          triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx));
2534
2535                                 tcu::Vec2               lodBounds       = tcu::computeCubeLodBoundsFromDerivates(coord, coordDx, coordDy, srcSize, lodPrec);
2536
2537                                 // Compute lod bounds across lodOffsets range.
2538                                 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
2539                                 {
2540                                         const float             wxo             = triWx + lodOffsets[lodOffsNdx].x();
2541                                         const float             wyo             = triWy + lodOffsets[lodOffsNdx].y();
2542                                         const float             nxo             = wxo/dstW;
2543                                         const float             nyo             = wyo/dstH;
2544
2545                                         const tcu::Vec3 coordO          (projectedTriInterpolate(triS[triNdx], triW[triNdx], nxo, nyo),
2546                                                                                                  projectedTriInterpolate(triT[triNdx], triW[triNdx], nxo, nyo),
2547                                                                                                  projectedTriInterpolate(triR[triNdx], triW[triNdx], nxo, nyo));
2548                                         const tcu::Vec3 coordDxo        (triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
2549                                                                                                  triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo),
2550                                                                                                  triDerivateX(triR[triNdx], triW[triNdx], wxo, dstW, nyo));
2551                                         const tcu::Vec3 coordDyo        (triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
2552                                                                                                  triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo),
2553                                                                                                  triDerivateY(triR[triNdx], triW[triNdx], wyo, dstH, nxo));
2554                                         const tcu::Vec2 lodO            = tcu::computeCubeLodBoundsFromDerivates(coordO, coordDxo, coordDyo, srcSize, lodPrec);
2555
2556                                         lodBounds.x() = de::min(lodBounds.x(), lodO.x());
2557                                         lodBounds.y() = de::max(lodBounds.y(), lodO.y());
2558                                 }
2559
2560                                 const tcu::Vec2 clampedLod      = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
2561                                 const bool              isOk            = tcu::isTexCompareResultValid(src, sampleParams.sampler, comparePrec, coord, clampedLod, sampleParams.ref, resPix.x());
2562
2563                                 if (!isOk)
2564                                 {
2565                                         errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
2566                                         numFailed += 1;
2567                                 }
2568                         }
2569                 }
2570         }
2571
2572         return numFailed;
2573 }
2574
2575 int computeTextureCompareDiff (const tcu::ConstPixelBufferAccess&       result,
2576                                                            const tcu::ConstPixelBufferAccess&   reference,
2577                                                            const tcu::PixelBufferAccess&                errorMask,
2578                                                            const tcu::Texture2DArrayView&               src,
2579                                                            const float*                                                 texCoord,
2580                                                            const ReferenceParams&                               sampleParams,
2581                                                            const tcu::TexComparePrecision&              comparePrec,
2582                                                            const tcu::LodPrecision&                             lodPrec,
2583                                                            const tcu::Vec3&                                             nonShadowThreshold)
2584 {
2585         DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
2586         DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
2587
2588         const tcu::Vec4         sq                              = tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
2589         const tcu::Vec4         tq                              = tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
2590         const tcu::Vec4         rq                              = tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
2591
2592         const tcu::IVec2        dstSize                 = tcu::IVec2(result.getWidth(), result.getHeight());
2593         const float                     dstW                    = float(dstSize.x());
2594         const float                     dstH                    = float(dstSize.y());
2595         const tcu::IVec2        srcSize                 = tcu::IVec2(src.getWidth(), src.getHeight());
2596
2597         // Coordinates and lod per triangle.
2598         const tcu::Vec3         triS[2]                 = { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
2599         const tcu::Vec3         triT[2]                 = { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
2600         const tcu::Vec3         triR[2]                 = { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
2601         const tcu::Vec3         triW[2]                 = { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
2602
2603         const tcu::Vec2         lodBias                 ((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
2604
2605         int                                     numFailed               = 0;
2606
2607         const tcu::Vec2 lodOffsets[] =
2608         {
2609                 tcu::Vec2(-1,  0),
2610                 tcu::Vec2(+1,  0),
2611                 tcu::Vec2( 0, -1),
2612                 tcu::Vec2( 0, +1),
2613         };
2614
2615         tcu::clear(errorMask, tcu::RGBA::green().toVec());
2616
2617         for (int py = 0; py < result.getHeight(); py++)
2618         {
2619                 for (int px = 0; px < result.getWidth(); px++)
2620                 {
2621                         const tcu::Vec4 resPix  = result.getPixel(px, py);
2622                         const tcu::Vec4 refPix  = reference.getPixel(px, py);
2623
2624                         // Other channels should trivially match to reference.
2625                         if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(refPix.swizzle(1,2,3) - resPix.swizzle(1,2,3)), nonShadowThreshold)))
2626                         {
2627                                 errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
2628                                 numFailed += 1;
2629                                 continue;
2630                         }
2631
2632                         // Reference result is known to be a valid result, we can
2633                         // skip verification if thes results are equal
2634                         if (resPix.x() != refPix.x())
2635                         {
2636                                 const float             wx              = (float)px + 0.5f;
2637                                 const float             wy              = (float)py + 0.5f;
2638                                 const float             nx              = wx / dstW;
2639                                 const float             ny              = wy / dstH;
2640
2641                                 const int               triNdx  = nx + ny >= 1.0f ? 1 : 0;
2642                                 const float             triWx   = triNdx ? dstW - wx : wx;
2643                                 const float             triWy   = triNdx ? dstH - wy : wy;
2644                                 const float             triNx   = triNdx ? 1.0f - nx : nx;
2645                                 const float             triNy   = triNdx ? 1.0f - ny : ny;
2646
2647                                 const tcu::Vec3 coord           (projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
2648                                                                                          projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
2649                                                                                          projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy));
2650                                 const tcu::Vec2 coordDx         = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
2651                                                                                                                 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy)) * srcSize.asFloat();
2652                                 const tcu::Vec2 coordDy         = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
2653                                                                                                                 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx)) * srcSize.asFloat();
2654
2655                                 tcu::Vec2               lodBounds       = tcu::computeLodBoundsFromDerivates(coordDx.x(), coordDx.y(), coordDy.x(), coordDy.y(), lodPrec);
2656
2657                                 // Compute lod bounds across lodOffsets range.
2658                                 for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
2659                                 {
2660                                         const float             wxo             = triWx + lodOffsets[lodOffsNdx].x();
2661                                         const float             wyo             = triWy + lodOffsets[lodOffsNdx].y();
2662                                         const float             nxo             = wxo/dstW;
2663                                         const float             nyo             = wyo/dstH;
2664
2665                                         const tcu::Vec2 coordDxo        = tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
2666                                                                                                                         triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo)) * srcSize.asFloat();
2667                                         const tcu::Vec2 coordDyo        = tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
2668                                                                                                                         triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo)) * srcSize.asFloat();
2669                                         const tcu::Vec2 lodO            = tcu::computeLodBoundsFromDerivates(coordDxo.x(), coordDxo.y(), coordDyo.x(), coordDyo.y(), lodPrec);
2670
2671                                         lodBounds.x() = de::min(lodBounds.x(), lodO.x());
2672                                         lodBounds.y() = de::max(lodBounds.y(), lodO.y());
2673                                 }
2674
2675                                 const tcu::Vec2 clampedLod      = tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
2676                                 const bool              isOk            = tcu::isTexCompareResultValid(src, sampleParams.sampler, comparePrec, coord, clampedLod, sampleParams.ref, resPix.x());
2677
2678                                 if (!isOk)
2679                                 {
2680                                         errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
2681                                         numFailed += 1;
2682                                 }
2683                         }
2684                 }
2685         }
2686
2687         return numFailed;
2688 }
2689
2690 // Mipmap generation comparison.
2691
2692 static int compareGenMipmapBilinear (const tcu::ConstPixelBufferAccess& dst, const tcu::ConstPixelBufferAccess& src, const tcu::PixelBufferAccess& errorMask, const GenMipmapPrecision& precision)
2693 {
2694         DE_ASSERT(dst.getDepth() == 1 && src.getDepth() == 1); // \todo [2013-10-29 pyry] 3D textures.
2695
2696         const float             dstW            = float(dst.getWidth());
2697         const float             dstH            = float(dst.getHeight());
2698         const float             srcW            = float(src.getWidth());
2699         const float             srcH            = float(src.getHeight());
2700         int                             numFailed       = 0;
2701
2702         // Translation to lookup verification parameters.
2703         const tcu::Sampler              sampler         (tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE,
2704                                                                                  tcu::Sampler::LINEAR, tcu::Sampler::LINEAR, 0.0f, false /* non-normalized coords */);
2705         tcu::LookupPrecision    lookupPrec;
2706
2707         lookupPrec.colorThreshold       = precision.colorThreshold;
2708         lookupPrec.colorMask            = precision.colorMask;
2709         lookupPrec.coordBits            = tcu::IVec3(22);
2710         lookupPrec.uvwBits                      = precision.filterBits;
2711
2712         for (int y = 0; y < dst.getHeight(); y++)
2713         for (int x = 0; x < dst.getWidth(); x++)
2714         {
2715                 const tcu::Vec4 result  = dst.getPixel(x, y);
2716                 const float             cx              = (float(x)+0.5f) / dstW * srcW;
2717                 const float             cy              = (float(y)+0.5f) / dstH * srcH;
2718                 const bool              isOk    = tcu::isLinearSampleResultValid(src, sampler, lookupPrec, tcu::Vec2(cx, cy), 0, result);
2719
2720                 errorMask.setPixel(isOk ? tcu::RGBA::green().toVec() : tcu::RGBA::red().toVec(), x, y);
2721                 if (!isOk)
2722                         numFailed += 1;
2723         }
2724
2725         return numFailed;
2726 }
2727
2728 static int compareGenMipmapBox (const tcu::ConstPixelBufferAccess& dst, const tcu::ConstPixelBufferAccess& src, const tcu::PixelBufferAccess& errorMask, const GenMipmapPrecision& precision)
2729 {
2730         DE_ASSERT(dst.getDepth() == 1 && src.getDepth() == 1); // \todo [2013-10-29 pyry] 3D textures.
2731
2732         const float             dstW            = float(dst.getWidth());
2733         const float             dstH            = float(dst.getHeight());
2734         const float             srcW            = float(src.getWidth());
2735         const float             srcH            = float(src.getHeight());
2736         int                             numFailed       = 0;
2737
2738         // Translation to lookup verification parameters.
2739         const tcu::Sampler              sampler         (tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE,
2740                                                                                  tcu::Sampler::LINEAR, tcu::Sampler::LINEAR, 0.0f, false /* non-normalized coords */);
2741         tcu::LookupPrecision    lookupPrec;
2742
2743         lookupPrec.colorThreshold       = precision.colorThreshold;
2744         lookupPrec.colorMask            = precision.colorMask;
2745         lookupPrec.coordBits            = tcu::IVec3(22);
2746         lookupPrec.uvwBits                      = precision.filterBits;
2747
2748         for (int y = 0; y < dst.getHeight(); y++)
2749         for (int x = 0; x < dst.getWidth(); x++)
2750         {
2751                 const tcu::Vec4 result  = dst.getPixel(x, y);
2752                 const float             cx              = deFloatFloor(float(x) / dstW * srcW) + 1.0f;
2753                 const float             cy              = deFloatFloor(float(y) / dstH * srcH) + 1.0f;
2754                 const bool              isOk    = tcu::isLinearSampleResultValid(src, sampler, lookupPrec, tcu::Vec2(cx, cy), 0, result);
2755
2756                 errorMask.setPixel(isOk ? tcu::RGBA::green().toVec() : tcu::RGBA::red().toVec(), x, y);
2757                 if (!isOk)
2758                         numFailed += 1;
2759         }
2760
2761         return numFailed;
2762 }
2763
2764 static int compareGenMipmapVeryLenient (const tcu::ConstPixelBufferAccess& dst, const tcu::ConstPixelBufferAccess& src, const tcu::PixelBufferAccess& errorMask, const GenMipmapPrecision& precision)
2765 {
2766         DE_ASSERT(dst.getDepth() == 1 && src.getDepth() == 1); // \todo [2013-10-29 pyry] 3D textures.
2767         DE_UNREF(precision);
2768
2769         const float             dstW            = float(dst.getWidth());
2770         const float             dstH            = float(dst.getHeight());
2771         const float             srcW            = float(src.getWidth());
2772         const float             srcH            = float(src.getHeight());
2773         int                             numFailed       = 0;
2774
2775         for (int y = 0; y < dst.getHeight(); y++)
2776         for (int x = 0; x < dst.getWidth(); x++)
2777         {
2778                 const tcu::Vec4 result  = dst.getPixel(x, y);
2779                 const int               minX            = deFloorFloatToInt32(((float)x-0.5f) / dstW * srcW);
2780                 const int               minY            = deFloorFloatToInt32(((float)y-0.5f) / dstH * srcH);
2781                 const int               maxX            = deCeilFloatToInt32(((float)x+1.5f) / dstW * srcW);
2782                 const int               maxY            = deCeilFloatToInt32(((float)y+1.5f) / dstH * srcH);
2783                 tcu::Vec4               minVal, maxVal;
2784                 bool                    isOk;
2785
2786                 DE_ASSERT(minX < maxX && minY < maxY);
2787
2788                 for (int ky = minY; ky <= maxY; ky++)
2789                 {
2790                         for (int kx = minX; kx <= maxX; kx++)
2791                         {
2792                                 const int               sx              = de::clamp(kx, 0, src.getWidth()-1);
2793                                 const int               sy              = de::clamp(ky, 0, src.getHeight()-1);
2794                                 const tcu::Vec4 sample  = src.getPixel(sx, sy);
2795
2796                                 if (ky == minY && kx == minX)
2797                                 {
2798                                         minVal = sample;
2799                                         maxVal = sample;
2800                                 }
2801                                 else
2802                                 {
2803                                         minVal = min(sample, minVal);
2804                                         maxVal = max(sample, maxVal);
2805                                 }
2806                         }
2807                 }
2808
2809                 isOk = boolAll(logicalAnd(lessThanEqual(minVal, result), lessThanEqual(result, maxVal)));
2810
2811                 errorMask.setPixel(isOk ? tcu::RGBA::green().toVec() : tcu::RGBA::red().toVec(), x, y);
2812                 if (!isOk)
2813                         numFailed += 1;
2814         }
2815
2816         return numFailed;
2817 }
2818
2819 qpTestResult compareGenMipmapResult (tcu::TestLog& log, const tcu::Texture2D& resultTexture, const tcu::Texture2D& level0Reference, const GenMipmapPrecision& precision)
2820 {
2821         qpTestResult result = QP_TEST_RESULT_PASS;
2822
2823         // Special comparison for level 0.
2824         {
2825                 const tcu::Vec4         threshold       = select(precision.colorThreshold, tcu::Vec4(1.0f), precision.colorMask);
2826                 const bool                      level0Ok        = tcu::floatThresholdCompare(log, "Level0", "Level 0", level0Reference.getLevel(0), resultTexture.getLevel(0), threshold, tcu::COMPARE_LOG_RESULT);
2827
2828                 if (!level0Ok)
2829                 {
2830                         log << tcu::TestLog::Message << "ERROR: Level 0 comparison failed!" << tcu::TestLog::EndMessage;
2831                         result = QP_TEST_RESULT_FAIL;
2832                 }
2833         }
2834
2835         for (int levelNdx = 1; levelNdx < resultTexture.getNumLevels(); levelNdx++)
2836         {
2837                 const tcu::ConstPixelBufferAccess       src                     = resultTexture.getLevel(levelNdx-1);
2838                 const tcu::ConstPixelBufferAccess       dst                     = resultTexture.getLevel(levelNdx);
2839                 tcu::Surface                                            errorMask       (dst.getWidth(), dst.getHeight());
2840                 bool                                                            levelOk         = false;
2841
2842                 // Try different comparisons in quality order.
2843
2844                 if (!levelOk)
2845                 {
2846                         const int numFailed = compareGenMipmapBilinear(dst, src, errorMask.getAccess(), precision);
2847                         if (numFailed == 0)
2848                                 levelOk = true;
2849                         else
2850                                 log << tcu::TestLog::Message << "WARNING: Level " << levelNdx << " comparison to bilinear method failed, found " << numFailed << " invalid pixels." << tcu::TestLog::EndMessage;
2851                 }
2852
2853                 if (!levelOk)
2854                 {
2855                         const int numFailed = compareGenMipmapBox(dst, src, errorMask.getAccess(), precision);
2856                         if (numFailed == 0)
2857                                 levelOk = true;
2858                         else
2859                                 log << tcu::TestLog::Message << "WARNING: Level " << levelNdx << " comparison to box method failed, found " << numFailed << " invalid pixels." << tcu::TestLog::EndMessage;
2860                 }
2861
2862                 // At this point all high-quality methods have been used.
2863                 if (!levelOk && result == QP_TEST_RESULT_PASS)
2864                         result = QP_TEST_RESULT_QUALITY_WARNING;
2865
2866                 if (!levelOk)
2867                 {
2868                         const int numFailed = compareGenMipmapVeryLenient(dst, src, errorMask.getAccess(), precision);
2869                         if (numFailed == 0)
2870                                 levelOk = true;
2871                         else
2872                                 log << tcu::TestLog::Message << "ERROR: Level " << levelNdx << " appears to contain " << numFailed << " completely wrong pixels, failing case!" << tcu::TestLog::EndMessage;
2873                 }
2874
2875                 if (!levelOk)
2876                         result = QP_TEST_RESULT_FAIL;
2877
2878                 log << tcu::TestLog::ImageSet(string("Level") + de::toString(levelNdx), string("Level ") + de::toString(levelNdx) + " result")
2879                         << tcu::TestLog::Image("Result", "Result", dst);
2880
2881                 if (!levelOk)
2882                         log << tcu::TestLog::Image("ErrorMask", "Error mask", errorMask);
2883
2884                 log << tcu::TestLog::EndImageSet;
2885         }
2886
2887         return result;
2888 }
2889
2890 qpTestResult compareGenMipmapResult (tcu::TestLog& log, const tcu::TextureCube& resultTexture, const tcu::TextureCube& level0Reference, const GenMipmapPrecision& precision)
2891 {
2892         qpTestResult result = QP_TEST_RESULT_PASS;
2893
2894         static const char* s_faceNames[] = { "-X", "+X", "-Y", "+Y", "-Z", "+Z" };
2895         DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_faceNames) == tcu::CUBEFACE_LAST);
2896
2897         // Special comparison for level 0.
2898         for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; faceNdx++)
2899         {
2900                 const tcu::CubeFace     face            = tcu::CubeFace(faceNdx);
2901                 const tcu::Vec4         threshold       = select(precision.colorThreshold, tcu::Vec4(1.0f), precision.colorMask);
2902                 const bool                      level0Ok        = tcu::floatThresholdCompare(log,
2903                                                                                                                                          ("Level0Face" + de::toString(faceNdx)).c_str(),
2904                                                                                                                                          (string("Level 0, face ") + s_faceNames[face]).c_str(),
2905                                                                                                                                          level0Reference.getLevelFace(0, face),
2906                                                                                                                                          resultTexture.getLevelFace(0, face),
2907                                                                                                                                          threshold, tcu::COMPARE_LOG_RESULT);
2908
2909                 if (!level0Ok)
2910                 {
2911                         log << tcu::TestLog::Message << "ERROR: Level 0, face " << s_faceNames[face] << " comparison failed!" << tcu::TestLog::EndMessage;
2912                         result = QP_TEST_RESULT_FAIL;
2913                 }
2914         }
2915
2916         for (int levelNdx = 1; levelNdx < resultTexture.getNumLevels(); levelNdx++)
2917         {
2918                 for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; faceNdx++)
2919                 {
2920                         const tcu::CubeFace                                     face            = tcu::CubeFace(faceNdx);
2921                         const char*                                                     faceName        = s_faceNames[face];
2922                         const tcu::ConstPixelBufferAccess       src                     = resultTexture.getLevelFace(levelNdx-1,        face);
2923                         const tcu::ConstPixelBufferAccess       dst                     = resultTexture.getLevelFace(levelNdx,          face);
2924                         tcu::Surface                                            errorMask       (dst.getWidth(), dst.getHeight());
2925                         bool                                                            levelOk         = false;
2926
2927                         // Try different comparisons in quality order.
2928
2929                         if (!levelOk)
2930                         {
2931                                 const int numFailed = compareGenMipmapBilinear(dst, src, errorMask.getAccess(), precision);
2932                                 if (numFailed == 0)
2933                                         levelOk = true;
2934                                 else
2935                                         log << tcu::TestLog::Message << "WARNING: Level " << levelNdx << ", face " << faceName << " comparison to bilinear method failed, found " << numFailed << " invalid pixels." << tcu::TestLog::EndMessage;
2936                         }
2937
2938                         if (!levelOk)
2939                         {
2940                                 const int numFailed = compareGenMipmapBox(dst, src, errorMask.getAccess(), precision);
2941                                 if (numFailed == 0)
2942                                         levelOk = true;
2943                                 else
2944                                         log << tcu::TestLog::Message << "WARNING: Level " << levelNdx << ", face " << faceName <<" comparison to box method failed, found " << numFailed << " invalid pixels." << tcu::TestLog::EndMessage;
2945                         }
2946
2947                         // At this point all high-quality methods have been used.
2948                         if (!levelOk && result == QP_TEST_RESULT_PASS)
2949                                 result = QP_TEST_RESULT_QUALITY_WARNING;
2950
2951                         if (!levelOk)
2952                         {
2953                                 const int numFailed = compareGenMipmapVeryLenient(dst, src, errorMask.getAccess(), precision);
2954                                 if (numFailed == 0)
2955                                         levelOk = true;
2956                                 else
2957                                         log << tcu::TestLog::Message << "ERROR: Level " << levelNdx << ", face " << faceName << " appears to contain " << numFailed << " completely wrong pixels, failing case!" << tcu::TestLog::EndMessage;
2958                         }
2959
2960                         if (!levelOk)
2961                                 result = QP_TEST_RESULT_FAIL;
2962
2963                         log << tcu::TestLog::ImageSet(string("Level") + de::toString(levelNdx) + "Face" + de::toString(faceNdx), string("Level ") + de::toString(levelNdx) + ", face " + string(faceName) + " result")
2964                                 << tcu::TestLog::Image("Result", "Result", dst);
2965
2966                         if (!levelOk)
2967                                 log << tcu::TestLog::Image("ErrorMask", "Error mask", errorMask);
2968
2969                         log << tcu::TestLog::EndImageSet;
2970                 }
2971         }
2972
2973         return result;
2974 }
2975
2976 // Logging utilities.
2977
2978 std::ostream& operator<< (std::ostream& str, const LogGradientFmt& fmt)
2979 {
2980         return str << "(R: " << fmt.valueMin->x() << " -> " << fmt.valueMax->x() << ", "
2981                            <<  "G: " << fmt.valueMin->y() << " -> " << fmt.valueMax->y() << ", "
2982                            <<  "B: " << fmt.valueMin->z() << " -> " << fmt.valueMax->z() << ", "
2983                            <<  "A: " << fmt.valueMin->w() << " -> " << fmt.valueMax->w() << ")";
2984 }
2985
2986 } // TextureTestUtil
2987 } // glu