Relax uvwBits to 3 in dEQP-GLES2.functional.texture.filtering.cube am: f1c8ff1f20
[platform/upstream/VK-GL-CTS.git] / framework / common / tcuTexCompareVerifier.cpp
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program Tester Core
3  * ----------------------------------------
4  *
5  * Copyright 2014 The Android Open Source Project
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Texture compare (shadow) result verifier.
22  *//*--------------------------------------------------------------------*/
23
24 #include "tcuTexCompareVerifier.hpp"
25 #include "tcuTexVerifierUtil.hpp"
26 #include "tcuTextureUtil.hpp"
27 #include "tcuVectorUtil.hpp"
28 #include "deMath.h"
29
30 namespace tcu
31 {
32
33 using namespace TexVerifierUtil;
34
35 // Generic utilities
36
37 #if defined(DE_DEBUG)
38 static bool isSamplerSupported (const Sampler& sampler)
39 {
40         return sampler.compare != Sampler::COMPAREMODE_NONE &&
41                    isWrapModeSupported(sampler.wrapS)                   &&
42                    isWrapModeSupported(sampler.wrapT)                   &&
43                    isWrapModeSupported(sampler.wrapR);
44 }
45 #endif // DE_DEBUG
46
47 struct CmpResultSet
48 {
49         bool    isTrue;
50         bool    isFalse;
51
52         CmpResultSet (void)
53                 : isTrue        (false)
54                 , isFalse       (false)
55         {
56         }
57 };
58
59 static CmpResultSet execCompare (const Sampler::CompareMode     compareMode,
60                                                                  const float                            cmpValue_,
61                                                                  const float                            cmpReference_,
62                                                                  const int                                      referenceBits,
63                                                                  const bool                                     isFixedPoint)
64 {
65         const bool              clampValues             = isFixedPoint; // if comparing against a floating point texture, ref (and value) is not clamped
66         const float             cmpValue                = (clampValues) ? (de::clamp(cmpValue_, 0.0f, 1.0f)) : (cmpValue_);
67         const float             cmpReference    = (clampValues) ? (de::clamp(cmpReference_, 0.0f, 1.0f)) : (cmpReference_);
68         const float             err                             = computeFixedPointError(referenceBits);
69         CmpResultSet    res;
70
71         switch (compareMode)
72         {
73                 case Sampler::COMPAREMODE_LESS:
74                         res.isTrue      = cmpReference-err < cmpValue;
75                         res.isFalse     = cmpReference+err >= cmpValue;
76                         break;
77
78                 case Sampler::COMPAREMODE_LESS_OR_EQUAL:
79                         res.isTrue      = cmpReference-err <= cmpValue;
80                         res.isFalse     = cmpReference+err > cmpValue;
81                         break;
82
83                 case Sampler::COMPAREMODE_GREATER:
84                         res.isTrue      = cmpReference+err > cmpValue;
85                         res.isFalse     = cmpReference-err <= cmpValue;
86                         break;
87
88                 case Sampler::COMPAREMODE_GREATER_OR_EQUAL:
89                         res.isTrue      = cmpReference+err >= cmpValue;
90                         res.isFalse     = cmpReference-err < cmpValue;
91                         break;
92
93                 case Sampler::COMPAREMODE_EQUAL:
94                         res.isTrue      = de::inRange(cmpValue, cmpReference-err, cmpReference+err);
95                         res.isFalse     = err != 0.0f || cmpValue != cmpReference;
96                         break;
97
98                 case Sampler::COMPAREMODE_NOT_EQUAL:
99                         res.isTrue      = err != 0.0f || cmpValue != cmpReference;
100                         res.isFalse     = de::inRange(cmpValue, cmpReference-err, cmpReference+err);
101                         break;
102
103                 case Sampler::COMPAREMODE_ALWAYS:
104                         res.isTrue      = true;
105                         break;
106
107                 case Sampler::COMPAREMODE_NEVER:
108                         res.isFalse     = true;
109                         break;
110
111                 default:
112                         DE_ASSERT(false);
113         }
114
115         DE_ASSERT(res.isTrue || res.isFalse);
116         return res;
117 }
118
119 static inline bool isResultInSet (const CmpResultSet resultSet, const float result, const int resultBits)
120 {
121         const float err         = computeFixedPointError(resultBits);
122         const float     minR    = result-err;
123         const float     maxR    = result+err;
124
125         return (resultSet.isTrue        && de::inRange(1.0f, minR, maxR)) ||
126                    (resultSet.isFalse   && de::inRange(0.0f, minR, maxR));
127 }
128
129 static inline bool coordsInBounds (const ConstPixelBufferAccess& access, int x, int y, int z)
130 {
131         return de::inBounds(x, 0, access.getWidth()) && de::inBounds(y, 0, access.getHeight()) && de::inBounds(z, 0, access.getDepth());
132 }
133
134 static float lookupDepth (const tcu::ConstPixelBufferAccess& access, const Sampler& sampler, int i, int j, int k)
135 {
136         if (coordsInBounds(access, i, j, k))
137                 return access.getPixDepth(i, j, k);
138         else
139                 return sampleTextureBorder<float>(access.getFormat(), sampler).x();
140 }
141
142 // lookup depth value at a point that is guaranteed to not sample border such as cube map faces.
143 static float lookupDepthNoBorder (const tcu::ConstPixelBufferAccess& access, const Sampler& sampler, int i, int j, int k = 0)
144 {
145         DE_UNREF(sampler);
146         DE_ASSERT(coordsInBounds(access, i, j, k));
147         return access.getPixDepth(i, j, k);
148 }
149
150 // Values are in order (0,0), (1,0), (0,1), (1,1)
151 static float bilinearInterpolate (const Vec4& values, const float x, const float y)
152 {
153         const float             v00             = values[0];
154         const float             v10             = values[1];
155         const float             v01             = values[2];
156         const float             v11             = values[3];
157         const float             res             = v00*(1.0f-x)*(1.0f-y) + v10*x*(1.0f-y) + v01*(1.0f-x)*y + v11*x*y;
158         return res;
159 }
160
161 static bool isFixedPointDepthTextureFormat (const tcu::TextureFormat& format)
162 {
163         const tcu::TextureChannelClass channelClass = tcu::getTextureChannelClass(format.type);
164
165         if (format.order == TextureFormat::D)
166         {
167                 // depth internal formats cannot be non-normalized integers
168                 return channelClass != tcu::TEXTURECHANNELCLASS_FLOATING_POINT;
169         }
170         else if (format.order == TextureFormat::DS)
171         {
172                 // combined formats have no single channel class, detect format manually
173                 switch (format.type)
174                 {
175                         case tcu::TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV:   return false;
176                         case tcu::TextureFormat::UNSIGNED_INT_16_8_8:                   return true;
177                         case tcu::TextureFormat::UNSIGNED_INT_24_8:                             return true;
178                         case tcu::TextureFormat::UNSIGNED_INT_24_8_REV:                 return true;
179
180                         default:
181                         {
182                                 // unknown format
183                                 DE_ASSERT(false);
184                                 return true;
185                         }
186                 }
187         }
188
189         return false;
190 }
191
192 static bool isLinearCompareValid (const Sampler::CompareMode    compareMode,
193                                                                   const TexComparePrecision&    prec,
194                                                                   const Vec2&                                   depths,
195                                                                   const Vec2&                                   fBounds,
196                                                                   const float                                   cmpReference,
197                                                                   const float                                   result,
198                                                                   const bool                                    isFixedPointDepth)
199 {
200         DE_ASSERT(0.0f <= fBounds.x() && fBounds.x() <= fBounds.y() && fBounds.y() <= 1.0f);
201
202         const float                     d0                      = depths[0];
203         const float                     d1                      = depths[1];
204
205         const CmpResultSet      cmp0            = execCompare(compareMode, d0, cmpReference, prec.referenceBits, isFixedPointDepth);
206         const CmpResultSet      cmp1            = execCompare(compareMode, d1, cmpReference, prec.referenceBits, isFixedPointDepth);
207
208         const deUint32          isTrue          = (deUint32(cmp0.isTrue)<<0)
209                                                                         | (deUint32(cmp1.isTrue)<<1);
210         const deUint32          isFalse         = (deUint32(cmp0.isFalse)<<0)
211                                                                         | (deUint32(cmp1.isFalse)<<1);
212
213         // Interpolation parameters
214         const float                     f0                      = fBounds.x();
215         const float                     f1                      = fBounds.y();
216
217         // Error parameters
218         const float                     pcfErr          = computeFixedPointError(prec.pcfBits);
219         const float                     resErr          = computeFixedPointError(prec.resultBits);
220         const float                     totalErr        = pcfErr+resErr;
221
222         // Iterate over all valid combinations.
223         for (deUint32 comb = 0; comb < (1<<2); comb++)
224         {
225                 // Filter out invalid combinations.
226                 if (((comb & isTrue) | (~comb & isFalse)) != (1<<2)-1)
227                         continue;
228
229                 const bool              cmp0True        = ((comb>>0)&1) != 0;
230                 const bool              cmp1True        = ((comb>>1)&1) != 0;
231
232                 const float             ref0            = cmp0True ? 1.0f : 0.0f;
233                 const float             ref1            = cmp1True ? 1.0f : 0.0f;
234
235                 const float             v0                      = ref0*(1.0f-f0) + ref1*f0;
236                 const float             v1                      = ref0*(1.0f-f1) + ref1*f1;
237                 const float             minV            = de::min(v0, v1);
238                 const float             maxV            = de::max(v0, v1);
239                 const float             minR            = minV-totalErr;
240                 const float             maxR            = maxV+totalErr;
241
242                 if (de::inRange(result, minR, maxR))
243                         return true;
244         }
245
246         return false;
247 }
248
249 static inline BVec4 extractBVec4 (const deUint32 val, int offset)
250 {
251         return BVec4(((val>>(offset+0))&1) != 0,
252                                  ((val>>(offset+1))&1) != 0,
253                                  ((val>>(offset+2))&1) != 0,
254                                  ((val>>(offset+3))&1) != 0);
255 }
256
257 static bool isBilinearAnyCompareValid (const Sampler::CompareMode       compareMode,
258                                                                            const TexComparePrecision&   prec,
259                                                                            const Vec4&                                  depths,
260                                                                            const float                                  cmpReference,
261                                                                            const float                                  result,
262                                                                            const bool                                   isFixedPointDepth)
263 {
264         DE_ASSERT(prec.pcfBits == 0);
265
266         const float                     d0                      = depths[0];
267         const float                     d1                      = depths[1];
268         const float                     d2                      = depths[2];
269         const float                     d3                      = depths[3];
270
271         const CmpResultSet      cmp0            = execCompare(compareMode, d0, cmpReference, prec.referenceBits, isFixedPointDepth);
272         const CmpResultSet      cmp1            = execCompare(compareMode, d1, cmpReference, prec.referenceBits, isFixedPointDepth);
273         const CmpResultSet      cmp2            = execCompare(compareMode, d2, cmpReference, prec.referenceBits, isFixedPointDepth);
274         const CmpResultSet      cmp3            = execCompare(compareMode, d3, cmpReference, prec.referenceBits, isFixedPointDepth);
275
276         const bool                      canBeTrue       = cmp0.isTrue || cmp1.isTrue || cmp2.isTrue || cmp3.isTrue;
277         const bool                      canBeFalse      = cmp0.isFalse || cmp1.isFalse || cmp2.isFalse || cmp3.isFalse;
278
279         const float                     resErr          = computeFixedPointError(prec.resultBits);
280
281         const float                     minBound        = canBeFalse ? 0.0f : 1.0f;
282         const float                     maxBound        = canBeTrue ? 1.0f : 0.0f;
283
284         return de::inRange(result, minBound-resErr, maxBound+resErr);
285 }
286
287 static bool isBilinearPCFCompareValid (const Sampler::CompareMode       compareMode,
288                                                                            const TexComparePrecision&   prec,
289                                                                            const Vec4&                                  depths,
290                                                                            const Vec2&                                  xBounds,
291                                                                            const Vec2&                                  yBounds,
292                                                                            const float                                  cmpReference,
293                                                                            const float                                  result,
294                                                                            const bool                                   isFixedPointDepth)
295 {
296         DE_ASSERT(0.0f <= xBounds.x() && xBounds.x() <= xBounds.y() && xBounds.y() <= 1.0f);
297         DE_ASSERT(0.0f <= yBounds.x() && yBounds.x() <= yBounds.y() && yBounds.y() <= 1.0f);
298         DE_ASSERT(prec.pcfBits > 0);
299
300         const float                     d0                      = depths[0];
301         const float                     d1                      = depths[1];
302         const float                     d2                      = depths[2];
303         const float                     d3                      = depths[3];
304
305         const CmpResultSet      cmp0            = execCompare(compareMode, d0, cmpReference, prec.referenceBits, isFixedPointDepth);
306         const CmpResultSet      cmp1            = execCompare(compareMode, d1, cmpReference, prec.referenceBits, isFixedPointDepth);
307         const CmpResultSet      cmp2            = execCompare(compareMode, d2, cmpReference, prec.referenceBits, isFixedPointDepth);
308         const CmpResultSet      cmp3            = execCompare(compareMode, d3, cmpReference, prec.referenceBits, isFixedPointDepth);
309
310         const deUint32          isTrue          = (deUint32(cmp0.isTrue)<<0)
311                                                                         | (deUint32(cmp1.isTrue)<<1)
312                                                                         | (deUint32(cmp2.isTrue)<<2)
313                                                                         | (deUint32(cmp3.isTrue)<<3);
314         const deUint32          isFalse         = (deUint32(cmp0.isFalse)<<0)
315                                                                         | (deUint32(cmp1.isFalse)<<1)
316                                                                         | (deUint32(cmp2.isFalse)<<2)
317                                                                         | (deUint32(cmp3.isFalse)<<3);
318
319         // Interpolation parameters
320         const float                     x0                      = xBounds.x();
321         const float                     x1                      = xBounds.y();
322         const float                     y0                      = yBounds.x();
323         const float                     y1                      = yBounds.y();
324
325         // Error parameters
326         const float                     pcfErr          = computeFixedPointError(prec.pcfBits);
327         const float                     resErr          = computeFixedPointError(prec.resultBits);
328         const float                     totalErr        = pcfErr+resErr;
329
330         // Iterate over all valid combinations.
331         // \note It is not enough to compute minmax over all possible result sets, as ranges may
332         //               not necessarily overlap, i.e. there are gaps between valid ranges.
333         for (deUint32 comb = 0; comb < (1<<4); comb++)
334         {
335                 // Filter out invalid combinations:
336                 //  1) True bit is set in comb but not in isTrue => sample can not be true
337                 //  2) True bit is NOT set in comb and not in isFalse => sample can not be false
338                 if (((comb & isTrue) | (~comb & isFalse)) != (1<<4)-1)
339                         continue;
340
341                 const BVec4             cmpTrue         = extractBVec4(comb, 0);
342                 const Vec4              refVal          = select(Vec4(1.0f), Vec4(0.0f), cmpTrue);
343
344                 const float             v0                      = bilinearInterpolate(refVal, x0, y0);
345                 const float             v1                      = bilinearInterpolate(refVal, x1, y0);
346                 const float             v2                      = bilinearInterpolate(refVal, x0, y1);
347                 const float             v3                      = bilinearInterpolate(refVal, x1, y1);
348                 const float             minV            = de::min(v0, de::min(v1, de::min(v2, v3)));
349                 const float             maxV            = de::max(v0, de::max(v1, de::max(v2, v3)));
350                 const float             minR            = minV-totalErr;
351                 const float             maxR            = maxV+totalErr;
352
353                 if (de::inRange(result, minR, maxR))
354                         return true;
355         }
356
357         return false;
358 }
359
360 static bool isBilinearCompareValid (const Sampler::CompareMode  compareMode,
361                                                                         const TexComparePrecision&      prec,
362                                                                         const Vec4&                                     depths,
363                                                                         const Vec2&                                     xBounds,
364                                                                         const Vec2&                                     yBounds,
365                                                                         const float                                     cmpReference,
366                                                                         const float                                     result,
367                                                                         const bool                                      isFixedPointDepth)
368 {
369         if (prec.pcfBits > 0)
370                 return isBilinearPCFCompareValid(compareMode, prec, depths, xBounds, yBounds, cmpReference, result, isFixedPointDepth);
371         else
372                 return isBilinearAnyCompareValid(compareMode, prec, depths, cmpReference, result, isFixedPointDepth);
373 }
374
375 static bool isTrilinearAnyCompareValid (const Sampler::CompareMode      compareMode,
376                                                                                 const TexComparePrecision&      prec,
377                                                                                 const Vec4&                                     depths0,
378                                                                                 const Vec4&                                     depths1,
379                                                                                 const float                                     cmpReference,
380                                                                                 const float                                     result,
381                                                                                 const bool                                      isFixedPointDepth)
382 {
383         DE_ASSERT(prec.pcfBits == 0);
384
385         const CmpResultSet      cmp00           = execCompare(compareMode, depths0[0], cmpReference, prec.referenceBits, isFixedPointDepth);
386         const CmpResultSet      cmp01           = execCompare(compareMode, depths0[1], cmpReference, prec.referenceBits, isFixedPointDepth);
387         const CmpResultSet      cmp02           = execCompare(compareMode, depths0[2], cmpReference, prec.referenceBits, isFixedPointDepth);
388         const CmpResultSet      cmp03           = execCompare(compareMode, depths0[3], cmpReference, prec.referenceBits, isFixedPointDepth);
389
390         const CmpResultSet      cmp10           = execCompare(compareMode, depths1[0], cmpReference, prec.referenceBits, isFixedPointDepth);
391         const CmpResultSet      cmp11           = execCompare(compareMode, depths1[1], cmpReference, prec.referenceBits, isFixedPointDepth);
392         const CmpResultSet      cmp12           = execCompare(compareMode, depths1[2], cmpReference, prec.referenceBits, isFixedPointDepth);
393         const CmpResultSet      cmp13           = execCompare(compareMode, depths1[3], cmpReference, prec.referenceBits, isFixedPointDepth);
394
395         const bool                      canBeTrue       = cmp00.isTrue ||
396                                                                           cmp01.isTrue ||
397                                                                           cmp02.isTrue ||
398                                                                           cmp03.isTrue ||
399                                                                           cmp10.isTrue ||
400                                                                           cmp11.isTrue ||
401                                                                           cmp12.isTrue ||
402                                                                           cmp13.isTrue;
403         const bool                      canBeFalse      = cmp00.isFalse ||
404                                                                           cmp01.isFalse ||
405                                                                           cmp02.isFalse ||
406                                                                           cmp03.isFalse ||
407                                                                           cmp10.isFalse ||
408                                                                           cmp11.isFalse ||
409                                                                           cmp12.isFalse ||
410                                                                           cmp13.isFalse;
411
412         const float                     resErr          = computeFixedPointError(prec.resultBits);
413
414         const float                     minBound        = canBeFalse ? 0.0f : 1.0f;
415         const float                     maxBound        = canBeTrue ? 1.0f : 0.0f;
416
417         return de::inRange(result, minBound-resErr, maxBound+resErr);
418 }
419
420 static bool isTrilinearPCFCompareValid (const Sampler::CompareMode      compareMode,
421                                                                                 const TexComparePrecision&      prec,
422                                                                                 const Vec4&                                     depths0,
423                                                                                 const Vec4&                                     depths1,
424                                                                                 const Vec2&                                     xBounds0,
425                                                                                 const Vec2&                                     yBounds0,
426                                                                                 const Vec2&                                     xBounds1,
427                                                                                 const Vec2&                                     yBounds1,
428                                                                                 const Vec2&                                     fBounds,
429                                                                                 const float                                     cmpReference,
430                                                                                 const float                                     result,
431                                                                                 const bool                                      isFixedPointDepth)
432 {
433         DE_ASSERT(0.0f <= xBounds0.x() && xBounds0.x() <= xBounds0.y() && xBounds0.y() <= 1.0f);
434         DE_ASSERT(0.0f <= yBounds0.x() && yBounds0.x() <= yBounds0.y() && yBounds0.y() <= 1.0f);
435         DE_ASSERT(0.0f <= xBounds1.x() && xBounds1.x() <= xBounds1.y() && xBounds1.y() <= 1.0f);
436         DE_ASSERT(0.0f <= yBounds1.x() && yBounds1.x() <= yBounds1.y() && yBounds1.y() <= 1.0f);
437         DE_ASSERT(0.0f <= fBounds.x() && fBounds.x() <= fBounds.y() && fBounds.y() <= 1.0f);
438         DE_ASSERT(prec.pcfBits > 0);
439
440         const CmpResultSet      cmp00           = execCompare(compareMode, depths0[0], cmpReference, prec.referenceBits, isFixedPointDepth);
441         const CmpResultSet      cmp01           = execCompare(compareMode, depths0[1], cmpReference, prec.referenceBits, isFixedPointDepth);
442         const CmpResultSet      cmp02           = execCompare(compareMode, depths0[2], cmpReference, prec.referenceBits, isFixedPointDepth);
443         const CmpResultSet      cmp03           = execCompare(compareMode, depths0[3], cmpReference, prec.referenceBits, isFixedPointDepth);
444
445         const CmpResultSet      cmp10           = execCompare(compareMode, depths1[0], cmpReference, prec.referenceBits, isFixedPointDepth);
446         const CmpResultSet      cmp11           = execCompare(compareMode, depths1[1], cmpReference, prec.referenceBits, isFixedPointDepth);
447         const CmpResultSet      cmp12           = execCompare(compareMode, depths1[2], cmpReference, prec.referenceBits, isFixedPointDepth);
448         const CmpResultSet      cmp13           = execCompare(compareMode, depths1[3], cmpReference, prec.referenceBits, isFixedPointDepth);
449
450         const deUint32          isTrue          = (deUint32(cmp00.isTrue)<<0)
451                                                                         | (deUint32(cmp01.isTrue)<<1)
452                                                                         | (deUint32(cmp02.isTrue)<<2)
453                                                                         | (deUint32(cmp03.isTrue)<<3)
454                                                                         | (deUint32(cmp10.isTrue)<<4)
455                                                                         | (deUint32(cmp11.isTrue)<<5)
456                                                                         | (deUint32(cmp12.isTrue)<<6)
457                                                                         | (deUint32(cmp13.isTrue)<<7);
458         const deUint32          isFalse         = (deUint32(cmp00.isFalse)<<0)
459                                                                         | (deUint32(cmp01.isFalse)<<1)
460                                                                         | (deUint32(cmp02.isFalse)<<2)
461                                                                         | (deUint32(cmp03.isFalse)<<3)
462                                                                         | (deUint32(cmp10.isFalse)<<4)
463                                                                         | (deUint32(cmp11.isFalse)<<5)
464                                                                         | (deUint32(cmp12.isFalse)<<6)
465                                                                         | (deUint32(cmp13.isFalse)<<7);
466
467         // Error parameters
468         const float                     pcfErr          = computeFixedPointError(prec.pcfBits);
469         const float                     resErr          = computeFixedPointError(prec.resultBits);
470         const float                     totalErr        = pcfErr+resErr;
471
472         // Iterate over all valid combinations.
473         for (deUint32 comb = 0; comb < (1<<8); comb++)
474         {
475                 // Filter out invalid combinations.
476                 if (((comb & isTrue) | (~comb & isFalse)) != (1<<8)-1)
477                         continue;
478
479                 const BVec4             cmpTrue0        = extractBVec4(comb, 0);
480                 const BVec4             cmpTrue1        = extractBVec4(comb, 4);
481                 const Vec4              refVal0         = select(Vec4(1.0f), Vec4(0.0f), cmpTrue0);
482                 const Vec4              refVal1         = select(Vec4(1.0f), Vec4(0.0f), cmpTrue1);
483
484                 // Bilinear interpolation within levels.
485                 const float             v00                     = bilinearInterpolate(refVal0, xBounds0.x(), yBounds0.x());
486                 const float             v01                     = bilinearInterpolate(refVal0, xBounds0.y(), yBounds0.x());
487                 const float             v02                     = bilinearInterpolate(refVal0, xBounds0.x(), yBounds0.y());
488                 const float             v03                     = bilinearInterpolate(refVal0, xBounds0.y(), yBounds0.y());
489                 const float             minV0           = de::min(v00, de::min(v01, de::min(v02, v03)));
490                 const float             maxV0           = de::max(v00, de::max(v01, de::max(v02, v03)));
491
492                 const float             v10                     = bilinearInterpolate(refVal1, xBounds1.x(), yBounds1.x());
493                 const float             v11                     = bilinearInterpolate(refVal1, xBounds1.y(), yBounds1.x());
494                 const float             v12                     = bilinearInterpolate(refVal1, xBounds1.x(), yBounds1.y());
495                 const float             v13                     = bilinearInterpolate(refVal1, xBounds1.y(), yBounds1.y());
496                 const float             minV1           = de::min(v10, de::min(v11, de::min(v12, v13)));
497                 const float             maxV1           = de::max(v10, de::max(v11, de::max(v12, v13)));
498
499                 // Compute min-max bounds by filtering between minimum bounds and maximum bounds between levels.
500                 // HW can end up choosing pretty much any of samples between levels, and thus interpolating
501                 // between minimums should yield lower bound for range, and same for upper bound.
502                 // \todo [2013-07-17 pyry] This seems separable? Can this be optimized? At least ranges could be pre-computed and later combined.
503                 const float             minF0           = minV0*(1.0f-fBounds.x()) + minV1*fBounds.x();
504                 const float             minF1           = minV0*(1.0f-fBounds.y()) + minV1*fBounds.y();
505                 const float             maxF0           = maxV0*(1.0f-fBounds.x()) + maxV1*fBounds.x();
506                 const float             maxF1           = maxV0*(1.0f-fBounds.y()) + maxV1*fBounds.y();
507
508                 const float             minF            = de::min(minF0, minF1);
509                 const float             maxF            = de::max(maxF0, maxF1);
510
511                 const float             minR            = minF-totalErr;
512                 const float             maxR            = maxF+totalErr;
513
514                 if (de::inRange(result, minR, maxR))
515                         return true;
516         }
517
518         return false;
519 }
520
521 static bool isTrilinearCompareValid (const Sampler::CompareMode compareMode,
522                                                                          const TexComparePrecision&     prec,
523                                                                          const Vec4&                            depths0,
524                                                                          const Vec4&                            depths1,
525                                                                          const Vec2&                            xBounds0,
526                                                                          const Vec2&                            yBounds0,
527                                                                          const Vec2&                            xBounds1,
528                                                                          const Vec2&                            yBounds1,
529                                                                          const Vec2&                            fBounds,
530                                                                          const float                            cmpReference,
531                                                                          const float                            result,
532                                                                          const bool                                     isFixedPointDepth)
533 {
534         if (prec.pcfBits > 0)
535                 return isTrilinearPCFCompareValid(compareMode, prec, depths0, depths1, xBounds0, yBounds0, xBounds1, yBounds1, fBounds, cmpReference, result, isFixedPointDepth);
536         else
537                 return isTrilinearAnyCompareValid(compareMode, prec, depths0, depths1, cmpReference, result, isFixedPointDepth);
538 }
539
540 static bool isNearestCompareResultValid (const ConstPixelBufferAccess&          level,
541                                                                                  const Sampler&                                         sampler,
542                                                                                  const TexComparePrecision&                     prec,
543                                                                                  const Vec2&                                            coord,
544                                                                                  const int                                                      coordZ,
545                                                                                  const float                                            cmpReference,
546                                                                                  const float                                            result)
547 {
548         const bool      isFixedPointDepth       = isFixedPointDepthTextureFormat(level.getFormat());
549         const Vec2      uBounds                         = computeNonNormalizedCoordBounds(sampler.normalizedCoords, level.getWidth(),   coord.x(), prec.coordBits.x(), prec.uvwBits.x());
550         const Vec2      vBounds                         = computeNonNormalizedCoordBounds(sampler.normalizedCoords, level.getHeight(),  coord.y(), prec.coordBits.y(), prec.uvwBits.y());
551
552         // Integer coordinates - without wrap mode
553         const int       minI            = deFloorFloatToInt32(uBounds.x());
554         const int       maxI            = deFloorFloatToInt32(uBounds.y());
555         const int       minJ            = deFloorFloatToInt32(vBounds.x());
556         const int       maxJ            = deFloorFloatToInt32(vBounds.y());
557
558         for (int j = minJ; j <= maxJ; j++)
559         {
560                 for (int i = minI; i <= maxI; i++)
561                 {
562                         const int                       x               = wrap(sampler.wrapS, i, level.getWidth());
563                         const int                       y               = wrap(sampler.wrapT, j, level.getHeight());
564                         const float                     depth   = lookupDepth(level, sampler, x, y, coordZ);
565                         const CmpResultSet      resSet  = execCompare(sampler.compare, depth, cmpReference, prec.referenceBits, isFixedPointDepth);
566
567                         if (isResultInSet(resSet, result, prec.resultBits))
568                                 return true;
569                 }
570         }
571
572         return false;
573 }
574
575 static bool isLinearCompareResultValid (const ConstPixelBufferAccess&           level,
576                                                                                 const Sampler&                                          sampler,
577                                                                                 const TexComparePrecision&                      prec,
578                                                                                 const Vec2&                                                     coord,
579                                                                                 const int                                                       coordZ,
580                                                                                 const float                                                     cmpReference,
581                                                                                 const float                                                     result)
582 {
583         const bool      isFixedPointDepth       = isFixedPointDepthTextureFormat(level.getFormat());
584         const Vec2      uBounds                         = computeNonNormalizedCoordBounds(sampler.normalizedCoords, level.getWidth(),   coord.x(), prec.coordBits.x(), prec.uvwBits.x());
585         const Vec2      vBounds                         = computeNonNormalizedCoordBounds(sampler.normalizedCoords, level.getHeight(),  coord.y(), prec.coordBits.y(), prec.uvwBits.y());
586
587         // Integer coordinate bounds for (x0,y0) - without wrap mode
588         const int       minI            = deFloorFloatToInt32(uBounds.x()-0.5f);
589         const int       maxI            = deFloorFloatToInt32(uBounds.y()-0.5f);
590         const int       minJ            = deFloorFloatToInt32(vBounds.x()-0.5f);
591         const int       maxJ            = deFloorFloatToInt32(vBounds.y()-0.5f);
592
593         const int       w                       = level.getWidth();
594         const int       h                       = level.getHeight();
595
596         // \todo [2013-07-03 pyry] This could be optimized by first computing ranges based on wrap mode.
597
598         for (int j = minJ; j <= maxJ; j++)
599         {
600                 for (int i = minI; i <= maxI; i++)
601                 {
602                         // Wrapped coordinates
603                         const int       x0              = wrap(sampler.wrapS, i  , w);
604                         const int       x1              = wrap(sampler.wrapS, i+1, w);
605                         const int       y0              = wrap(sampler.wrapT, j  , h);
606                         const int       y1              = wrap(sampler.wrapT, j+1, h);
607
608                         // Bounds for filtering factors
609                         const float     minA    = de::clamp((uBounds.x()-0.5f)-float(i), 0.0f, 1.0f);
610                         const float     maxA    = de::clamp((uBounds.y()-0.5f)-float(i), 0.0f, 1.0f);
611                         const float     minB    = de::clamp((vBounds.x()-0.5f)-float(j), 0.0f, 1.0f);
612                         const float     maxB    = de::clamp((vBounds.y()-0.5f)-float(j), 0.0f, 1.0f);
613
614                         const Vec4      depths  (lookupDepth(level, sampler, x0, y0, coordZ),
615                                                                  lookupDepth(level, sampler, x1, y0, coordZ),
616                                                                  lookupDepth(level, sampler, x0, y1, coordZ),
617                                                                  lookupDepth(level, sampler, x1, y1, coordZ));
618
619                         if (isBilinearCompareValid(sampler.compare, prec, depths, Vec2(minA, maxA), Vec2(minB, maxB), cmpReference, result, isFixedPointDepth))
620                                 return true;
621                 }
622         }
623
624         return false;
625 }
626
627 static bool isLevelCompareResultValid (const ConstPixelBufferAccess&    level,
628                                                                            const Sampler&                                       sampler,
629                                                                            const Sampler::FilterMode            filterMode,
630                                                                            const TexComparePrecision&           prec,
631                                                                            const Vec2&                                          coord,
632                                                                            const int                                            coordZ,
633                                                                            const float                                          cmpReference,
634                                                                            const float                                          result)
635 {
636         if (filterMode == Sampler::LINEAR)
637                 return isLinearCompareResultValid(level, sampler, prec, coord, coordZ, cmpReference, result);
638         else
639                 return isNearestCompareResultValid(level, sampler, prec, coord, coordZ, cmpReference, result);
640 }
641
642 static bool isNearestMipmapLinearCompareResultValid (const ConstPixelBufferAccess&      level0,
643                                                                                                          const ConstPixelBufferAccess&  level1,
644                                                                                                          const Sampler&                                 sampler,
645                                                                                                          const TexComparePrecision&             prec,
646                                                                                                          const Vec2&                                    coord,
647                                                                                                          const int                                              coordZ,
648                                                                                                          const Vec2&                                    fBounds,
649                                                                                                          const float                                    cmpReference,
650                                                                                                          const float                                    result)
651 {
652         const bool      isFixedPointDepth       = isFixedPointDepthTextureFormat(level0.getFormat());
653
654         const int       w0                                      = level0.getWidth();
655         const int       w1                                      = level1.getWidth();
656         const int       h0                                      = level0.getHeight();
657         const int       h1                                      = level1.getHeight();
658
659         const Vec2      uBounds0                        = computeNonNormalizedCoordBounds(sampler.normalizedCoords, w0, coord.x(), prec.coordBits.x(), prec.uvwBits.x());
660         const Vec2      uBounds1                        = computeNonNormalizedCoordBounds(sampler.normalizedCoords, w1, coord.x(), prec.coordBits.x(), prec.uvwBits.x());
661         const Vec2      vBounds0                        = computeNonNormalizedCoordBounds(sampler.normalizedCoords, h0, coord.y(), prec.coordBits.y(), prec.uvwBits.y());
662         const Vec2      vBounds1                        = computeNonNormalizedCoordBounds(sampler.normalizedCoords, h1, coord.y(), prec.coordBits.y(), prec.uvwBits.y());
663
664         // Integer coordinates - without wrap mode
665         const int       minI0                           = deFloorFloatToInt32(uBounds0.x());
666         const int       maxI0                           = deFloorFloatToInt32(uBounds0.y());
667         const int       minI1                           = deFloorFloatToInt32(uBounds1.x());
668         const int       maxI1                           = deFloorFloatToInt32(uBounds1.y());
669         const int       minJ0                           = deFloorFloatToInt32(vBounds0.x());
670         const int       maxJ0                           = deFloorFloatToInt32(vBounds0.y());
671         const int       minJ1                           = deFloorFloatToInt32(vBounds1.x());
672         const int       maxJ1                           = deFloorFloatToInt32(vBounds1.y());
673
674         for (int j0 = minJ0; j0 <= maxJ0; j0++)
675         {
676                 for (int i0 = minI0; i0 <= maxI0; i0++)
677                 {
678                         const float     depth0  = lookupDepth(level0, sampler, wrap(sampler.wrapS, i0, w0), wrap(sampler.wrapT, j0, h0), coordZ);
679
680                         for (int j1 = minJ1; j1 <= maxJ1; j1++)
681                         {
682                                 for (int i1 = minI1; i1 <= maxI1; i1++)
683                                 {
684                                         const float     depth1  = lookupDepth(level1, sampler, wrap(sampler.wrapS, i1, w1), wrap(sampler.wrapT, j1, h1), coordZ);
685
686                                         if (isLinearCompareValid(sampler.compare, prec, Vec2(depth0, depth1), fBounds, cmpReference, result, isFixedPointDepth))
687                                                 return true;
688                                 }
689                         }
690                 }
691         }
692
693         return false;
694 }
695
696 static bool isLinearMipmapLinearCompareResultValid (const ConstPixelBufferAccess&       level0,
697                                                                                                         const ConstPixelBufferAccess&   level1,
698                                                                                                         const Sampler&                                  sampler,
699                                                                                                         const TexComparePrecision&              prec,
700                                                                                                         const Vec2&                                             coord,
701                                                                                                         const int                                               coordZ,
702                                                                                                         const Vec2&                                             fBounds,
703                                                                                                         const float                                             cmpReference,
704                                                                                                         const float                                             result)
705 {
706         const bool      isFixedPointDepth       = isFixedPointDepthTextureFormat(level0.getFormat());
707
708         // \todo [2013-07-04 pyry] This is strictly not correct as coordinates between levels should be dependent.
709         //                                                 Right now this allows pairing any two valid bilinear quads.
710
711         const int       w0                                      = level0.getWidth();
712         const int       w1                                      = level1.getWidth();
713         const int       h0                                      = level0.getHeight();
714         const int       h1                                      = level1.getHeight();
715
716         const Vec2      uBounds0                        = computeNonNormalizedCoordBounds(sampler.normalizedCoords, w0, coord.x(), prec.coordBits.x(), prec.uvwBits.x());
717         const Vec2      uBounds1                        = computeNonNormalizedCoordBounds(sampler.normalizedCoords, w1, coord.x(), prec.coordBits.x(), prec.uvwBits.x());
718         const Vec2      vBounds0                        = computeNonNormalizedCoordBounds(sampler.normalizedCoords, h0, coord.y(), prec.coordBits.y(), prec.uvwBits.y());
719         const Vec2      vBounds1                        = computeNonNormalizedCoordBounds(sampler.normalizedCoords, h1, coord.y(), prec.coordBits.y(), prec.uvwBits.y());
720
721         // Integer coordinates - without wrap mode
722         const int       minI0                           = deFloorFloatToInt32(uBounds0.x()-0.5f);
723         const int       maxI0                           = deFloorFloatToInt32(uBounds0.y()-0.5f);
724         const int       minI1                           = deFloorFloatToInt32(uBounds1.x()-0.5f);
725         const int       maxI1                           = deFloorFloatToInt32(uBounds1.y()-0.5f);
726         const int       minJ0                           = deFloorFloatToInt32(vBounds0.x()-0.5f);
727         const int       maxJ0                           = deFloorFloatToInt32(vBounds0.y()-0.5f);
728         const int       minJ1                           = deFloorFloatToInt32(vBounds1.x()-0.5f);
729         const int       maxJ1                           = deFloorFloatToInt32(vBounds1.y()-0.5f);
730
731         for (int j0 = minJ0; j0 <= maxJ0; j0++)
732         {
733                 for (int i0 = minI0; i0 <= maxI0; i0++)
734                 {
735                         const float     minA0   = de::clamp((uBounds0.x()-0.5f)-float(i0), 0.0f, 1.0f);
736                         const float     maxA0   = de::clamp((uBounds0.y()-0.5f)-float(i0), 0.0f, 1.0f);
737                         const float     minB0   = de::clamp((vBounds0.x()-0.5f)-float(j0), 0.0f, 1.0f);
738                         const float     maxB0   = de::clamp((vBounds0.y()-0.5f)-float(j0), 0.0f, 1.0f);
739                         Vec4            depths0;
740
741                         {
742                                 const int       x0              = wrap(sampler.wrapS, i0  , w0);
743                                 const int       x1              = wrap(sampler.wrapS, i0+1, w0);
744                                 const int       y0              = wrap(sampler.wrapT, j0  , h0);
745                                 const int       y1              = wrap(sampler.wrapT, j0+1, h0);
746
747                                 depths0[0] = lookupDepth(level0, sampler, x0, y0, coordZ);
748                                 depths0[1] = lookupDepth(level0, sampler, x1, y0, coordZ);
749                                 depths0[2] = lookupDepth(level0, sampler, x0, y1, coordZ);
750                                 depths0[3] = lookupDepth(level0, sampler, x1, y1, coordZ);
751                         }
752
753                         for (int j1 = minJ1; j1 <= maxJ1; j1++)
754                         {
755                                 for (int i1 = minI1; i1 <= maxI1; i1++)
756                                 {
757                                         const float     minA1   = de::clamp((uBounds1.x()-0.5f)-float(i1), 0.0f, 1.0f);
758                                         const float     maxA1   = de::clamp((uBounds1.y()-0.5f)-float(i1), 0.0f, 1.0f);
759                                         const float     minB1   = de::clamp((vBounds1.x()-0.5f)-float(j1), 0.0f, 1.0f);
760                                         const float     maxB1   = de::clamp((vBounds1.y()-0.5f)-float(j1), 0.0f, 1.0f);
761                                         Vec4            depths1;
762
763                                         {
764                                                 const int       x0              = wrap(sampler.wrapS, i1  , w1);
765                                                 const int       x1              = wrap(sampler.wrapS, i1+1, w1);
766                                                 const int       y0              = wrap(sampler.wrapT, j1  , h1);
767                                                 const int       y1              = wrap(sampler.wrapT, j1+1, h1);
768
769                                                 depths1[0] = lookupDepth(level1, sampler, x0, y0, coordZ);
770                                                 depths1[1] = lookupDepth(level1, sampler, x1, y0, coordZ);
771                                                 depths1[2] = lookupDepth(level1, sampler, x0, y1, coordZ);
772                                                 depths1[3] = lookupDepth(level1, sampler, x1, y1, coordZ);
773                                         }
774
775                                         if (isTrilinearCompareValid(sampler.compare, prec, depths0, depths1,
776                                                                                                 Vec2(minA0, maxA0), Vec2(minB0, maxB0),
777                                                                                                 Vec2(minA1, maxA1), Vec2(minB1, maxB1),
778                                                                                                 fBounds, cmpReference, result, isFixedPointDepth))
779                                                 return true;
780                                 }
781                         }
782                 }
783         }
784
785         return false;
786 }
787
788 static bool isMipmapLinearCompareResultValid (const ConstPixelBufferAccess&             level0,
789                                                                                           const ConstPixelBufferAccess&         level1,
790                                                                                           const Sampler&                                        sampler,
791                                                                                           const Sampler::FilterMode                     levelFilter,
792                                                                                           const TexComparePrecision&            prec,
793                                                                                           const Vec2&                                           coord,
794                                                                                           const int                                                     coordZ,
795                                                                                           const Vec2&                                           fBounds,
796                                                                                           const float                                           cmpReference,
797                                                                                           const float                                           result)
798 {
799         if (levelFilter == Sampler::LINEAR)
800                 return isLinearMipmapLinearCompareResultValid(level0, level1, sampler, prec, coord, coordZ, fBounds, cmpReference, result);
801         else
802                 return isNearestMipmapLinearCompareResultValid(level0, level1, sampler, prec, coord, coordZ, fBounds, cmpReference, result);
803 }
804
805 bool isTexCompareResultValid (const Texture2DView&                      texture,
806                                                           const Sampler&                                sampler,
807                                                           const TexComparePrecision&    prec,
808                                                           const Vec2&                                   coord,
809                                                           const Vec2&                                   lodBounds,
810                                                           const float                                   cmpReference,
811                                                           const float                                   result)
812 {
813         const float             minLod                  = lodBounds.x();
814         const float             maxLod                  = lodBounds.y();
815         const bool              canBeMagnified  = minLod <= sampler.lodThreshold;
816         const bool              canBeMinified   = maxLod > sampler.lodThreshold;
817
818         DE_ASSERT(isSamplerSupported(sampler));
819
820         if (canBeMagnified)
821         {
822                 if (isLevelCompareResultValid(texture.getLevel(0), sampler, sampler.magFilter, prec, coord, 0, cmpReference, result))
823                         return true;
824         }
825
826         if (canBeMinified)
827         {
828                 const bool      isNearestMipmap = isNearestMipmapFilter(sampler.minFilter);
829                 const bool      isLinearMipmap  = isLinearMipmapFilter(sampler.minFilter);
830                 const int       minTexLevel             = 0;
831                 const int       maxTexLevel             = texture.getNumLevels()-1;
832
833                 DE_ASSERT(minTexLevel < maxTexLevel);
834
835                 if (isLinearMipmap)
836                 {
837                         const int               minLevel                = de::clamp((int)deFloatFloor(minLod), minTexLevel, maxTexLevel-1);
838                         const int               maxLevel                = de::clamp((int)deFloatFloor(maxLod), minTexLevel, maxTexLevel-1);
839
840                         DE_ASSERT(minLevel <= maxLevel);
841
842                         for (int level = minLevel; level <= maxLevel; level++)
843                         {
844                                 const float             minF    = de::clamp(minLod - float(level), 0.0f, 1.0f);
845                                 const float             maxF    = de::clamp(maxLod - float(level), 0.0f, 1.0f);
846
847                                 if (isMipmapLinearCompareResultValid(texture.getLevel(level), texture.getLevel(level+1), sampler, getLevelFilter(sampler.minFilter), prec, coord, 0, Vec2(minF, maxF), cmpReference, result))
848                                         return true;
849                         }
850                 }
851                 else if (isNearestMipmap)
852                 {
853                         // \note The accurate formula for nearest mipmapping is level = ceil(lod + 0.5) - 1 but Khronos has made
854                         //               decision to allow floor(lod + 0.5) as well.
855                         const int               minLevel                = de::clamp((int)deFloatCeil(minLod + 0.5f) - 1,        minTexLevel, maxTexLevel);
856                         const int               maxLevel                = de::clamp((int)deFloatFloor(maxLod + 0.5f),           minTexLevel, maxTexLevel);
857
858                         DE_ASSERT(minLevel <= maxLevel);
859
860                         for (int level = minLevel; level <= maxLevel; level++)
861                         {
862                                 if (isLevelCompareResultValid(texture.getLevel(level), sampler, getLevelFilter(sampler.minFilter), prec, coord, 0, cmpReference, result))
863                                         return true;
864                         }
865                 }
866                 else
867                 {
868                         if (isLevelCompareResultValid(texture.getLevel(0), sampler, sampler.minFilter, prec, coord, 0, cmpReference, result))
869                                 return true;
870                 }
871         }
872
873         return false;
874 }
875
876 static bool isSeamplessLinearMipmapLinearCompareResultValid (const TextureCubeView&                     texture,
877                                                                                                                          const int                                              baseLevelNdx,
878                                                                                                                          const Sampler&                                 sampler,
879                                                                                                                          const TexComparePrecision&             prec,
880                                                                                                                          const CubeFaceFloatCoords&             coords,
881                                                                                                                          const Vec2&                                    fBounds,
882                                                                                                                          const float                                    cmpReference,
883                                                                                                                          const float                                    result)
884 {
885         const bool      isFixedPointDepth       = isFixedPointDepthTextureFormat(texture.getLevelFace(baseLevelNdx, CUBEFACE_NEGATIVE_X).getFormat());
886         const int       size0                           = texture.getLevelFace(baseLevelNdx,    coords.face).getWidth();
887         const int       size1                           = texture.getLevelFace(baseLevelNdx+1,  coords.face).getWidth();
888
889         const Vec2      uBounds0                        = computeNonNormalizedCoordBounds(sampler.normalizedCoords, size0,      coords.s, prec.coordBits.x(), prec.uvwBits.x());
890         const Vec2      uBounds1                        = computeNonNormalizedCoordBounds(sampler.normalizedCoords, size1,      coords.s, prec.coordBits.x(), prec.uvwBits.x());
891         const Vec2      vBounds0                        = computeNonNormalizedCoordBounds(sampler.normalizedCoords, size0,      coords.t, prec.coordBits.y(), prec.uvwBits.y());
892         const Vec2      vBounds1                        = computeNonNormalizedCoordBounds(sampler.normalizedCoords, size1,      coords.t, prec.coordBits.y(), prec.uvwBits.y());
893
894         // Integer coordinates - without wrap mode
895         const int       minI0                           = deFloorFloatToInt32(uBounds0.x()-0.5f);
896         const int       maxI0                           = deFloorFloatToInt32(uBounds0.y()-0.5f);
897         const int       minI1                           = deFloorFloatToInt32(uBounds1.x()-0.5f);
898         const int       maxI1                           = deFloorFloatToInt32(uBounds1.y()-0.5f);
899         const int       minJ0                           = deFloorFloatToInt32(vBounds0.x()-0.5f);
900         const int       maxJ0                           = deFloorFloatToInt32(vBounds0.y()-0.5f);
901         const int       minJ1                           = deFloorFloatToInt32(vBounds1.x()-0.5f);
902         const int       maxJ1                           = deFloorFloatToInt32(vBounds1.y()-0.5f);
903
904         tcu::ConstPixelBufferAccess faces0[CUBEFACE_LAST];
905         tcu::ConstPixelBufferAccess faces1[CUBEFACE_LAST];
906
907         for (int face = 0; face < CUBEFACE_LAST; face++)
908         {
909                 faces0[face] = texture.getLevelFace(baseLevelNdx,       CubeFace(face));
910                 faces1[face] = texture.getLevelFace(baseLevelNdx+1,     CubeFace(face));
911         }
912
913         for (int j0 = minJ0; j0 <= maxJ0; j0++)
914         {
915                 for (int i0 = minI0; i0 <= maxI0; i0++)
916                 {
917                         const float     minA0   = de::clamp((uBounds0.x()-0.5f)-float(i0), 0.0f, 1.0f);
918                         const float     maxA0   = de::clamp((uBounds0.y()-0.5f)-float(i0), 0.0f, 1.0f);
919                         const float     minB0   = de::clamp((vBounds0.x()-0.5f)-float(j0), 0.0f, 1.0f);
920                         const float     maxB0   = de::clamp((vBounds0.y()-0.5f)-float(j0), 0.0f, 1.0f);
921                         Vec4            depths0;
922
923                         {
924                                 const CubeFaceIntCoords c00     = remapCubeEdgeCoords(CubeFaceIntCoords(coords.face, IVec2(i0+0, j0+0)), size0);
925                                 const CubeFaceIntCoords c10     = remapCubeEdgeCoords(CubeFaceIntCoords(coords.face, IVec2(i0+1, j0+0)), size0);
926                                 const CubeFaceIntCoords c01     = remapCubeEdgeCoords(CubeFaceIntCoords(coords.face, IVec2(i0+0, j0+1)), size0);
927                                 const CubeFaceIntCoords c11     = remapCubeEdgeCoords(CubeFaceIntCoords(coords.face, IVec2(i0+1, j0+1)), size0);
928
929                                 // If any of samples is out of both edges, implementations can do pretty much anything according to spec.
930                                 // \todo [2013-07-08 pyry] Test the special case where all corner pixels have exactly the same color.
931                                 if (c00.face == CUBEFACE_LAST || c01.face == CUBEFACE_LAST || c10.face == CUBEFACE_LAST || c11.face == CUBEFACE_LAST)
932                                         return true;
933
934                                 depths0[0] = lookupDepthNoBorder(faces0[c00.face], sampler, c00.s, c00.t);
935                                 depths0[1] = lookupDepthNoBorder(faces0[c10.face], sampler, c10.s, c10.t);
936                                 depths0[2] = lookupDepthNoBorder(faces0[c01.face], sampler, c01.s, c01.t);
937                                 depths0[3] = lookupDepthNoBorder(faces0[c11.face], sampler, c11.s, c11.t);
938                         }
939
940                         for (int j1 = minJ1; j1 <= maxJ1; j1++)
941                         {
942                                 for (int i1 = minI1; i1 <= maxI1; i1++)
943                                 {
944                                         const float     minA1   = de::clamp((uBounds1.x()-0.5f)-float(i1), 0.0f, 1.0f);
945                                         const float     maxA1   = de::clamp((uBounds1.y()-0.5f)-float(i1), 0.0f, 1.0f);
946                                         const float     minB1   = de::clamp((vBounds1.x()-0.5f)-float(j1), 0.0f, 1.0f);
947                                         const float     maxB1   = de::clamp((vBounds1.y()-0.5f)-float(j1), 0.0f, 1.0f);
948                                         Vec4            depths1;
949
950                                         {
951                                                 const CubeFaceIntCoords c00     = remapCubeEdgeCoords(CubeFaceIntCoords(coords.face, IVec2(i1+0, j1+0)), size1);
952                                                 const CubeFaceIntCoords c10     = remapCubeEdgeCoords(CubeFaceIntCoords(coords.face, IVec2(i1+1, j1+0)), size1);
953                                                 const CubeFaceIntCoords c01     = remapCubeEdgeCoords(CubeFaceIntCoords(coords.face, IVec2(i1+0, j1+1)), size1);
954                                                 const CubeFaceIntCoords c11     = remapCubeEdgeCoords(CubeFaceIntCoords(coords.face, IVec2(i1+1, j1+1)), size1);
955
956                                                 if (c00.face == CUBEFACE_LAST || c01.face == CUBEFACE_LAST || c10.face == CUBEFACE_LAST || c11.face == CUBEFACE_LAST)
957                                                         return true;
958
959                                                 depths1[0] = lookupDepthNoBorder(faces1[c00.face], sampler, c00.s, c00.t);
960                                                 depths1[1] = lookupDepthNoBorder(faces1[c10.face], sampler, c10.s, c10.t);
961                                                 depths1[2] = lookupDepthNoBorder(faces1[c01.face], sampler, c01.s, c01.t);
962                                                 depths1[3] = lookupDepthNoBorder(faces1[c11.face], sampler, c11.s, c11.t);
963                                         }
964
965
966                                         if (isTrilinearCompareValid(sampler.compare, prec, depths0, depths1,
967                                                                                                 Vec2(minA0, maxA0), Vec2(minB0, maxB0),
968                                                                                                 Vec2(minA1, maxA1), Vec2(minB1, maxB1),
969                                                                                                 fBounds, cmpReference, result, isFixedPointDepth))
970                                                 return true;
971                                 }
972                         }
973                 }
974         }
975
976         return false;
977 }
978
979 static bool isCubeMipmapLinearCompareResultValid (const TextureCubeView&                texture,
980                                                                                                   const int                                             baseLevelNdx,
981                                                                                                   const Sampler&                                sampler,
982                                                                                                   const Sampler::FilterMode             levelFilter,
983                                                                                                   const TexComparePrecision&    prec,
984                                                                                                   const CubeFaceFloatCoords&    coords,
985                                                                                                   const Vec2&                                   fBounds,
986                                                                                                   const float                                   cmpReference,
987                                                                                                   const float                                   result)
988 {
989         if (levelFilter == Sampler::LINEAR)
990         {
991                 if (sampler.seamlessCubeMap)
992                         return isSeamplessLinearMipmapLinearCompareResultValid(texture, baseLevelNdx, sampler, prec, coords, fBounds, cmpReference, result);
993                 else
994                         return isLinearMipmapLinearCompareResultValid(texture.getLevelFace(baseLevelNdx,        coords.face),
995                                                                                                                   texture.getLevelFace(baseLevelNdx+1,  coords.face),
996                                                                                                                   sampler, prec, Vec2(coords.s, coords.t), 0, fBounds, cmpReference, result);
997         }
998         else
999                 return isNearestMipmapLinearCompareResultValid(texture.getLevelFace(baseLevelNdx,       coords.face),
1000                                                                                                            texture.getLevelFace(baseLevelNdx+1, coords.face),
1001                                                                                                            sampler, prec, Vec2(coords.s, coords.t), 0, fBounds, cmpReference, result);
1002 }
1003
1004 static bool isSeamlessLinearCompareResultValid (const TextureCubeView&          texture,
1005                                                                                                 const int                                       levelNdx,
1006                                                                                                 const Sampler&                          sampler,
1007                                                                                                 const TexComparePrecision&      prec,
1008                                                                                                 const CubeFaceFloatCoords&      coords,
1009                                                                                                 const float                                     cmpReference,
1010                                                                                                 const float                                     result)
1011 {
1012         const bool      isFixedPointDepth       = isFixedPointDepthTextureFormat(texture.getLevelFace(levelNdx, CUBEFACE_NEGATIVE_X).getFormat());
1013         const int       size                            = texture.getLevelFace(levelNdx, coords.face).getWidth();
1014
1015         const Vec2      uBounds                         = computeNonNormalizedCoordBounds(sampler.normalizedCoords, size, coords.s, prec.coordBits.x(), prec.uvwBits.x());
1016         const Vec2      vBounds                         = computeNonNormalizedCoordBounds(sampler.normalizedCoords, size, coords.t, prec.coordBits.y(), prec.uvwBits.y());
1017
1018         // Integer coordinate bounds for (x0,y0) - without wrap mode
1019         const int       minI                            = deFloorFloatToInt32(uBounds.x()-0.5f);
1020         const int       maxI                            = deFloorFloatToInt32(uBounds.y()-0.5f);
1021         const int       minJ                            = deFloorFloatToInt32(vBounds.x()-0.5f);
1022         const int       maxJ                            = deFloorFloatToInt32(vBounds.y()-0.5f);
1023
1024         // Face accesses
1025         ConstPixelBufferAccess faces[CUBEFACE_LAST];
1026         for (int face = 0; face < CUBEFACE_LAST; face++)
1027                 faces[face] = texture.getLevelFace(levelNdx, CubeFace(face));
1028
1029         for (int j = minJ; j <= maxJ; j++)
1030         {
1031                 for (int i = minI; i <= maxI; i++)
1032                 {
1033                         const CubeFaceIntCoords c00     = remapCubeEdgeCoords(CubeFaceIntCoords(coords.face, IVec2(i+0, j+0)), size);
1034                         const CubeFaceIntCoords c10     = remapCubeEdgeCoords(CubeFaceIntCoords(coords.face, IVec2(i+1, j+0)), size);
1035                         const CubeFaceIntCoords c01     = remapCubeEdgeCoords(CubeFaceIntCoords(coords.face, IVec2(i+0, j+1)), size);
1036                         const CubeFaceIntCoords c11     = remapCubeEdgeCoords(CubeFaceIntCoords(coords.face, IVec2(i+1, j+1)), size);
1037
1038                         // If any of samples is out of both edges, implementations can do pretty much anything according to spec.
1039                         // \todo [2013-07-08 pyry] Test the special case where all corner pixels have exactly the same color.
1040                         if (c00.face == CUBEFACE_LAST || c01.face == CUBEFACE_LAST || c10.face == CUBEFACE_LAST || c11.face == CUBEFACE_LAST)
1041                                 return true;
1042
1043                         // Bounds for filtering factors
1044                         const float     minA    = de::clamp((uBounds.x()-0.5f)-float(i), 0.0f, 1.0f);
1045                         const float     maxA    = de::clamp((uBounds.y()-0.5f)-float(i), 0.0f, 1.0f);
1046                         const float     minB    = de::clamp((vBounds.x()-0.5f)-float(j), 0.0f, 1.0f);
1047                         const float     maxB    = de::clamp((vBounds.y()-0.5f)-float(j), 0.0f, 1.0f);
1048
1049                         Vec4 depths;
1050                         depths[0] = lookupDepthNoBorder(faces[c00.face], sampler, c00.s, c00.t);
1051                         depths[1] = lookupDepthNoBorder(faces[c10.face], sampler, c10.s, c10.t);
1052                         depths[2] = lookupDepthNoBorder(faces[c01.face], sampler, c01.s, c01.t);
1053                         depths[3] = lookupDepthNoBorder(faces[c11.face], sampler, c11.s, c11.t);
1054
1055                         if (isBilinearCompareValid(sampler.compare, prec, depths, Vec2(minA, maxA), Vec2(minB, maxB), cmpReference, result, isFixedPointDepth))
1056                                 return true;
1057                 }
1058         }
1059
1060         return false;
1061 }
1062
1063 static bool isCubeLevelCompareResultValid (const TextureCubeView&                       texture,
1064                                                                                    const int                                            levelNdx,
1065                                                                                    const Sampler&                                       sampler,
1066                                                                                    const Sampler::FilterMode            filterMode,
1067                                                                                    const TexComparePrecision&           prec,
1068                                                                                    const CubeFaceFloatCoords&           coords,
1069                                                                                    const float                                          cmpReference,
1070                                                                                    const float                                          result)
1071 {
1072         if (filterMode == Sampler::LINEAR)
1073         {
1074                 if (sampler.seamlessCubeMap)
1075                         return isSeamlessLinearCompareResultValid(texture, levelNdx, sampler, prec, coords, cmpReference, result);
1076                 else
1077                         return isLinearCompareResultValid(texture.getLevelFace(levelNdx, coords.face), sampler, prec, Vec2(coords.s, coords.t), 0, cmpReference, result);
1078         }
1079         else
1080                 return isNearestCompareResultValid(texture.getLevelFace(levelNdx, coords.face), sampler, prec, Vec2(coords.s, coords.t), 0, cmpReference, result);
1081 }
1082
1083 bool isTexCompareResultValid (const TextureCubeView& texture, const Sampler& sampler, const TexComparePrecision& prec, const Vec3& coord, const Vec2& lodBounds, const float cmpReference, const float result)
1084 {
1085         int                     numPossibleFaces                                = 0;
1086         CubeFace        possibleFaces[CUBEFACE_LAST];
1087
1088         DE_ASSERT(isSamplerSupported(sampler));
1089
1090         getPossibleCubeFaces(coord, prec.coordBits, &possibleFaces[0], numPossibleFaces);
1091
1092         if (numPossibleFaces == 0)
1093                 return true; // Result is undefined.
1094
1095         for (int tryFaceNdx = 0; tryFaceNdx < numPossibleFaces; tryFaceNdx++)
1096         {
1097                 const CubeFaceFloatCoords       faceCoords              (possibleFaces[tryFaceNdx], projectToFace(possibleFaces[tryFaceNdx], coord));
1098                 const float                                     minLod                  = lodBounds.x();
1099                 const float                                     maxLod                  = lodBounds.y();
1100                 const bool                                      canBeMagnified  = minLod <= sampler.lodThreshold;
1101                 const bool                                      canBeMinified   = maxLod > sampler.lodThreshold;
1102
1103                 if (canBeMagnified)
1104                 {
1105                         if (isCubeLevelCompareResultValid(texture, 0, sampler, sampler.magFilter, prec, faceCoords, cmpReference, result))
1106                                 return true;
1107                 }
1108
1109                 if (canBeMinified)
1110                 {
1111                         const bool      isNearestMipmap = isNearestMipmapFilter(sampler.minFilter);
1112                         const bool      isLinearMipmap  = isLinearMipmapFilter(sampler.minFilter);
1113                         const int       minTexLevel             = 0;
1114                         const int       maxTexLevel             = texture.getNumLevels()-1;
1115
1116                         DE_ASSERT(minTexLevel < maxTexLevel);
1117
1118                         if (isLinearMipmap)
1119                         {
1120                                 const int               minLevel                = de::clamp((int)deFloatFloor(minLod), minTexLevel, maxTexLevel-1);
1121                                 const int               maxLevel                = de::clamp((int)deFloatFloor(maxLod), minTexLevel, maxTexLevel-1);
1122
1123                                 DE_ASSERT(minLevel <= maxLevel);
1124
1125                                 for (int level = minLevel; level <= maxLevel; level++)
1126                                 {
1127                                         const float             minF    = de::clamp(minLod - float(level), 0.0f, 1.0f);
1128                                         const float             maxF    = de::clamp(maxLod - float(level), 0.0f, 1.0f);
1129
1130                                         if (isCubeMipmapLinearCompareResultValid(texture, level, sampler, getLevelFilter(sampler.minFilter), prec, faceCoords, Vec2(minF, maxF), cmpReference, result))
1131                                                 return true;
1132                                 }
1133                         }
1134                         else if (isNearestMipmap)
1135                         {
1136                                 // \note The accurate formula for nearest mipmapping is level = ceil(lod + 0.5) - 1 but Khronos has made
1137                                 //               decision to allow floor(lod + 0.5) as well.
1138                                 const int               minLevel                = de::clamp((int)deFloatCeil(minLod + 0.5f) - 1,        minTexLevel, maxTexLevel);
1139                                 const int               maxLevel                = de::clamp((int)deFloatFloor(maxLod + 0.5f),           minTexLevel, maxTexLevel);
1140
1141                                 DE_ASSERT(minLevel <= maxLevel);
1142
1143                                 for (int level = minLevel; level <= maxLevel; level++)
1144                                 {
1145                                         if (isCubeLevelCompareResultValid(texture, level, sampler, getLevelFilter(sampler.minFilter), prec, faceCoords, cmpReference, result))
1146                                                 return true;
1147                                 }
1148                         }
1149                         else
1150                         {
1151                                 if (isCubeLevelCompareResultValid(texture, 0, sampler, sampler.minFilter, prec, faceCoords, cmpReference, result))
1152                                         return true;
1153                         }
1154                 }
1155         }
1156
1157         return false;
1158 }
1159
1160 bool isTexCompareResultValid (const Texture2DArrayView& texture, const Sampler& sampler, const TexComparePrecision& prec, const Vec3& coord, const Vec2& lodBounds, const float cmpReference, const float result)
1161 {
1162         const float             depthErr        = computeFloatingPointError(coord.z(), prec.coordBits.z()) + computeFixedPointError(prec.uvwBits.z());
1163         const float             minZ            = coord.z()-depthErr;
1164         const float             maxZ            = coord.z()+depthErr;
1165         const int               minLayer        = de::clamp(deFloorFloatToInt32(minZ + 0.5f), 0, texture.getNumLayers()-1);
1166         const int               maxLayer        = de::clamp(deFloorFloatToInt32(maxZ + 0.5f), 0, texture.getNumLayers()-1);
1167
1168         DE_ASSERT(isSamplerSupported(sampler));
1169
1170         for (int layer = minLayer; layer <= maxLayer; layer++)
1171         {
1172                 const float             minLod                  = lodBounds.x();
1173                 const float             maxLod                  = lodBounds.y();
1174                 const bool              canBeMagnified  = minLod <= sampler.lodThreshold;
1175                 const bool              canBeMinified   = maxLod > sampler.lodThreshold;
1176
1177                 if (canBeMagnified)
1178                 {
1179                         if (isLevelCompareResultValid(texture.getLevel(0), sampler, sampler.magFilter, prec, coord.swizzle(0,1), layer, cmpReference, result))
1180                                 return true;
1181                 }
1182
1183                 if (canBeMinified)
1184                 {
1185                         const bool      isNearestMipmap = isNearestMipmapFilter(sampler.minFilter);
1186                         const bool      isLinearMipmap  = isLinearMipmapFilter(sampler.minFilter);
1187                         const int       minTexLevel             = 0;
1188                         const int       maxTexLevel             = texture.getNumLevels()-1;
1189
1190                         DE_ASSERT(minTexLevel < maxTexLevel);
1191
1192                         if (isLinearMipmap)
1193                         {
1194                                 const int               minLevel                = de::clamp((int)deFloatFloor(minLod), minTexLevel, maxTexLevel-1);
1195                                 const int               maxLevel                = de::clamp((int)deFloatFloor(maxLod), minTexLevel, maxTexLevel-1);
1196
1197                                 DE_ASSERT(minLevel <= maxLevel);
1198
1199                                 for (int level = minLevel; level <= maxLevel; level++)
1200                                 {
1201                                         const float             minF    = de::clamp(minLod - float(level), 0.0f, 1.0f);
1202                                         const float             maxF    = de::clamp(maxLod - float(level), 0.0f, 1.0f);
1203
1204                                         if (isMipmapLinearCompareResultValid(texture.getLevel(level), texture.getLevel(level+1), sampler, getLevelFilter(sampler.minFilter), prec, coord.swizzle(0,1), layer, Vec2(minF, maxF), cmpReference, result))
1205                                                 return true;
1206                                 }
1207                         }
1208                         else if (isNearestMipmap)
1209                         {
1210                                 // \note The accurate formula for nearest mipmapping is level = ceil(lod + 0.5) - 1 but Khronos has made
1211                                 //               decision to allow floor(lod + 0.5) as well.
1212                                 const int               minLevel                = de::clamp((int)deFloatCeil(minLod + 0.5f) - 1,        minTexLevel, maxTexLevel);
1213                                 const int               maxLevel                = de::clamp((int)deFloatFloor(maxLod + 0.5f),           minTexLevel, maxTexLevel);
1214
1215                                 DE_ASSERT(minLevel <= maxLevel);
1216
1217                                 for (int level = minLevel; level <= maxLevel; level++)
1218                                 {
1219                                         if (isLevelCompareResultValid(texture.getLevel(level), sampler, getLevelFilter(sampler.minFilter), prec, coord.swizzle(0,1), layer, cmpReference, result))
1220                                                 return true;
1221                                 }
1222                         }
1223                         else
1224                         {
1225                                 if (isLevelCompareResultValid(texture.getLevel(0), sampler, sampler.minFilter, prec, coord.swizzle(0,1), layer, cmpReference, result))
1226                                         return true;
1227                         }
1228                 }
1229         }
1230
1231         return false;
1232 }
1233
1234 static bool isGatherOffsetsCompareResultValid (const ConstPixelBufferAccess&    texture,
1235                                                                                            const Sampler&                                       sampler,
1236                                                                                            const TexComparePrecision&           prec,
1237                                                                                            const Vec2&                                          coord,
1238                                                                                            int                                                          coordZ,
1239                                                                                            const IVec2                                          (&offsets)[4],
1240                                                                                            float                                                        cmpReference,
1241                                                                                            const Vec4&                                          result)
1242 {
1243         const bool      isFixedPointDepth       = isFixedPointDepthTextureFormat(texture.getFormat());
1244         const Vec2      uBounds                         = computeNonNormalizedCoordBounds(sampler.normalizedCoords, texture.getWidth(),         coord.x(), prec.coordBits.x(), prec.uvwBits.x());
1245         const Vec2      vBounds                         = computeNonNormalizedCoordBounds(sampler.normalizedCoords, texture.getHeight(),        coord.y(), prec.coordBits.y(), prec.uvwBits.y());
1246
1247         // Integer coordinate bounds for (x0, y0) - without wrap mode
1248         const int       minI                            = deFloorFloatToInt32(uBounds.x()-0.5f);
1249         const int       maxI                            = deFloorFloatToInt32(uBounds.y()-0.5f);
1250         const int       minJ                            = deFloorFloatToInt32(vBounds.x()-0.5f);
1251         const int       maxJ                            = deFloorFloatToInt32(vBounds.y()-0.5f);
1252
1253         const int       w                                       = texture.getWidth();
1254         const int       h                                       = texture.getHeight();
1255
1256         for (int j = minJ; j <= maxJ; j++)
1257         {
1258                 for (int i = minI; i <= maxI; i++)
1259                 {
1260                         bool isCurrentPixelValid = true;
1261
1262                         for (int offNdx = 0; offNdx < 4 && isCurrentPixelValid; offNdx++)
1263                         {
1264                                 // offNdx-th coordinate offset and then wrapped.
1265                                 const int                       x               = wrap(sampler.wrapS, i+offsets[offNdx].x(), w);
1266                                 const int                       y               = wrap(sampler.wrapT, j+offsets[offNdx].y(), h);
1267                                 const float                     depth   = lookupDepth(texture, sampler, x, y, coordZ);
1268                                 const CmpResultSet      resSet  = execCompare(sampler.compare, depth, cmpReference, prec.referenceBits, isFixedPointDepth);
1269
1270                                 if (!isResultInSet(resSet, result[offNdx], prec.resultBits))
1271                                         isCurrentPixelValid = false;
1272                         }
1273
1274                         if (isCurrentPixelValid)
1275                                 return true;
1276                 }
1277         }
1278
1279         return false;
1280 }
1281
1282 bool isGatherOffsetsCompareResultValid (const Texture2DView&            texture,
1283                                                                                 const Sampler&                          sampler,
1284                                                                                 const TexComparePrecision&      prec,
1285                                                                                 const Vec2&                                     coord,
1286                                                                                 const IVec2                                     (&offsets)[4],
1287                                                                                 float                                           cmpReference,
1288                                                                                 const Vec4&                                     result)
1289 {
1290         DE_ASSERT(isSamplerSupported(sampler));
1291
1292         return isGatherOffsetsCompareResultValid(texture.getLevel(0), sampler, prec, coord, 0, offsets, cmpReference, result);
1293 }
1294
1295 bool isGatherOffsetsCompareResultValid (const Texture2DArrayView&       texture,
1296                                                                                 const Sampler&                          sampler,
1297                                                                                 const TexComparePrecision&      prec,
1298                                                                                 const Vec3&                                     coord,
1299                                                                                 const IVec2                                     (&offsets)[4],
1300                                                                                 float                                           cmpReference,
1301                                                                                 const Vec4&                                     result)
1302 {
1303         const float             depthErr        = computeFloatingPointError(coord.z(), prec.coordBits.z()) + computeFixedPointError(prec.uvwBits.z());
1304         const float             minZ            = coord.z()-depthErr;
1305         const float             maxZ            = coord.z()+depthErr;
1306         const int               minLayer        = de::clamp(deFloorFloatToInt32(minZ + 0.5f), 0, texture.getNumLayers()-1);
1307         const int               maxLayer        = de::clamp(deFloorFloatToInt32(maxZ + 0.5f), 0, texture.getNumLayers()-1);
1308
1309         DE_ASSERT(isSamplerSupported(sampler));
1310
1311         for (int layer = minLayer; layer <= maxLayer; layer++)
1312         {
1313                 if (isGatherOffsetsCompareResultValid(texture.getLevel(0), sampler, prec, coord.swizzle(0,1), layer, offsets, cmpReference, result))
1314                         return true;
1315         }
1316         return false;
1317 }
1318
1319 static bool isGatherCompareResultValid (const TextureCubeView&          texture,
1320                                                                                 const Sampler&                          sampler,
1321                                                                                 const TexComparePrecision&      prec,
1322                                                                                 const CubeFaceFloatCoords&      coords,
1323                                                                                 float                                           cmpReference,
1324                                                                                 const Vec4&                                     result)
1325 {
1326         const bool      isFixedPointDepth       = isFixedPointDepthTextureFormat(texture.getLevelFace(0, coords.face).getFormat());
1327         const int       size                            = texture.getLevelFace(0, coords.face).getWidth();
1328         const Vec2      uBounds                         = computeNonNormalizedCoordBounds(sampler.normalizedCoords, size, coords.s, prec.coordBits.x(), prec.uvwBits.x());
1329         const Vec2      vBounds                         = computeNonNormalizedCoordBounds(sampler.normalizedCoords, size, coords.t, prec.coordBits.y(), prec.uvwBits.y());
1330
1331         // Integer coordinate bounds for (x0,y0) - without wrap mode
1332         const int       minI                            = deFloorFloatToInt32(uBounds.x()-0.5f);
1333         const int       maxI                            = deFloorFloatToInt32(uBounds.y()-0.5f);
1334         const int       minJ                            = deFloorFloatToInt32(vBounds.x()-0.5f);
1335         const int       maxJ                            = deFloorFloatToInt32(vBounds.y()-0.5f);
1336
1337         // Face accesses
1338         ConstPixelBufferAccess faces[CUBEFACE_LAST];
1339         for (int face = 0; face < CUBEFACE_LAST; face++)
1340                 faces[face] = texture.getLevelFace(0, CubeFace(face));
1341
1342         for (int j = minJ; j <= maxJ; j++)
1343         {
1344                 for (int i = minI; i <= maxI; i++)
1345                 {
1346                         static const IVec2 offsets[4] =
1347                         {
1348                                 IVec2(0, 1),
1349                                 IVec2(1, 1),
1350                                 IVec2(1, 0),
1351                                 IVec2(0, 0)
1352                         };
1353
1354                         bool isCurrentPixelValid = true;
1355
1356                         for (int offNdx = 0; offNdx < 4 && isCurrentPixelValid; offNdx++)
1357                         {
1358                                 const CubeFaceIntCoords c = remapCubeEdgeCoords(CubeFaceIntCoords(coords.face, i+offsets[offNdx].x(), j+offsets[offNdx].y()), size);
1359                                 // If any of samples is out of both edges, implementations can do pretty much anything according to spec.
1360                                 // \todo [2014-06-05 nuutti] Test the special case where all corner pixels have exactly the same color.
1361                                 //                                                       See also isSeamlessLinearCompareResultValid and similar.
1362                                 if (c.face == CUBEFACE_LAST)
1363                                         return true;
1364
1365                                 const float                     depth   = lookupDepthNoBorder(faces[c.face], sampler, c.s, c.t);
1366                                 const CmpResultSet      resSet  = execCompare(sampler.compare, depth, cmpReference, prec.referenceBits, isFixedPointDepth);
1367
1368                                 if (!isResultInSet(resSet, result[offNdx], prec.resultBits))
1369                                         isCurrentPixelValid = false;
1370                         }
1371
1372                         if (isCurrentPixelValid)
1373                                 return true;
1374                 }
1375         }
1376
1377         return false;
1378 }
1379
1380 bool isGatherCompareResultValid (const TextureCubeView&                 texture,
1381                                                                  const Sampler&                                 sampler,
1382                                                                  const TexComparePrecision&             prec,
1383                                                                  const Vec3&                                    coord,
1384                                                                  float                                                  cmpReference,
1385                                                                  const Vec4&                                    result)
1386 {
1387         int                     numPossibleFaces                                = 0;
1388         CubeFace        possibleFaces[CUBEFACE_LAST];
1389
1390         DE_ASSERT(isSamplerSupported(sampler));
1391
1392         getPossibleCubeFaces(coord, prec.coordBits, &possibleFaces[0], numPossibleFaces);
1393
1394         if (numPossibleFaces == 0)
1395                 return true; // Result is undefined.
1396
1397         for (int tryFaceNdx = 0; tryFaceNdx < numPossibleFaces; tryFaceNdx++)
1398         {
1399                 const CubeFaceFloatCoords faceCoords(possibleFaces[tryFaceNdx], projectToFace(possibleFaces[tryFaceNdx], coord));
1400
1401                 if (isGatherCompareResultValid(texture, sampler, prec, faceCoords, cmpReference, result))
1402                         return true;
1403         }
1404
1405         return false;
1406 }
1407
1408 } // tcu