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