Fix missing dependency on sparse binds
[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 // lookup depth value at a point that is guaranteed to not sample border such as cube map faces.
135 static float lookupDepthNoBorder (const tcu::ConstPixelBufferAccess& access, const Sampler& sampler, int i, int j, int k = 0)
136 {
137         DE_UNREF(sampler);
138         DE_ASSERT(coordsInBounds(access, i, j, k));
139         DE_ASSERT(      access.getFormat().order == TextureFormat::D || access.getFormat().order == TextureFormat::DS ||
140                                 access.getFormat().order == TextureFormat::R);
141
142         if (access.getFormat().order == TextureFormat::R)
143                 return access.getPixel(i,j,k).x();
144         else
145                 return access.getPixDepth(i, j, k);
146 }
147
148 static float lookupDepth (const tcu::ConstPixelBufferAccess& access, const Sampler& sampler, int i, int j, int k)
149 {
150         if (coordsInBounds(access, i, j, k))
151                 return lookupDepthNoBorder(access, sampler, i, j, k);
152         else
153                 return sampleTextureBorder<float>(access.getFormat(), sampler).x();
154 }
155
156 // Values are in order (0,0), (1,0), (0,1), (1,1)
157 static float bilinearInterpolate (const Vec4& values, const float x, const float y)
158 {
159         const float             v00             = values[0];
160         const float             v10             = values[1];
161         const float             v01             = values[2];
162         const float             v11             = values[3];
163         const float             res             = v00*(1.0f-x)*(1.0f-y) + v10*x*(1.0f-y) + v01*(1.0f-x)*y + v11*x*y;
164         return res;
165 }
166
167 static bool isFixedPointDepthTextureFormat (const tcu::TextureFormat& format)
168 {
169         const tcu::TextureChannelClass channelClass = tcu::getTextureChannelClass(format.type);
170
171         if (format.order == TextureFormat::D || format.order == TextureFormat::R)
172         {
173                 // depth internal formats cannot be non-normalized integers
174                 return channelClass != tcu::TEXTURECHANNELCLASS_FLOATING_POINT;
175         }
176         else if (format.order == TextureFormat::DS)
177         {
178                 // combined formats have no single channel class, detect format manually
179                 switch (format.type)
180                 {
181                         case tcu::TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV:   return false;
182                         case tcu::TextureFormat::UNSIGNED_INT_16_8_8:                   return true;
183                         case tcu::TextureFormat::UNSIGNED_INT_24_8:                             return true;
184                         case tcu::TextureFormat::UNSIGNED_INT_24_8_REV:                 return true;
185
186                         default:
187                         {
188                                 // unknown format
189                                 DE_ASSERT(false);
190                                 return true;
191                         }
192                 }
193         }
194
195         return false;
196 }
197
198 static bool isLinearCompareValid (const Sampler::CompareMode    compareMode,
199                                                                   const TexComparePrecision&    prec,
200                                                                   const Vec2&                                   depths,
201                                                                   const Vec2&                                   fBounds,
202                                                                   const float                                   cmpReference,
203                                                                   const float                                   result,
204                                                                   const bool                                    isFixedPointDepth)
205 {
206         DE_ASSERT(0.0f <= fBounds.x() && fBounds.x() <= fBounds.y() && fBounds.y() <= 1.0f);
207
208         const float                     d0                      = depths[0];
209         const float                     d1                      = depths[1];
210
211         const CmpResultSet      cmp0            = execCompare(compareMode, d0, cmpReference, prec.referenceBits, isFixedPointDepth);
212         const CmpResultSet      cmp1            = execCompare(compareMode, d1, cmpReference, prec.referenceBits, isFixedPointDepth);
213
214         const deUint32          isTrue          = (deUint32(cmp0.isTrue)<<0)
215                                                                         | (deUint32(cmp1.isTrue)<<1);
216         const deUint32          isFalse         = (deUint32(cmp0.isFalse)<<0)
217                                                                         | (deUint32(cmp1.isFalse)<<1);
218
219         // Interpolation parameters
220         const float                     f0                      = fBounds.x();
221         const float                     f1                      = fBounds.y();
222
223         // Error parameters
224         const float                     pcfErr          = computeFixedPointError(prec.pcfBits);
225         const float                     resErr          = computeFixedPointError(prec.resultBits);
226         const float                     totalErr        = pcfErr+resErr;
227
228         // Iterate over all valid combinations.
229         for (deUint32 comb = 0; comb < (1<<2); comb++)
230         {
231                 // Filter out invalid combinations.
232                 if (((comb & isTrue) | (~comb & isFalse)) != (1<<2)-1)
233                         continue;
234
235                 const bool              cmp0True        = ((comb>>0)&1) != 0;
236                 const bool              cmp1True        = ((comb>>1)&1) != 0;
237
238                 const float             ref0            = cmp0True ? 1.0f : 0.0f;
239                 const float             ref1            = cmp1True ? 1.0f : 0.0f;
240
241                 const float             v0                      = ref0*(1.0f-f0) + ref1*f0;
242                 const float             v1                      = ref0*(1.0f-f1) + ref1*f1;
243                 const float             minV            = de::min(v0, v1);
244                 const float             maxV            = de::max(v0, v1);
245                 const float             minR            = minV-totalErr;
246                 const float             maxR            = maxV+totalErr;
247
248                 if (de::inRange(result, minR, maxR))
249                         return true;
250         }
251
252         return false;
253 }
254
255 static inline BVec4 extractBVec4 (const deUint32 val, int offset)
256 {
257         return BVec4(((val>>(offset+0))&1) != 0,
258                                  ((val>>(offset+1))&1) != 0,
259                                  ((val>>(offset+2))&1) != 0,
260                                  ((val>>(offset+3))&1) != 0);
261 }
262
263 static bool isBilinearAnyCompareValid (const Sampler::CompareMode       compareMode,
264                                                                            const TexComparePrecision&   prec,
265                                                                            const Vec4&                                  depths,
266                                                                            const float                                  cmpReference,
267                                                                            const float                                  result,
268                                                                            const bool                                   isFixedPointDepth)
269 {
270         DE_ASSERT(prec.pcfBits == 0);
271
272         const float                     d0                      = depths[0];
273         const float                     d1                      = depths[1];
274         const float                     d2                      = depths[2];
275         const float                     d3                      = depths[3];
276
277         const CmpResultSet      cmp0            = execCompare(compareMode, d0, cmpReference, prec.referenceBits, isFixedPointDepth);
278         const CmpResultSet      cmp1            = execCompare(compareMode, d1, cmpReference, prec.referenceBits, isFixedPointDepth);
279         const CmpResultSet      cmp2            = execCompare(compareMode, d2, cmpReference, prec.referenceBits, isFixedPointDepth);
280         const CmpResultSet      cmp3            = execCompare(compareMode, d3, cmpReference, prec.referenceBits, isFixedPointDepth);
281
282         const bool                      canBeTrue       = cmp0.isTrue || cmp1.isTrue || cmp2.isTrue || cmp3.isTrue;
283         const bool                      canBeFalse      = cmp0.isFalse || cmp1.isFalse || cmp2.isFalse || cmp3.isFalse;
284
285         const float                     resErr          = computeFixedPointError(prec.resultBits);
286
287         const float                     minBound        = canBeFalse ? 0.0f : 1.0f;
288         const float                     maxBound        = canBeTrue ? 1.0f : 0.0f;
289
290         return de::inRange(result, minBound-resErr, maxBound+resErr);
291 }
292
293 static bool isBilinearPCFCompareValid (const Sampler::CompareMode       compareMode,
294                                                                            const TexComparePrecision&   prec,
295                                                                            const Vec4&                                  depths,
296                                                                            const Vec2&                                  xBounds,
297                                                                            const Vec2&                                  yBounds,
298                                                                            const float                                  cmpReference,
299                                                                            const float                                  result,
300                                                                            const bool                                   isFixedPointDepth)
301 {
302         DE_ASSERT(0.0f <= xBounds.x() && xBounds.x() <= xBounds.y() && xBounds.y() <= 1.0f);
303         DE_ASSERT(0.0f <= yBounds.x() && yBounds.x() <= yBounds.y() && yBounds.y() <= 1.0f);
304         DE_ASSERT(prec.pcfBits > 0);
305
306         const float                     d0                      = depths[0];
307         const float                     d1                      = depths[1];
308         const float                     d2                      = depths[2];
309         const float                     d3                      = depths[3];
310
311         const CmpResultSet      cmp0            = execCompare(compareMode, d0, cmpReference, prec.referenceBits, isFixedPointDepth);
312         const CmpResultSet      cmp1            = execCompare(compareMode, d1, cmpReference, prec.referenceBits, isFixedPointDepth);
313         const CmpResultSet      cmp2            = execCompare(compareMode, d2, cmpReference, prec.referenceBits, isFixedPointDepth);
314         const CmpResultSet      cmp3            = execCompare(compareMode, d3, cmpReference, prec.referenceBits, isFixedPointDepth);
315
316         const deUint32          isTrue          = (deUint32(cmp0.isTrue)<<0)
317                                                                         | (deUint32(cmp1.isTrue)<<1)
318                                                                         | (deUint32(cmp2.isTrue)<<2)
319                                                                         | (deUint32(cmp3.isTrue)<<3);
320         const deUint32          isFalse         = (deUint32(cmp0.isFalse)<<0)
321                                                                         | (deUint32(cmp1.isFalse)<<1)
322                                                                         | (deUint32(cmp2.isFalse)<<2)
323                                                                         | (deUint32(cmp3.isFalse)<<3);
324
325         // Interpolation parameters
326         const float                     x0                      = xBounds.x();
327         const float                     x1                      = xBounds.y();
328         const float                     y0                      = yBounds.x();
329         const float                     y1                      = yBounds.y();
330
331         // Error parameters
332         const float                     pcfErr          = computeFixedPointError(prec.pcfBits);
333         const float                     resErr          = computeFixedPointError(prec.resultBits);
334         const float                     totalErr        = pcfErr+resErr;
335
336         // Iterate over all valid combinations.
337         // \note It is not enough to compute minmax over all possible result sets, as ranges may
338         //               not necessarily overlap, i.e. there are gaps between valid ranges.
339         for (deUint32 comb = 0; comb < (1<<4); comb++)
340         {
341                 // Filter out invalid combinations:
342                 //  1) True bit is set in comb but not in isTrue => sample can not be true
343                 //  2) True bit is NOT set in comb and not in isFalse => sample can not be false
344                 if (((comb & isTrue) | (~comb & isFalse)) != (1<<4)-1)
345                         continue;
346
347                 const BVec4             cmpTrue         = extractBVec4(comb, 0);
348                 const Vec4              refVal          = select(Vec4(1.0f), Vec4(0.0f), cmpTrue);
349
350                 const float             v0                      = bilinearInterpolate(refVal, x0, y0);
351                 const float             v1                      = bilinearInterpolate(refVal, x1, y0);
352                 const float             v2                      = bilinearInterpolate(refVal, x0, y1);
353                 const float             v3                      = bilinearInterpolate(refVal, x1, y1);
354                 const float             minV            = de::min(v0, de::min(v1, de::min(v2, v3)));
355                 const float             maxV            = de::max(v0, de::max(v1, de::max(v2, v3)));
356                 const float             minR            = minV-totalErr;
357                 const float             maxR            = maxV+totalErr;
358
359                 if (de::inRange(result, minR, maxR))
360                         return true;
361         }
362
363         return false;
364 }
365
366 static bool isBilinearCompareValid (const Sampler::CompareMode  compareMode,
367                                                                         const TexComparePrecision&      prec,
368                                                                         const Vec4&                                     depths,
369                                                                         const Vec2&                                     xBounds,
370                                                                         const Vec2&                                     yBounds,
371                                                                         const float                                     cmpReference,
372                                                                         const float                                     result,
373                                                                         const bool                                      isFixedPointDepth)
374 {
375         if (prec.pcfBits > 0)
376                 return isBilinearPCFCompareValid(compareMode, prec, depths, xBounds, yBounds, cmpReference, result, isFixedPointDepth);
377         else
378                 return isBilinearAnyCompareValid(compareMode, prec, depths, cmpReference, result, isFixedPointDepth);
379 }
380
381 static bool isTrilinearAnyCompareValid (const Sampler::CompareMode      compareMode,
382                                                                                 const TexComparePrecision&      prec,
383                                                                                 const Vec4&                                     depths0,
384                                                                                 const Vec4&                                     depths1,
385                                                                                 const float                                     cmpReference,
386                                                                                 const float                                     result,
387                                                                                 const bool                                      isFixedPointDepth)
388 {
389         DE_ASSERT(prec.pcfBits == 0);
390
391         const CmpResultSet      cmp00           = execCompare(compareMode, depths0[0], cmpReference, prec.referenceBits, isFixedPointDepth);
392         const CmpResultSet      cmp01           = execCompare(compareMode, depths0[1], cmpReference, prec.referenceBits, isFixedPointDepth);
393         const CmpResultSet      cmp02           = execCompare(compareMode, depths0[2], cmpReference, prec.referenceBits, isFixedPointDepth);
394         const CmpResultSet      cmp03           = execCompare(compareMode, depths0[3], cmpReference, prec.referenceBits, isFixedPointDepth);
395
396         const CmpResultSet      cmp10           = execCompare(compareMode, depths1[0], cmpReference, prec.referenceBits, isFixedPointDepth);
397         const CmpResultSet      cmp11           = execCompare(compareMode, depths1[1], cmpReference, prec.referenceBits, isFixedPointDepth);
398         const CmpResultSet      cmp12           = execCompare(compareMode, depths1[2], cmpReference, prec.referenceBits, isFixedPointDepth);
399         const CmpResultSet      cmp13           = execCompare(compareMode, depths1[3], cmpReference, prec.referenceBits, isFixedPointDepth);
400
401         const bool                      canBeTrue       = cmp00.isTrue ||
402                                                                           cmp01.isTrue ||
403                                                                           cmp02.isTrue ||
404                                                                           cmp03.isTrue ||
405                                                                           cmp10.isTrue ||
406                                                                           cmp11.isTrue ||
407                                                                           cmp12.isTrue ||
408                                                                           cmp13.isTrue;
409         const bool                      canBeFalse      = cmp00.isFalse ||
410                                                                           cmp01.isFalse ||
411                                                                           cmp02.isFalse ||
412                                                                           cmp03.isFalse ||
413                                                                           cmp10.isFalse ||
414                                                                           cmp11.isFalse ||
415                                                                           cmp12.isFalse ||
416                                                                           cmp13.isFalse;
417
418         const float                     resErr          = computeFixedPointError(prec.resultBits);
419
420         const float                     minBound        = canBeFalse ? 0.0f : 1.0f;
421         const float                     maxBound        = canBeTrue ? 1.0f : 0.0f;
422
423         return de::inRange(result, minBound-resErr, maxBound+resErr);
424 }
425
426 static bool isTrilinearPCFCompareValid (const Sampler::CompareMode      compareMode,
427                                                                                 const TexComparePrecision&      prec,
428                                                                                 const Vec4&                                     depths0,
429                                                                                 const Vec4&                                     depths1,
430                                                                                 const Vec2&                                     xBounds0,
431                                                                                 const Vec2&                                     yBounds0,
432                                                                                 const Vec2&                                     xBounds1,
433                                                                                 const Vec2&                                     yBounds1,
434                                                                                 const Vec2&                                     fBounds,
435                                                                                 const float                                     cmpReference,
436                                                                                 const float                                     result,
437                                                                                 const bool                                      isFixedPointDepth)
438 {
439         DE_ASSERT(0.0f <= xBounds0.x() && xBounds0.x() <= xBounds0.y() && xBounds0.y() <= 1.0f);
440         DE_ASSERT(0.0f <= yBounds0.x() && yBounds0.x() <= yBounds0.y() && yBounds0.y() <= 1.0f);
441         DE_ASSERT(0.0f <= xBounds1.x() && xBounds1.x() <= xBounds1.y() && xBounds1.y() <= 1.0f);
442         DE_ASSERT(0.0f <= yBounds1.x() && yBounds1.x() <= yBounds1.y() && yBounds1.y() <= 1.0f);
443         DE_ASSERT(0.0f <= fBounds.x() && fBounds.x() <= fBounds.y() && fBounds.y() <= 1.0f);
444         DE_ASSERT(prec.pcfBits > 0);
445
446         const CmpResultSet      cmp00           = execCompare(compareMode, depths0[0], cmpReference, prec.referenceBits, isFixedPointDepth);
447         const CmpResultSet      cmp01           = execCompare(compareMode, depths0[1], cmpReference, prec.referenceBits, isFixedPointDepth);
448         const CmpResultSet      cmp02           = execCompare(compareMode, depths0[2], cmpReference, prec.referenceBits, isFixedPointDepth);
449         const CmpResultSet      cmp03           = execCompare(compareMode, depths0[3], cmpReference, prec.referenceBits, isFixedPointDepth);
450
451         const CmpResultSet      cmp10           = execCompare(compareMode, depths1[0], cmpReference, prec.referenceBits, isFixedPointDepth);
452         const CmpResultSet      cmp11           = execCompare(compareMode, depths1[1], cmpReference, prec.referenceBits, isFixedPointDepth);
453         const CmpResultSet      cmp12           = execCompare(compareMode, depths1[2], cmpReference, prec.referenceBits, isFixedPointDepth);
454         const CmpResultSet      cmp13           = execCompare(compareMode, depths1[3], cmpReference, prec.referenceBits, isFixedPointDepth);
455
456         const deUint32          isTrue          = (deUint32(cmp00.isTrue)<<0)
457                                                                         | (deUint32(cmp01.isTrue)<<1)
458                                                                         | (deUint32(cmp02.isTrue)<<2)
459                                                                         | (deUint32(cmp03.isTrue)<<3)
460                                                                         | (deUint32(cmp10.isTrue)<<4)
461                                                                         | (deUint32(cmp11.isTrue)<<5)
462                                                                         | (deUint32(cmp12.isTrue)<<6)
463                                                                         | (deUint32(cmp13.isTrue)<<7);
464         const deUint32          isFalse         = (deUint32(cmp00.isFalse)<<0)
465                                                                         | (deUint32(cmp01.isFalse)<<1)
466                                                                         | (deUint32(cmp02.isFalse)<<2)
467                                                                         | (deUint32(cmp03.isFalse)<<3)
468                                                                         | (deUint32(cmp10.isFalse)<<4)
469                                                                         | (deUint32(cmp11.isFalse)<<5)
470                                                                         | (deUint32(cmp12.isFalse)<<6)
471                                                                         | (deUint32(cmp13.isFalse)<<7);
472
473         // Error parameters
474         const float                     pcfErr          = computeFixedPointError(prec.pcfBits);
475         const float                     resErr          = computeFixedPointError(prec.resultBits);
476         const float                     totalErr        = pcfErr+resErr;
477
478         // Iterate over all valid combinations.
479         for (deUint32 comb = 0; comb < (1<<8); comb++)
480         {
481                 // Filter out invalid combinations.
482                 if (((comb & isTrue) | (~comb & isFalse)) != (1<<8)-1)
483                         continue;
484
485                 const BVec4             cmpTrue0        = extractBVec4(comb, 0);
486                 const BVec4             cmpTrue1        = extractBVec4(comb, 4);
487                 const Vec4              refVal0         = select(Vec4(1.0f), Vec4(0.0f), cmpTrue0);
488                 const Vec4              refVal1         = select(Vec4(1.0f), Vec4(0.0f), cmpTrue1);
489
490                 // Bilinear interpolation within levels.
491                 const float             v00                     = bilinearInterpolate(refVal0, xBounds0.x(), yBounds0.x());
492                 const float             v01                     = bilinearInterpolate(refVal0, xBounds0.y(), yBounds0.x());
493                 const float             v02                     = bilinearInterpolate(refVal0, xBounds0.x(), yBounds0.y());
494                 const float             v03                     = bilinearInterpolate(refVal0, xBounds0.y(), yBounds0.y());
495                 const float             minV0           = de::min(v00, de::min(v01, de::min(v02, v03)));
496                 const float             maxV0           = de::max(v00, de::max(v01, de::max(v02, v03)));
497
498                 const float             v10                     = bilinearInterpolate(refVal1, xBounds1.x(), yBounds1.x());
499                 const float             v11                     = bilinearInterpolate(refVal1, xBounds1.y(), yBounds1.x());
500                 const float             v12                     = bilinearInterpolate(refVal1, xBounds1.x(), yBounds1.y());
501                 const float             v13                     = bilinearInterpolate(refVal1, xBounds1.y(), yBounds1.y());
502                 const float             minV1           = de::min(v10, de::min(v11, de::min(v12, v13)));
503                 const float             maxV1           = de::max(v10, de::max(v11, de::max(v12, v13)));
504
505                 // Compute min-max bounds by filtering between minimum bounds and maximum bounds between levels.
506                 // HW can end up choosing pretty much any of samples between levels, and thus interpolating
507                 // between minimums should yield lower bound for range, and same for upper bound.
508                 // \todo [2013-07-17 pyry] This seems separable? Can this be optimized? At least ranges could be pre-computed and later combined.
509                 const float             minF0           = minV0*(1.0f-fBounds.x()) + minV1*fBounds.x();
510                 const float             minF1           = minV0*(1.0f-fBounds.y()) + minV1*fBounds.y();
511                 const float             maxF0           = maxV0*(1.0f-fBounds.x()) + maxV1*fBounds.x();
512                 const float             maxF1           = maxV0*(1.0f-fBounds.y()) + maxV1*fBounds.y();
513
514                 const float             minF            = de::min(minF0, minF1);
515                 const float             maxF            = de::max(maxF0, maxF1);
516
517                 const float             minR            = minF-totalErr;
518                 const float             maxR            = maxF+totalErr;
519
520                 if (de::inRange(result, minR, maxR))
521                         return true;
522         }
523
524         return false;
525 }
526
527 static bool isTrilinearCompareValid (const Sampler::CompareMode compareMode,
528                                                                          const TexComparePrecision&     prec,
529                                                                          const Vec4&                            depths0,
530                                                                          const Vec4&                            depths1,
531                                                                          const Vec2&                            xBounds0,
532                                                                          const Vec2&                            yBounds0,
533                                                                          const Vec2&                            xBounds1,
534                                                                          const Vec2&                            yBounds1,
535                                                                          const Vec2&                            fBounds,
536                                                                          const float                            cmpReference,
537                                                                          const float                            result,
538                                                                          const bool                                     isFixedPointDepth)
539 {
540         if (prec.pcfBits > 0)
541                 return isTrilinearPCFCompareValid(compareMode, prec, depths0, depths1, xBounds0, yBounds0, xBounds1, yBounds1, fBounds, cmpReference, result, isFixedPointDepth);
542         else
543                 return isTrilinearAnyCompareValid(compareMode, prec, depths0, depths1, cmpReference, result, isFixedPointDepth);
544 }
545
546 static bool isNearestCompareResultValid (const ConstPixelBufferAccess&          level,
547                                                                                  const Sampler&                                         sampler,
548                                                                                  const TexComparePrecision&                     prec,
549                                                                                  const Vec2&                                            coord,
550                                                                                  const int                                                      coordZ,
551                                                                                  const float                                            cmpReference,
552                                                                                  const float                                            result)
553 {
554         const bool      isFixedPointDepth       = isFixedPointDepthTextureFormat(level.getFormat());
555         const Vec2      uBounds                         = computeNonNormalizedCoordBounds(sampler.normalizedCoords, level.getWidth(),   coord.x(), prec.coordBits.x(), prec.uvwBits.x());
556         const Vec2      vBounds                         = computeNonNormalizedCoordBounds(sampler.normalizedCoords, level.getHeight(),  coord.y(), prec.coordBits.y(), prec.uvwBits.y());
557
558         // Integer coordinates - without wrap mode
559         const int       minI            = deFloorFloatToInt32(uBounds.x());
560         const int       maxI            = deFloorFloatToInt32(uBounds.y());
561         const int       minJ            = deFloorFloatToInt32(vBounds.x());
562         const int       maxJ            = deFloorFloatToInt32(vBounds.y());
563
564         for (int j = minJ; j <= maxJ; j++)
565         {
566                 for (int i = minI; i <= maxI; i++)
567                 {
568                         const int                       x               = wrap(sampler.wrapS, i, level.getWidth());
569                         const int                       y               = wrap(sampler.wrapT, j, level.getHeight());
570                         const float                     depth   = lookupDepth(level, sampler, x, y, coordZ);
571                         const CmpResultSet      resSet  = execCompare(sampler.compare, depth, cmpReference, prec.referenceBits, isFixedPointDepth);
572
573                         if (isResultInSet(resSet, result, prec.resultBits))
574                                 return true;
575                 }
576         }
577
578         return false;
579 }
580
581 static bool isLinearCompareResultValid (const ConstPixelBufferAccess&           level,
582                                                                                 const Sampler&                                          sampler,
583                                                                                 const TexComparePrecision&                      prec,
584                                                                                 const Vec2&                                                     coord,
585                                                                                 const int                                                       coordZ,
586                                                                                 const float                                                     cmpReference,
587                                                                                 const float                                                     result)
588 {
589         const bool      isFixedPointDepth       = isFixedPointDepthTextureFormat(level.getFormat());
590         const Vec2      uBounds                         = computeNonNormalizedCoordBounds(sampler.normalizedCoords, level.getWidth(),   coord.x(), prec.coordBits.x(), prec.uvwBits.x());
591         const Vec2      vBounds                         = computeNonNormalizedCoordBounds(sampler.normalizedCoords, level.getHeight(),  coord.y(), prec.coordBits.y(), prec.uvwBits.y());
592
593         // Integer coordinate bounds for (x0,y0) - without wrap mode
594         const int       minI            = deFloorFloatToInt32(uBounds.x()-0.5f);
595         const int       maxI            = deFloorFloatToInt32(uBounds.y()-0.5f);
596         const int       minJ            = deFloorFloatToInt32(vBounds.x()-0.5f);
597         const int       maxJ            = deFloorFloatToInt32(vBounds.y()-0.5f);
598
599         const int       w                       = level.getWidth();
600         const int       h                       = level.getHeight();
601
602         // \todo [2013-07-03 pyry] This could be optimized by first computing ranges based on wrap mode.
603
604         for (int j = minJ; j <= maxJ; j++)
605         {
606                 for (int i = minI; i <= maxI; i++)
607                 {
608                         // Wrapped coordinates
609                         const int       x0              = wrap(sampler.wrapS, i  , w);
610                         const int       x1              = wrap(sampler.wrapS, i+1, w);
611                         const int       y0              = wrap(sampler.wrapT, j  , h);
612                         const int       y1              = wrap(sampler.wrapT, j+1, h);
613
614                         // Bounds for filtering factors
615                         const float     minA    = de::clamp((uBounds.x()-0.5f)-float(i), 0.0f, 1.0f);
616                         const float     maxA    = de::clamp((uBounds.y()-0.5f)-float(i), 0.0f, 1.0f);
617                         const float     minB    = de::clamp((vBounds.x()-0.5f)-float(j), 0.0f, 1.0f);
618                         const float     maxB    = de::clamp((vBounds.y()-0.5f)-float(j), 0.0f, 1.0f);
619
620                         const Vec4      depths  (lookupDepth(level, sampler, x0, y0, coordZ),
621                                                                  lookupDepth(level, sampler, x1, y0, coordZ),
622                                                                  lookupDepth(level, sampler, x0, y1, coordZ),
623                                                                  lookupDepth(level, sampler, x1, y1, coordZ));
624
625                         if (isBilinearCompareValid(sampler.compare, prec, depths, Vec2(minA, maxA), Vec2(minB, maxB), cmpReference, result, isFixedPointDepth))
626                                 return true;
627                 }
628         }
629
630         return false;
631 }
632
633 static bool isLevelCompareResultValid (const ConstPixelBufferAccess&    level,
634                                                                            const Sampler&                                       sampler,
635                                                                            const Sampler::FilterMode            filterMode,
636                                                                            const TexComparePrecision&           prec,
637                                                                            const Vec2&                                          coord,
638                                                                            const int                                            coordZ,
639                                                                            const float                                          cmpReference,
640                                                                            const float                                          result)
641 {
642         if (filterMode == Sampler::LINEAR)
643                 return isLinearCompareResultValid(level, sampler, prec, coord, coordZ, cmpReference, result);
644         else
645                 return isNearestCompareResultValid(level, sampler, prec, coord, coordZ, cmpReference, result);
646 }
647
648 static bool isNearestMipmapLinearCompareResultValid (const ConstPixelBufferAccess&      level0,
649                                                                                                          const ConstPixelBufferAccess&  level1,
650                                                                                                          const Sampler&                                 sampler,
651                                                                                                          const TexComparePrecision&             prec,
652                                                                                                          const Vec2&                                    coord,
653                                                                                                          const int                                              coordZ,
654                                                                                                          const Vec2&                                    fBounds,
655                                                                                                          const float                                    cmpReference,
656                                                                                                          const float                                    result)
657 {
658         const bool      isFixedPointDepth       = isFixedPointDepthTextureFormat(level0.getFormat());
659
660         const int       w0                                      = level0.getWidth();
661         const int       w1                                      = level1.getWidth();
662         const int       h0                                      = level0.getHeight();
663         const int       h1                                      = level1.getHeight();
664
665         const Vec2      uBounds0                        = computeNonNormalizedCoordBounds(sampler.normalizedCoords, w0, coord.x(), prec.coordBits.x(), prec.uvwBits.x());
666         const Vec2      uBounds1                        = computeNonNormalizedCoordBounds(sampler.normalizedCoords, w1, coord.x(), prec.coordBits.x(), prec.uvwBits.x());
667         const Vec2      vBounds0                        = computeNonNormalizedCoordBounds(sampler.normalizedCoords, h0, coord.y(), prec.coordBits.y(), prec.uvwBits.y());
668         const Vec2      vBounds1                        = computeNonNormalizedCoordBounds(sampler.normalizedCoords, h1, coord.y(), prec.coordBits.y(), prec.uvwBits.y());
669
670         // Integer coordinates - without wrap mode
671         const int       minI0                           = deFloorFloatToInt32(uBounds0.x());
672         const int       maxI0                           = deFloorFloatToInt32(uBounds0.y());
673         const int       minI1                           = deFloorFloatToInt32(uBounds1.x());
674         const int       maxI1                           = deFloorFloatToInt32(uBounds1.y());
675         const int       minJ0                           = deFloorFloatToInt32(vBounds0.x());
676         const int       maxJ0                           = deFloorFloatToInt32(vBounds0.y());
677         const int       minJ1                           = deFloorFloatToInt32(vBounds1.x());
678         const int       maxJ1                           = deFloorFloatToInt32(vBounds1.y());
679
680         for (int j0 = minJ0; j0 <= maxJ0; j0++)
681         {
682                 for (int i0 = minI0; i0 <= maxI0; i0++)
683                 {
684                         const float     depth0  = lookupDepth(level0, sampler, wrap(sampler.wrapS, i0, w0), wrap(sampler.wrapT, j0, h0), coordZ);
685
686                         for (int j1 = minJ1; j1 <= maxJ1; j1++)
687                         {
688                                 for (int i1 = minI1; i1 <= maxI1; i1++)
689                                 {
690                                         const float     depth1  = lookupDepth(level1, sampler, wrap(sampler.wrapS, i1, w1), wrap(sampler.wrapT, j1, h1), coordZ);
691
692                                         if (isLinearCompareValid(sampler.compare, prec, Vec2(depth0, depth1), fBounds, cmpReference, result, isFixedPointDepth))
693                                                 return true;
694                                 }
695                         }
696                 }
697         }
698
699         return false;
700 }
701
702 static bool isLinearMipmapLinearCompareResultValid (const ConstPixelBufferAccess&       level0,
703                                                                                                         const ConstPixelBufferAccess&   level1,
704                                                                                                         const Sampler&                                  sampler,
705                                                                                                         const TexComparePrecision&              prec,
706                                                                                                         const Vec2&                                             coord,
707                                                                                                         const int                                               coordZ,
708                                                                                                         const Vec2&                                             fBounds,
709                                                                                                         const float                                             cmpReference,
710                                                                                                         const float                                             result)
711 {
712         const bool      isFixedPointDepth       = isFixedPointDepthTextureFormat(level0.getFormat());
713
714         // \todo [2013-07-04 pyry] This is strictly not correct as coordinates between levels should be dependent.
715         //                                                 Right now this allows pairing any two valid bilinear quads.
716
717         const int       w0                                      = level0.getWidth();
718         const int       w1                                      = level1.getWidth();
719         const int       h0                                      = level0.getHeight();
720         const int       h1                                      = level1.getHeight();
721
722         const Vec2      uBounds0                        = computeNonNormalizedCoordBounds(sampler.normalizedCoords, w0, coord.x(), prec.coordBits.x(), prec.uvwBits.x());
723         const Vec2      uBounds1                        = computeNonNormalizedCoordBounds(sampler.normalizedCoords, w1, coord.x(), prec.coordBits.x(), prec.uvwBits.x());
724         const Vec2      vBounds0                        = computeNonNormalizedCoordBounds(sampler.normalizedCoords, h0, coord.y(), prec.coordBits.y(), prec.uvwBits.y());
725         const Vec2      vBounds1                        = computeNonNormalizedCoordBounds(sampler.normalizedCoords, h1, coord.y(), prec.coordBits.y(), prec.uvwBits.y());
726
727         // Integer coordinates - without wrap mode
728         const int       minI0                           = deFloorFloatToInt32(uBounds0.x()-0.5f);
729         const int       maxI0                           = deFloorFloatToInt32(uBounds0.y()-0.5f);
730         const int       minI1                           = deFloorFloatToInt32(uBounds1.x()-0.5f);
731         const int       maxI1                           = deFloorFloatToInt32(uBounds1.y()-0.5f);
732         const int       minJ0                           = deFloorFloatToInt32(vBounds0.x()-0.5f);
733         const int       maxJ0                           = deFloorFloatToInt32(vBounds0.y()-0.5f);
734         const int       minJ1                           = deFloorFloatToInt32(vBounds1.x()-0.5f);
735         const int       maxJ1                           = deFloorFloatToInt32(vBounds1.y()-0.5f);
736
737         for (int j0 = minJ0; j0 <= maxJ0; j0++)
738         {
739                 for (int i0 = minI0; i0 <= maxI0; i0++)
740                 {
741                         const float     minA0   = de::clamp((uBounds0.x()-0.5f)-float(i0), 0.0f, 1.0f);
742                         const float     maxA0   = de::clamp((uBounds0.y()-0.5f)-float(i0), 0.0f, 1.0f);
743                         const float     minB0   = de::clamp((vBounds0.x()-0.5f)-float(j0), 0.0f, 1.0f);
744                         const float     maxB0   = de::clamp((vBounds0.y()-0.5f)-float(j0), 0.0f, 1.0f);
745                         Vec4            depths0;
746
747                         {
748                                 const int       x0              = wrap(sampler.wrapS, i0  , w0);
749                                 const int       x1              = wrap(sampler.wrapS, i0+1, w0);
750                                 const int       y0              = wrap(sampler.wrapT, j0  , h0);
751                                 const int       y1              = wrap(sampler.wrapT, j0+1, h0);
752
753                                 depths0[0] = lookupDepth(level0, sampler, x0, y0, coordZ);
754                                 depths0[1] = lookupDepth(level0, sampler, x1, y0, coordZ);
755                                 depths0[2] = lookupDepth(level0, sampler, x0, y1, coordZ);
756                                 depths0[3] = lookupDepth(level0, sampler, x1, y1, coordZ);
757                         }
758
759                         for (int j1 = minJ1; j1 <= maxJ1; j1++)
760                         {
761                                 for (int i1 = minI1; i1 <= maxI1; i1++)
762                                 {
763                                         const float     minA1   = de::clamp((uBounds1.x()-0.5f)-float(i1), 0.0f, 1.0f);
764                                         const float     maxA1   = de::clamp((uBounds1.y()-0.5f)-float(i1), 0.0f, 1.0f);
765                                         const float     minB1   = de::clamp((vBounds1.x()-0.5f)-float(j1), 0.0f, 1.0f);
766                                         const float     maxB1   = de::clamp((vBounds1.y()-0.5f)-float(j1), 0.0f, 1.0f);
767                                         Vec4            depths1;
768
769                                         {
770                                                 const int       x0              = wrap(sampler.wrapS, i1  , w1);
771                                                 const int       x1              = wrap(sampler.wrapS, i1+1, w1);
772                                                 const int       y0              = wrap(sampler.wrapT, j1  , h1);
773                                                 const int       y1              = wrap(sampler.wrapT, j1+1, h1);
774
775                                                 depths1[0] = lookupDepth(level1, sampler, x0, y0, coordZ);
776                                                 depths1[1] = lookupDepth(level1, sampler, x1, y0, coordZ);
777                                                 depths1[2] = lookupDepth(level1, sampler, x0, y1, coordZ);
778                                                 depths1[3] = lookupDepth(level1, sampler, x1, y1, coordZ);
779                                         }
780
781                                         if (isTrilinearCompareValid(sampler.compare, prec, depths0, depths1,
782                                                                                                 Vec2(minA0, maxA0), Vec2(minB0, maxB0),
783                                                                                                 Vec2(minA1, maxA1), Vec2(minB1, maxB1),
784                                                                                                 fBounds, cmpReference, result, isFixedPointDepth))
785                                                 return true;
786                                 }
787                         }
788                 }
789         }
790
791         return false;
792 }
793
794 static bool isMipmapLinearCompareResultValid (const ConstPixelBufferAccess&             level0,
795                                                                                           const ConstPixelBufferAccess&         level1,
796                                                                                           const Sampler&                                        sampler,
797                                                                                           const Sampler::FilterMode                     levelFilter,
798                                                                                           const TexComparePrecision&            prec,
799                                                                                           const Vec2&                                           coord,
800                                                                                           const int                                                     coordZ,
801                                                                                           const Vec2&                                           fBounds,
802                                                                                           const float                                           cmpReference,
803                                                                                           const float                                           result)
804 {
805         if (levelFilter == Sampler::LINEAR)
806                 return isLinearMipmapLinearCompareResultValid(level0, level1, sampler, prec, coord, coordZ, fBounds, cmpReference, result);
807         else
808                 return isNearestMipmapLinearCompareResultValid(level0, level1, sampler, prec, coord, coordZ, fBounds, cmpReference, result);
809 }
810
811 bool isTexCompareResultValid (const Texture2DView&                      texture,
812                                                           const Sampler&                                sampler,
813                                                           const TexComparePrecision&    prec,
814                                                           const Vec2&                                   coord,
815                                                           const Vec2&                                   lodBounds,
816                                                           const float                                   cmpReference,
817                                                           const float                                   result)
818 {
819         const float             minLod                  = lodBounds.x();
820         const float             maxLod                  = lodBounds.y();
821         const bool              canBeMagnified  = minLod <= sampler.lodThreshold;
822         const bool              canBeMinified   = maxLod > sampler.lodThreshold;
823
824         DE_ASSERT(isSamplerSupported(sampler));
825
826         if (canBeMagnified)
827         {
828                 if (isLevelCompareResultValid(texture.getLevel(0), sampler, sampler.magFilter, prec, coord, 0, cmpReference, result))
829                         return true;
830         }
831
832         if (canBeMinified)
833         {
834                 const bool      isNearestMipmap = isNearestMipmapFilter(sampler.minFilter);
835                 const bool      isLinearMipmap  = isLinearMipmapFilter(sampler.minFilter);
836                 const int       minTexLevel             = 0;
837                 const int       maxTexLevel             = texture.getNumLevels()-1;
838
839                 DE_ASSERT(minTexLevel < maxTexLevel);
840
841                 if (isLinearMipmap)
842                 {
843                         const int               minLevel                = de::clamp((int)deFloatFloor(minLod), minTexLevel, maxTexLevel-1);
844                         const int               maxLevel                = de::clamp((int)deFloatFloor(maxLod), minTexLevel, maxTexLevel-1);
845
846                         DE_ASSERT(minLevel <= maxLevel);
847
848                         for (int level = minLevel; level <= maxLevel; level++)
849                         {
850                                 const float             minF    = de::clamp(minLod - float(level), 0.0f, 1.0f);
851                                 const float             maxF    = de::clamp(maxLod - float(level), 0.0f, 1.0f);
852
853                                 if (isMipmapLinearCompareResultValid(texture.getLevel(level), texture.getLevel(level+1), sampler, getLevelFilter(sampler.minFilter), prec, coord, 0, Vec2(minF, maxF), cmpReference, result))
854                                         return true;
855                         }
856                 }
857                 else if (isNearestMipmap)
858                 {
859                         // \note The accurate formula for nearest mipmapping is level = ceil(lod + 0.5) - 1 but Khronos has made
860                         //               decision to allow floor(lod + 0.5) as well.
861                         const int               minLevel                = de::clamp((int)deFloatCeil(minLod + 0.5f) - 1,        minTexLevel, maxTexLevel);
862                         const int               maxLevel                = de::clamp((int)deFloatFloor(maxLod + 0.5f),           minTexLevel, maxTexLevel);
863
864                         DE_ASSERT(minLevel <= maxLevel);
865
866                         for (int level = minLevel; level <= maxLevel; level++)
867                         {
868                                 if (isLevelCompareResultValid(texture.getLevel(level), sampler, getLevelFilter(sampler.minFilter), prec, coord, 0, cmpReference, result))
869                                         return true;
870                         }
871                 }
872                 else
873                 {
874                         if (isLevelCompareResultValid(texture.getLevel(0), sampler, sampler.minFilter, prec, coord, 0, cmpReference, result))
875                                 return true;
876                 }
877         }
878
879         return false;
880 }
881
882 static bool isSeamplessLinearMipmapLinearCompareResultValid (const TextureCubeView&                     texture,
883                                                                                                                          const int                                              baseLevelNdx,
884                                                                                                                          const Sampler&                                 sampler,
885                                                                                                                          const TexComparePrecision&             prec,
886                                                                                                                          const CubeFaceFloatCoords&             coords,
887                                                                                                                          const Vec2&                                    fBounds,
888                                                                                                                          const float                                    cmpReference,
889                                                                                                                          const float                                    result)
890 {
891         const bool      isFixedPointDepth       = isFixedPointDepthTextureFormat(texture.getLevelFace(baseLevelNdx, CUBEFACE_NEGATIVE_X).getFormat());
892         const int       size0                           = texture.getLevelFace(baseLevelNdx,    coords.face).getWidth();
893         const int       size1                           = texture.getLevelFace(baseLevelNdx+1,  coords.face).getWidth();
894
895         const Vec2      uBounds0                        = computeNonNormalizedCoordBounds(sampler.normalizedCoords, size0,      coords.s, prec.coordBits.x(), prec.uvwBits.x());
896         const Vec2      uBounds1                        = computeNonNormalizedCoordBounds(sampler.normalizedCoords, size1,      coords.s, prec.coordBits.x(), prec.uvwBits.x());
897         const Vec2      vBounds0                        = computeNonNormalizedCoordBounds(sampler.normalizedCoords, size0,      coords.t, prec.coordBits.y(), prec.uvwBits.y());
898         const Vec2      vBounds1                        = computeNonNormalizedCoordBounds(sampler.normalizedCoords, size1,      coords.t, prec.coordBits.y(), prec.uvwBits.y());
899
900         // Integer coordinates - without wrap mode
901         const int       minI0                           = deFloorFloatToInt32(uBounds0.x()-0.5f);
902         const int       maxI0                           = deFloorFloatToInt32(uBounds0.y()-0.5f);
903         const int       minI1                           = deFloorFloatToInt32(uBounds1.x()-0.5f);
904         const int       maxI1                           = deFloorFloatToInt32(uBounds1.y()-0.5f);
905         const int       minJ0                           = deFloorFloatToInt32(vBounds0.x()-0.5f);
906         const int       maxJ0                           = deFloorFloatToInt32(vBounds0.y()-0.5f);
907         const int       minJ1                           = deFloorFloatToInt32(vBounds1.x()-0.5f);
908         const int       maxJ1                           = deFloorFloatToInt32(vBounds1.y()-0.5f);
909
910         tcu::ConstPixelBufferAccess faces0[CUBEFACE_LAST];
911         tcu::ConstPixelBufferAccess faces1[CUBEFACE_LAST];
912
913         for (int face = 0; face < CUBEFACE_LAST; face++)
914         {
915                 faces0[face] = texture.getLevelFace(baseLevelNdx,       CubeFace(face));
916                 faces1[face] = texture.getLevelFace(baseLevelNdx+1,     CubeFace(face));
917         }
918
919         for (int j0 = minJ0; j0 <= maxJ0; j0++)
920         {
921                 for (int i0 = minI0; i0 <= maxI0; i0++)
922                 {
923                         const float     minA0   = de::clamp((uBounds0.x()-0.5f)-float(i0), 0.0f, 1.0f);
924                         const float     maxA0   = de::clamp((uBounds0.y()-0.5f)-float(i0), 0.0f, 1.0f);
925                         const float     minB0   = de::clamp((vBounds0.x()-0.5f)-float(j0), 0.0f, 1.0f);
926                         const float     maxB0   = de::clamp((vBounds0.y()-0.5f)-float(j0), 0.0f, 1.0f);
927                         Vec4            depths0;
928
929                         {
930                                 const CubeFaceIntCoords c00     = remapCubeEdgeCoords(CubeFaceIntCoords(coords.face, IVec2(i0+0, j0+0)), size0);
931                                 const CubeFaceIntCoords c10     = remapCubeEdgeCoords(CubeFaceIntCoords(coords.face, IVec2(i0+1, j0+0)), size0);
932                                 const CubeFaceIntCoords c01     = remapCubeEdgeCoords(CubeFaceIntCoords(coords.face, IVec2(i0+0, j0+1)), size0);
933                                 const CubeFaceIntCoords c11     = remapCubeEdgeCoords(CubeFaceIntCoords(coords.face, IVec2(i0+1, j0+1)), size0);
934
935                                 // If any of samples is out of both edges, implementations can do pretty much anything according to spec.
936                                 // \todo [2013-07-08 pyry] Test the special case where all corner pixels have exactly the same color.
937                                 if (c00.face == CUBEFACE_LAST || c01.face == CUBEFACE_LAST || c10.face == CUBEFACE_LAST || c11.face == CUBEFACE_LAST)
938                                         return true;
939
940                                 depths0[0] = lookupDepthNoBorder(faces0[c00.face], sampler, c00.s, c00.t);
941                                 depths0[1] = lookupDepthNoBorder(faces0[c10.face], sampler, c10.s, c10.t);
942                                 depths0[2] = lookupDepthNoBorder(faces0[c01.face], sampler, c01.s, c01.t);
943                                 depths0[3] = lookupDepthNoBorder(faces0[c11.face], sampler, c11.s, c11.t);
944                         }
945
946                         for (int j1 = minJ1; j1 <= maxJ1; j1++)
947                         {
948                                 for (int i1 = minI1; i1 <= maxI1; i1++)
949                                 {
950                                         const float     minA1   = de::clamp((uBounds1.x()-0.5f)-float(i1), 0.0f, 1.0f);
951                                         const float     maxA1   = de::clamp((uBounds1.y()-0.5f)-float(i1), 0.0f, 1.0f);
952                                         const float     minB1   = de::clamp((vBounds1.x()-0.5f)-float(j1), 0.0f, 1.0f);
953                                         const float     maxB1   = de::clamp((vBounds1.y()-0.5f)-float(j1), 0.0f, 1.0f);
954                                         Vec4            depths1;
955
956                                         {
957                                                 const CubeFaceIntCoords c00     = remapCubeEdgeCoords(CubeFaceIntCoords(coords.face, IVec2(i1+0, j1+0)), size1);
958                                                 const CubeFaceIntCoords c10     = remapCubeEdgeCoords(CubeFaceIntCoords(coords.face, IVec2(i1+1, j1+0)), size1);
959                                                 const CubeFaceIntCoords c01     = remapCubeEdgeCoords(CubeFaceIntCoords(coords.face, IVec2(i1+0, j1+1)), size1);
960                                                 const CubeFaceIntCoords c11     = remapCubeEdgeCoords(CubeFaceIntCoords(coords.face, IVec2(i1+1, j1+1)), size1);
961
962                                                 if (c00.face == CUBEFACE_LAST || c01.face == CUBEFACE_LAST || c10.face == CUBEFACE_LAST || c11.face == CUBEFACE_LAST)
963                                                         return true;
964
965                                                 depths1[0] = lookupDepthNoBorder(faces1[c00.face], sampler, c00.s, c00.t);
966                                                 depths1[1] = lookupDepthNoBorder(faces1[c10.face], sampler, c10.s, c10.t);
967                                                 depths1[2] = lookupDepthNoBorder(faces1[c01.face], sampler, c01.s, c01.t);
968                                                 depths1[3] = lookupDepthNoBorder(faces1[c11.face], sampler, c11.s, c11.t);
969                                         }
970
971
972                                         if (isTrilinearCompareValid(sampler.compare, prec, depths0, depths1,
973                                                                                                 Vec2(minA0, maxA0), Vec2(minB0, maxB0),
974                                                                                                 Vec2(minA1, maxA1), Vec2(minB1, maxB1),
975                                                                                                 fBounds, cmpReference, result, isFixedPointDepth))
976                                                 return true;
977                                 }
978                         }
979                 }
980         }
981
982         return false;
983 }
984
985 static bool isCubeMipmapLinearCompareResultValid (const TextureCubeView&                texture,
986                                                                                                   const int                                             baseLevelNdx,
987                                                                                                   const Sampler&                                sampler,
988                                                                                                   const Sampler::FilterMode             levelFilter,
989                                                                                                   const TexComparePrecision&    prec,
990                                                                                                   const CubeFaceFloatCoords&    coords,
991                                                                                                   const Vec2&                                   fBounds,
992                                                                                                   const float                                   cmpReference,
993                                                                                                   const float                                   result)
994 {
995         if (levelFilter == Sampler::LINEAR)
996         {
997                 if (sampler.seamlessCubeMap)
998                         return isSeamplessLinearMipmapLinearCompareResultValid(texture, baseLevelNdx, sampler, prec, coords, fBounds, cmpReference, result);
999                 else
1000                         return isLinearMipmapLinearCompareResultValid(texture.getLevelFace(baseLevelNdx,        coords.face),
1001                                                                                                                   texture.getLevelFace(baseLevelNdx+1,  coords.face),
1002                                                                                                                   sampler, prec, Vec2(coords.s, coords.t), 0, fBounds, cmpReference, result);
1003         }
1004         else
1005                 return isNearestMipmapLinearCompareResultValid(texture.getLevelFace(baseLevelNdx,       coords.face),
1006                                                                                                            texture.getLevelFace(baseLevelNdx+1, coords.face),
1007                                                                                                            sampler, prec, Vec2(coords.s, coords.t), 0, fBounds, cmpReference, result);
1008 }
1009
1010 static bool isSeamlessLinearCompareResultValid (const TextureCubeView&          texture,
1011                                                                                                 const int                                       levelNdx,
1012                                                                                                 const Sampler&                          sampler,
1013                                                                                                 const TexComparePrecision&      prec,
1014                                                                                                 const CubeFaceFloatCoords&      coords,
1015                                                                                                 const float                                     cmpReference,
1016                                                                                                 const float                                     result)
1017 {
1018         const bool      isFixedPointDepth       = isFixedPointDepthTextureFormat(texture.getLevelFace(levelNdx, CUBEFACE_NEGATIVE_X).getFormat());
1019         const int       size                            = texture.getLevelFace(levelNdx, coords.face).getWidth();
1020
1021         const Vec2      uBounds                         = computeNonNormalizedCoordBounds(sampler.normalizedCoords, size, coords.s, prec.coordBits.x(), prec.uvwBits.x());
1022         const Vec2      vBounds                         = computeNonNormalizedCoordBounds(sampler.normalizedCoords, size, coords.t, prec.coordBits.y(), prec.uvwBits.y());
1023
1024         // Integer coordinate bounds for (x0,y0) - without wrap mode
1025         const int       minI                            = deFloorFloatToInt32(uBounds.x()-0.5f);
1026         const int       maxI                            = deFloorFloatToInt32(uBounds.y()-0.5f);
1027         const int       minJ                            = deFloorFloatToInt32(vBounds.x()-0.5f);
1028         const int       maxJ                            = deFloorFloatToInt32(vBounds.y()-0.5f);
1029
1030         // Face accesses
1031         ConstPixelBufferAccess faces[CUBEFACE_LAST];
1032         for (int face = 0; face < CUBEFACE_LAST; face++)
1033                 faces[face] = texture.getLevelFace(levelNdx, CubeFace(face));
1034
1035         for (int j = minJ; j <= maxJ; j++)
1036         {
1037                 for (int i = minI; i <= maxI; i++)
1038                 {
1039                         const CubeFaceIntCoords c00     = remapCubeEdgeCoords(CubeFaceIntCoords(coords.face, IVec2(i+0, j+0)), size);
1040                         const CubeFaceIntCoords c10     = remapCubeEdgeCoords(CubeFaceIntCoords(coords.face, IVec2(i+1, j+0)), size);
1041                         const CubeFaceIntCoords c01     = remapCubeEdgeCoords(CubeFaceIntCoords(coords.face, IVec2(i+0, j+1)), size);
1042                         const CubeFaceIntCoords c11     = remapCubeEdgeCoords(CubeFaceIntCoords(coords.face, IVec2(i+1, j+1)), size);
1043
1044                         // If any of samples is out of both edges, implementations can do pretty much anything according to spec.
1045                         // \todo [2013-07-08 pyry] Test the special case where all corner pixels have exactly the same color.
1046                         if (c00.face == CUBEFACE_LAST || c01.face == CUBEFACE_LAST || c10.face == CUBEFACE_LAST || c11.face == CUBEFACE_LAST)
1047                                 return true;
1048
1049                         // Bounds for filtering factors
1050                         const float     minA    = de::clamp((uBounds.x()-0.5f)-float(i), 0.0f, 1.0f);
1051                         const float     maxA    = de::clamp((uBounds.y()-0.5f)-float(i), 0.0f, 1.0f);
1052                         const float     minB    = de::clamp((vBounds.x()-0.5f)-float(j), 0.0f, 1.0f);
1053                         const float     maxB    = de::clamp((vBounds.y()-0.5f)-float(j), 0.0f, 1.0f);
1054
1055                         Vec4 depths;
1056                         depths[0] = lookupDepthNoBorder(faces[c00.face], sampler, c00.s, c00.t);
1057                         depths[1] = lookupDepthNoBorder(faces[c10.face], sampler, c10.s, c10.t);
1058                         depths[2] = lookupDepthNoBorder(faces[c01.face], sampler, c01.s, c01.t);
1059                         depths[3] = lookupDepthNoBorder(faces[c11.face], sampler, c11.s, c11.t);
1060
1061                         if (isBilinearCompareValid(sampler.compare, prec, depths, Vec2(minA, maxA), Vec2(minB, maxB), cmpReference, result, isFixedPointDepth))
1062                                 return true;
1063                 }
1064         }
1065
1066         return false;
1067 }
1068
1069 static bool isCubeLevelCompareResultValid (const TextureCubeView&                       texture,
1070                                                                                    const int                                            levelNdx,
1071                                                                                    const Sampler&                                       sampler,
1072                                                                                    const Sampler::FilterMode            filterMode,
1073                                                                                    const TexComparePrecision&           prec,
1074                                                                                    const CubeFaceFloatCoords&           coords,
1075                                                                                    const float                                          cmpReference,
1076                                                                                    const float                                          result)
1077 {
1078         if (filterMode == Sampler::LINEAR)
1079         {
1080                 if (sampler.seamlessCubeMap)
1081                         return isSeamlessLinearCompareResultValid(texture, levelNdx, sampler, prec, coords, cmpReference, result);
1082                 else
1083                         return isLinearCompareResultValid(texture.getLevelFace(levelNdx, coords.face), sampler, prec, Vec2(coords.s, coords.t), 0, cmpReference, result);
1084         }
1085         else
1086                 return isNearestCompareResultValid(texture.getLevelFace(levelNdx, coords.face), sampler, prec, Vec2(coords.s, coords.t), 0, cmpReference, result);
1087 }
1088
1089 static bool isCubeLevelCompareResultValid (const TextureCubeArrayView&  texture,
1090                                                                                    const int                                    baseLevelNdx,
1091                                                                                    const Sampler&                               sampler,
1092                                                                                    const Sampler::FilterMode    filterMode,
1093                                                                                    const TexComparePrecision&   prec,
1094                                                                                    const CubeFaceFloatCoords&   coords,
1095                                                                                    const float                                  depth,
1096                                                                                    const float                                  cmpReference,
1097                                                                                    const float                                  result)
1098 {
1099         const float     depthErr        = computeFloatingPointError(depth, prec.coordBits.z()) + computeFixedPointError(prec.uvwBits.z());
1100         const float     minZ            = depth - depthErr;
1101         const float     maxZ            = depth + depthErr;
1102         const int       minLayer        = de::clamp(deFloorFloatToInt32(minZ + 0.5f), 0, texture.getNumLayers() - 1);
1103         const int       maxLayer        = de::clamp(deFloorFloatToInt32(maxZ + 0.5f), 0, texture.getNumLayers() - 1);
1104         const int       numLevels       = texture.getNumLevels();
1105
1106         for (int layer = minLayer; layer <= maxLayer; layer++)
1107         {
1108                 std::vector<tcu::ConstPixelBufferAccess>        levelsAtLayer[CUBEFACE_LAST];
1109
1110                 for (int faceNdx = 0; faceNdx < CUBEFACE_LAST; faceNdx++)
1111                 {
1112                         levelsAtLayer[faceNdx].resize(numLevels);
1113
1114                         for (int levelNdx = 0; levelNdx < numLevels; ++levelNdx)
1115                         {
1116                                 const tcu::ConstPixelBufferAccess&      level   = texture.getLevel(levelNdx);
1117
1118                                 levelsAtLayer[faceNdx][levelNdx] = ConstPixelBufferAccess(level.getFormat(), level.getWidth(), level.getHeight(), 1, level.getPixelPtr(0, 0, CUBEFACE_LAST * layer + faceNdx));
1119                         }
1120                 }
1121
1122                 const tcu::ConstPixelBufferAccess*      levels[CUBEFACE_LAST]
1123                 {
1124                         // Such a strange order due to sampleCompare TextureCubeArrayView uses getCubeArrayFaceIndex while in TextureCubeView does not
1125                         &levelsAtLayer[1][0],
1126                         &levelsAtLayer[0][0],
1127                         &levelsAtLayer[3][0],
1128                         &levelsAtLayer[2][0],
1129                         &levelsAtLayer[5][0],
1130                         &levelsAtLayer[4][0],
1131                 };
1132
1133                 if (isCubeLevelCompareResultValid(TextureCubeView(numLevels, levels), baseLevelNdx, sampler, filterMode, prec, coords, cmpReference, result))
1134                         return true;
1135         }
1136
1137         return false;
1138 }
1139
1140 static bool isCubeMipmapLinearCompareResultValid (const TextureCubeArrayView&   texture,
1141                                                                                                   const int                                             baseLevelNdx,
1142                                                                                                   const Sampler&                                sampler,
1143                                                                                                   const Sampler::FilterMode             levelFilter,
1144                                                                                                   const TexComparePrecision&    prec,
1145                                                                                                   const CubeFaceFloatCoords&    coords,
1146                                                                                                   const float                                   depth,
1147                                                                                                   const Vec2&                                   fBounds,
1148                                                                                                   const float                                   cmpReference,
1149                                                                                                   const float                                   result)
1150 {
1151         const float     depthErr        = computeFloatingPointError(depth, prec.coordBits.z()) + computeFixedPointError(prec.uvwBits.z());
1152         const float     minZ            = depth - depthErr;
1153         const float     maxZ            = depth + depthErr;
1154         const int       minLayer        = de::clamp(deFloorFloatToInt32(minZ + 0.5f), 0, texture.getNumLayers() - 1);
1155         const int       maxLayer        = de::clamp(deFloorFloatToInt32(maxZ + 0.5f), 0, texture.getNumLayers() - 1);
1156         const int       numLevels       = texture.getNumLevels();
1157
1158         for (int layer = minLayer; layer <= maxLayer; layer++)
1159         {
1160                 std::vector<tcu::ConstPixelBufferAccess>        levelsAtLayer[CUBEFACE_LAST];
1161
1162                 for (int faceNdx = 0; faceNdx < CUBEFACE_LAST; faceNdx++)
1163                 {
1164                         levelsAtLayer[faceNdx].resize(numLevels);
1165
1166                         for (int levelNdx = 0; levelNdx < numLevels; ++levelNdx)
1167                         {
1168                                 const tcu::ConstPixelBufferAccess&      level   = texture.getLevel(levelNdx);
1169
1170                                 levelsAtLayer[faceNdx][levelNdx] = ConstPixelBufferAccess(level.getFormat(), level.getWidth(), level.getHeight(), 1, level.getPixelPtr(0, 0, CUBEFACE_LAST * layer + faceNdx));
1171                         }
1172                 }
1173
1174                 const tcu::ConstPixelBufferAccess*      levels[CUBEFACE_LAST]
1175                 {
1176                         // Such a strange order due to sampleCompare TextureCubeArrayView uses getCubeArrayFaceIndex while in TextureCubeView does not
1177                         &levelsAtLayer[1][0],
1178                         &levelsAtLayer[0][0],
1179                         &levelsAtLayer[3][0],
1180                         &levelsAtLayer[2][0],
1181                         &levelsAtLayer[5][0],
1182                         &levelsAtLayer[4][0],
1183                 };
1184
1185                 if (isCubeMipmapLinearCompareResultValid(TextureCubeView(numLevels, levels), baseLevelNdx, sampler, levelFilter, prec, coords, fBounds, cmpReference, result))
1186                         return true;
1187         }
1188
1189         return false;
1190 }
1191
1192 static bool isNearestCompareResultValid (const ConstPixelBufferAccess&          level,
1193                                                                                  const Sampler&                                         sampler,
1194                                                                                  const TexComparePrecision&                     prec,
1195                                                                                  const Vec1&                                            coord,
1196                                                                                  const int                                                      coordZ,
1197                                                                                  const float                                            cmpReference,
1198                                                                                  const float                                            result)
1199 {
1200         const bool      isFixedPointDepth       = isFixedPointDepthTextureFormat(level.getFormat());
1201         const Vec2      uBounds                         = computeNonNormalizedCoordBounds(sampler.normalizedCoords, level.getWidth(), coord.x(), prec.coordBits.x(), prec.uvwBits.x());
1202
1203         // Integer coordinates - without wrap mode
1204         const int       minI                            = deFloorFloatToInt32(uBounds.x());
1205         const int       maxI                            = deFloorFloatToInt32(uBounds.y());
1206
1207         for (int i = minI; i <= maxI; i++)
1208         {
1209                 const int                       x               = wrap(sampler.wrapS, i, level.getWidth());
1210                 const float                     depth   = lookupDepth(level, sampler, x, coordZ, 0);
1211                 const CmpResultSet      resSet  = execCompare(sampler.compare, depth, cmpReference, prec.referenceBits, isFixedPointDepth);
1212
1213                 if (isResultInSet(resSet, result, prec.resultBits))
1214                         return true;
1215         }
1216
1217         return false;
1218 }
1219
1220 static bool isLinearCompareResultValid (const ConstPixelBufferAccess&           level,
1221                                                                                 const Sampler&                                          sampler,
1222                                                                                 const TexComparePrecision&                      prec,
1223                                                                                 const Vec1&                                                     coord,
1224                                                                                 const int                                                       coordZ,
1225                                                                                 const float                                                     cmpReference,
1226                                                                                 const float                                                     result)
1227 {
1228         const bool      isFixedPointDepth       = isFixedPointDepthTextureFormat(level.getFormat());
1229         const Vec2      uBounds                         = computeNonNormalizedCoordBounds(sampler.normalizedCoords, level.getWidth(), coord.x(), prec.coordBits.x(), prec.uvwBits.x());
1230
1231         // Integer coordinate bounds for (x0,y0) - without wrap mode
1232         const int       minI                            = deFloorFloatToInt32(uBounds.x() - 0.5f);
1233         const int       maxI                            = deFloorFloatToInt32(uBounds.y() - 0.5f);
1234
1235         const int       w                                       = level.getWidth();
1236
1237         // \todo [2013-07-03 pyry] This could be optimized by first computing ranges based on wrap mode.
1238
1239         for (int i = minI; i <= maxI; i++)
1240         {
1241                 // Wrapped coordinates
1242                 const int       x0              = wrap(sampler.wrapS, i    , w);
1243                 const int       x1              = wrap(sampler.wrapS, i + 1, w);
1244
1245                 // Bounds for filtering factors
1246                 const float     minA    = de::clamp((uBounds.x() - 0.5f) - float(i), 0.0f, 1.0f);
1247                 const float     maxA    = de::clamp((uBounds.y() - 0.5f) - float(i), 0.0f, 1.0f);
1248
1249                 const Vec2      depths  (lookupDepth(level, sampler, x0, coordZ, 0),
1250                                                          lookupDepth(level, sampler, x1, coordZ, 0));
1251
1252                 if (isLinearCompareValid(sampler.compare, prec, depths, Vec2(minA, maxA), cmpReference, result, isFixedPointDepth))
1253                         return true;
1254         }
1255
1256         return false;
1257 }
1258
1259 static bool isLevelCompareResultValid (const ConstPixelBufferAccess&    level,
1260                                                                            const Sampler&                                       sampler,
1261                                                                            const Sampler::FilterMode            filterMode,
1262                                                                            const TexComparePrecision&           prec,
1263                                                                            const Vec1&                                          coord,
1264                                                                            const int                                            coordZ,
1265                                                                            const float                                          cmpReference,
1266                                                                            const float                                          result)
1267 {
1268         if (filterMode == Sampler::LINEAR)
1269                 return isLinearCompareResultValid(level, sampler, prec, coord, coordZ, cmpReference, result);
1270         else
1271                 return isNearestCompareResultValid(level, sampler, prec, coord, coordZ, cmpReference, result);
1272 }
1273
1274 static bool isNearestMipmapLinearCompareResultValid (const ConstPixelBufferAccess&      level0,
1275                                                                                                          const ConstPixelBufferAccess&  level1,
1276                                                                                                          const Sampler&                                 sampler,
1277                                                                                                          const TexComparePrecision&             prec,
1278                                                                                                          const Vec1&                                    coord,
1279                                                                                                          const int                                              coordZ,
1280                                                                                                          const Vec2&                                    fBounds,
1281                                                                                                          const float                                    cmpReference,
1282                                                                                                          const float                                    result)
1283 {
1284         DE_UNREF(fBounds);
1285         const bool      isFixedPointDepth       = isFixedPointDepthTextureFormat(level0.getFormat());
1286
1287         const int       w0                                      = level0.getWidth();
1288         const int       w1                                      = level1.getWidth();
1289
1290         const Vec2      uBounds0                        = computeNonNormalizedCoordBounds(sampler.normalizedCoords, w0, coord.x(), prec.coordBits.x(), prec.uvwBits.x());
1291         const Vec2      uBounds1                        = computeNonNormalizedCoordBounds(sampler.normalizedCoords, w1, coord.x(), prec.coordBits.x(), prec.uvwBits.x());
1292
1293         // Integer coordinates - without wrap mode
1294         const int       minI0                           = deFloorFloatToInt32(uBounds0.x());
1295         const int       maxI0                           = deFloorFloatToInt32(uBounds0.y());
1296         const int       minI1                           = deFloorFloatToInt32(uBounds1.x());
1297         const int       maxI1                           = deFloorFloatToInt32(uBounds1.y());
1298
1299         for (int i0 = minI0; i0 <= maxI0; i0++)
1300         {
1301                 const float     depth0  = lookupDepth(level0, sampler, wrap(sampler.wrapS, i0, w0), coordZ, 0);
1302
1303                 for (int i1 = minI1; i1 <= maxI1; i1++)
1304                 {
1305                         const float     depth1  = lookupDepth(level1, sampler, wrap(sampler.wrapS, i1, w1), coordZ, 0);
1306
1307                         if (isLinearCompareValid(sampler.compare, prec, Vec2(depth0, depth1), fBounds, cmpReference, result, isFixedPointDepth))
1308                                 return true;
1309                 }
1310         }
1311
1312         return false;
1313 }
1314
1315
1316 static bool isLinearMipmapLinearCompareResultValid (const ConstPixelBufferAccess&       level0,
1317                                                                                                         const ConstPixelBufferAccess&   level1,
1318                                                                                                         const Sampler&                                  sampler,
1319                                                                                                         const TexComparePrecision&              prec,
1320                                                                                                         const Vec1&                                             coord,
1321                                                                                                         const int                                               coordZ,
1322                                                                                                         const Vec2&                                             fBounds,
1323                                                                                                         const float                                             cmpReference,
1324                                                                                                         const float                                             result)
1325 {
1326         DE_UNREF(fBounds);
1327         const bool      isFixedPointDepth       = isFixedPointDepthTextureFormat(level0.getFormat());
1328
1329         // \todo [2013-07-04 pyry] This is strictly not correct as coordinates between levels should be dependent.
1330         //                                                 Right now this allows pairing any two valid bilinear quads.
1331
1332         const int       w0                                      = level0.getWidth();
1333         const int       w1                                      = level1.getWidth();
1334
1335         const Vec2      uBounds0                        = computeNonNormalizedCoordBounds(sampler.normalizedCoords, w0, coord.x(), prec.coordBits.x(), prec.uvwBits.x());
1336         const Vec2      uBounds1                        = computeNonNormalizedCoordBounds(sampler.normalizedCoords, w1, coord.x(), prec.coordBits.x(), prec.uvwBits.x());
1337
1338         // Integer coordinates - without wrap mode
1339         const int       minI0                           = deFloorFloatToInt32(uBounds0.x()-0.5f);
1340         const int       maxI0                           = deFloorFloatToInt32(uBounds0.y()-0.5f);
1341         const int       minI1                           = deFloorFloatToInt32(uBounds1.x()-0.5f);
1342         const int       maxI1                           = deFloorFloatToInt32(uBounds1.y()-0.5f);
1343
1344         for (int i0 = minI0; i0 <= maxI0; i0++)
1345         {
1346                 const float     minA0   = de::clamp((uBounds0.x() - 0.5f) - float(i0), 0.0f, 1.0f);
1347                 const float     maxA0   = de::clamp((uBounds0.y() - 0.5f) - float(i0), 0.0f, 1.0f);
1348                 const Vec2      ptA0    = Vec2(minA0, maxA0);
1349                 Vec4            depths;
1350
1351                 {
1352                         const int       x0              = wrap(sampler.wrapS, i0    , w0);
1353                         const int       x1              = wrap(sampler.wrapS, i0 + 1, w0);
1354
1355                         depths[0] = lookupDepth(level0, sampler, x0, coordZ, 0);
1356                         depths[1] = lookupDepth(level0, sampler, x1, coordZ, 0);
1357                 }
1358
1359                 for (int i1 = minI1; i1 <= maxI1; i1++)
1360                 {
1361                         const float     minA1   = de::clamp((uBounds1.x() - 0.5f) - float(i1), 0.0f, 1.0f);
1362                         const float     maxA1   = de::clamp((uBounds1.y() - 0.5f) - float(i1), 0.0f, 1.0f);
1363                         const Vec2      ptA1    = Vec2(minA1, maxA1);
1364
1365                         {
1366                                 const int       x0              = wrap(sampler.wrapS, i1    , w1);
1367                                 const int       x1              = wrap(sampler.wrapS, i1 + 1, w1);
1368
1369                                 depths[2] = lookupDepth(level1, sampler, x0, coordZ, 0);
1370                                 depths[3] = lookupDepth(level1, sampler, x1, coordZ, 0);
1371                         }
1372
1373                         if (isBilinearCompareValid(sampler.compare,
1374                                                                            prec,
1375                                                                            depths,
1376                                                                            ptA0,
1377                                                                            ptA1,
1378                                                                            cmpReference,
1379                                                                            result,
1380                                                                            isFixedPointDepth))
1381                                 return true;
1382                 }
1383         }
1384
1385         return false;
1386 }
1387
1388 static bool isMipmapLinearCompareResultValid (const ConstPixelBufferAccess&             level0,
1389                                                                                           const ConstPixelBufferAccess&         level1,
1390                                                                                           const Sampler&                                        sampler,
1391                                                                                           const Sampler::FilterMode                     levelFilter,
1392                                                                                           const TexComparePrecision&            prec,
1393                                                                                           const Vec1&                                           coord,
1394                                                                                           const int                                                     coordZ,
1395                                                                                           const Vec2&                                           fBounds,
1396                                                                                           const float                                           cmpReference,
1397                                                                                           const float                                           result)
1398 {
1399         if (levelFilter == Sampler::LINEAR)
1400                 return isLinearMipmapLinearCompareResultValid(level0, level1, sampler, prec, coord, coordZ, fBounds, cmpReference, result);
1401         else
1402                 return isNearestMipmapLinearCompareResultValid(level0, level1, sampler, prec, coord, coordZ, fBounds, cmpReference, result);
1403 }
1404
1405 bool isTexCompareResultValid (const TextureCubeView& texture, const Sampler& sampler, const TexComparePrecision& prec, const Vec3& coord, const Vec2& lodBounds, const float cmpReference, const float result)
1406 {
1407         int                     numPossibleFaces                                = 0;
1408         CubeFace        possibleFaces[CUBEFACE_LAST];
1409
1410         DE_ASSERT(isSamplerSupported(sampler));
1411
1412         getPossibleCubeFaces(coord, prec.coordBits, &possibleFaces[0], numPossibleFaces);
1413
1414         if (numPossibleFaces == 0)
1415                 return true; // Result is undefined.
1416
1417         for (int tryFaceNdx = 0; tryFaceNdx < numPossibleFaces; tryFaceNdx++)
1418         {
1419                 const CubeFaceFloatCoords       faceCoords              (possibleFaces[tryFaceNdx], projectToFace(possibleFaces[tryFaceNdx], coord));
1420                 const float                                     minLod                  = lodBounds.x();
1421                 const float                                     maxLod                  = lodBounds.y();
1422                 const bool                                      canBeMagnified  = minLod <= sampler.lodThreshold;
1423                 const bool                                      canBeMinified   = maxLod > sampler.lodThreshold;
1424
1425                 if (canBeMagnified)
1426                 {
1427                         if (isCubeLevelCompareResultValid(texture, 0, sampler, sampler.magFilter, prec, faceCoords, cmpReference, result))
1428                                 return true;
1429                 }
1430
1431                 if (canBeMinified)
1432                 {
1433                         const bool      isNearestMipmap = isNearestMipmapFilter(sampler.minFilter);
1434                         const bool      isLinearMipmap  = isLinearMipmapFilter(sampler.minFilter);
1435                         const int       minTexLevel             = 0;
1436                         const int       maxTexLevel             = texture.getNumLevels()-1;
1437
1438                         DE_ASSERT(minTexLevel < maxTexLevel);
1439
1440                         if (isLinearMipmap)
1441                         {
1442                                 const int               minLevel                = de::clamp((int)deFloatFloor(minLod), minTexLevel, maxTexLevel-1);
1443                                 const int               maxLevel                = de::clamp((int)deFloatFloor(maxLod), minTexLevel, maxTexLevel-1);
1444
1445                                 DE_ASSERT(minLevel <= maxLevel);
1446
1447                                 for (int level = minLevel; level <= maxLevel; level++)
1448                                 {
1449                                         const float             minF    = de::clamp(minLod - float(level), 0.0f, 1.0f);
1450                                         const float             maxF    = de::clamp(maxLod - float(level), 0.0f, 1.0f);
1451
1452                                         if (isCubeMipmapLinearCompareResultValid(texture, level, sampler, getLevelFilter(sampler.minFilter), prec, faceCoords, Vec2(minF, maxF), cmpReference, result))
1453                                                 return true;
1454                                 }
1455                         }
1456                         else if (isNearestMipmap)
1457                         {
1458                                 // \note The accurate formula for nearest mipmapping is level = ceil(lod + 0.5) - 1 but Khronos has made
1459                                 //               decision to allow floor(lod + 0.5) as well.
1460                                 const int               minLevel                = de::clamp((int)deFloatCeil(minLod + 0.5f) - 1,        minTexLevel, maxTexLevel);
1461                                 const int               maxLevel                = de::clamp((int)deFloatFloor(maxLod + 0.5f),           minTexLevel, maxTexLevel);
1462
1463                                 DE_ASSERT(minLevel <= maxLevel);
1464
1465                                 for (int level = minLevel; level <= maxLevel; level++)
1466                                 {
1467                                         if (isCubeLevelCompareResultValid(texture, level, sampler, getLevelFilter(sampler.minFilter), prec, faceCoords, cmpReference, result))
1468                                                 return true;
1469                                 }
1470                         }
1471                         else
1472                         {
1473                                 if (isCubeLevelCompareResultValid(texture, 0, sampler, sampler.minFilter, prec, faceCoords, cmpReference, result))
1474                                         return true;
1475                         }
1476                 }
1477         }
1478
1479         return false;
1480 }
1481
1482 bool isTexCompareResultValid (const Texture2DArrayView& texture, const Sampler& sampler, const TexComparePrecision& prec, const Vec3& coord, const Vec2& lodBounds, const float cmpReference, const float result)
1483 {
1484         const float             depthErr        = computeFloatingPointError(coord.z(), prec.coordBits.z()) + computeFixedPointError(prec.uvwBits.z());
1485         const float             minZ            = coord.z()-depthErr;
1486         const float             maxZ            = coord.z()+depthErr;
1487         const int               minLayer        = de::clamp(deFloorFloatToInt32(minZ + 0.5f), 0, texture.getNumLayers()-1);
1488         const int               maxLayer        = de::clamp(deFloorFloatToInt32(maxZ + 0.5f), 0, texture.getNumLayers()-1);
1489
1490         DE_ASSERT(isSamplerSupported(sampler));
1491
1492         for (int layer = minLayer; layer <= maxLayer; layer++)
1493         {
1494                 const float             minLod                  = lodBounds.x();
1495                 const float             maxLod                  = lodBounds.y();
1496                 const bool              canBeMagnified  = minLod <= sampler.lodThreshold;
1497                 const bool              canBeMinified   = maxLod > sampler.lodThreshold;
1498
1499                 if (canBeMagnified)
1500                 {
1501                         if (isLevelCompareResultValid(texture.getLevel(0), sampler, sampler.magFilter, prec, coord.swizzle(0,1), layer, cmpReference, result))
1502                                 return true;
1503                 }
1504
1505                 if (canBeMinified)
1506                 {
1507                         const bool      isNearestMipmap = isNearestMipmapFilter(sampler.minFilter);
1508                         const bool      isLinearMipmap  = isLinearMipmapFilter(sampler.minFilter);
1509                         const int       minTexLevel             = 0;
1510                         const int       maxTexLevel             = texture.getNumLevels()-1;
1511
1512                         DE_ASSERT(minTexLevel < maxTexLevel);
1513
1514                         if (isLinearMipmap)
1515                         {
1516                                 const int               minLevel                = de::clamp((int)deFloatFloor(minLod), minTexLevel, maxTexLevel-1);
1517                                 const int               maxLevel                = de::clamp((int)deFloatFloor(maxLod), minTexLevel, maxTexLevel-1);
1518
1519                                 DE_ASSERT(minLevel <= maxLevel);
1520
1521                                 for (int level = minLevel; level <= maxLevel; level++)
1522                                 {
1523                                         const float             minF    = de::clamp(minLod - float(level), 0.0f, 1.0f);
1524                                         const float             maxF    = de::clamp(maxLod - float(level), 0.0f, 1.0f);
1525
1526                                         if (isMipmapLinearCompareResultValid(texture.getLevel(level), texture.getLevel(level+1), sampler, getLevelFilter(sampler.minFilter), prec, coord.swizzle(0,1), layer, Vec2(minF, maxF), cmpReference, result))
1527                                                 return true;
1528                                 }
1529                         }
1530                         else if (isNearestMipmap)
1531                         {
1532                                 // \note The accurate formula for nearest mipmapping is level = ceil(lod + 0.5) - 1 but Khronos has made
1533                                 //               decision to allow floor(lod + 0.5) as well.
1534                                 const int               minLevel                = de::clamp((int)deFloatCeil(minLod + 0.5f) - 1,        minTexLevel, maxTexLevel);
1535                                 const int               maxLevel                = de::clamp((int)deFloatFloor(maxLod + 0.5f),           minTexLevel, maxTexLevel);
1536
1537                                 DE_ASSERT(minLevel <= maxLevel);
1538
1539                                 for (int level = minLevel; level <= maxLevel; level++)
1540                                 {
1541                                         if (isLevelCompareResultValid(texture.getLevel(level), sampler, getLevelFilter(sampler.minFilter), prec, coord.swizzle(0,1), layer, cmpReference, result))
1542                                                 return true;
1543                                 }
1544                         }
1545                         else
1546                         {
1547                                 if (isLevelCompareResultValid(texture.getLevel(0), sampler, sampler.minFilter, prec, coord.swizzle(0,1), layer, cmpReference, result))
1548                                         return true;
1549                         }
1550                 }
1551         }
1552
1553         return false;
1554 }
1555
1556 bool isTexCompareResultValid (const Texture1DView&                      texture,
1557                                                           const Sampler&                                sampler,
1558                                                           const TexComparePrecision&    prec,
1559                                                           const Vec1&                                   coord,
1560                                                           const Vec2&                                   lodBounds,
1561                                                           const float                                   cmpReference,
1562                                                           const float                                   result)
1563 {
1564         const float             minLod                  = lodBounds.x();
1565         const float             maxLod                  = lodBounds.y();
1566         const bool              canBeMagnified  = minLod <= sampler.lodThreshold;
1567         const bool              canBeMinified   = maxLod > sampler.lodThreshold;
1568
1569         DE_ASSERT(isSamplerSupported(sampler));
1570
1571         if (canBeMagnified)
1572         {
1573                 if (isLevelCompareResultValid(texture.getLevel(0), sampler, sampler.magFilter, prec, coord, 0, cmpReference, result))
1574                         return true;
1575         }
1576
1577         if (canBeMinified)
1578         {
1579                 const bool      isNearestMipmap = isNearestMipmapFilter(sampler.minFilter);
1580                 const bool      isLinearMipmap  = isLinearMipmapFilter(sampler.minFilter);
1581                 const int       minTexLevel             = 0;
1582                 const int       maxTexLevel             = texture.getNumLevels()-1;
1583
1584                 DE_ASSERT(minTexLevel < maxTexLevel);
1585
1586                 if (isLinearMipmap)
1587                 {
1588                         const int               minLevel                = de::clamp((int)deFloatFloor(minLod), minTexLevel, maxTexLevel-1);
1589                         const int               maxLevel                = de::clamp((int)deFloatFloor(maxLod), minTexLevel, maxTexLevel-1);
1590
1591                         DE_ASSERT(minLevel <= maxLevel);
1592
1593                         for (int level = minLevel; level <= maxLevel; level++)
1594                         {
1595                                 const float             minF    = de::clamp(minLod - float(level), 0.0f, 1.0f);
1596                                 const float             maxF    = de::clamp(maxLod - float(level), 0.0f, 1.0f);
1597
1598                                 if (isMipmapLinearCompareResultValid(texture.getLevel(level), texture.getLevel(level+1), sampler, getLevelFilter(sampler.minFilter), prec, coord, 0, Vec2(minF, maxF), cmpReference, result))
1599                                         return true;
1600                         }
1601                 }
1602                 else if (isNearestMipmap)
1603                 {
1604                         // \note The accurate formula for nearest mipmapping is level = ceil(lod + 0.5) - 1 but Khronos has made
1605                         //               decision to allow floor(lod + 0.5) as well.
1606                         const int               minLevel                = de::clamp((int)deFloatCeil(minLod + 0.5f) - 1,        minTexLevel, maxTexLevel);
1607                         const int               maxLevel                = de::clamp((int)deFloatFloor(maxLod + 0.5f),           minTexLevel, maxTexLevel);
1608
1609                         DE_ASSERT(minLevel <= maxLevel);
1610
1611                         for (int level = minLevel; level <= maxLevel; level++)
1612                         {
1613                                 if (isLevelCompareResultValid(texture.getLevel(level), sampler, getLevelFilter(sampler.minFilter), prec, coord, 0, cmpReference, result))
1614                                         return true;
1615                         }
1616                 }
1617                 else
1618                 {
1619                         if (isLevelCompareResultValid(texture.getLevel(0), sampler, sampler.minFilter, prec, coord, 0, cmpReference, result))
1620                                 return true;
1621                 }
1622         }
1623
1624         return false;
1625 }
1626
1627 bool isTexCompareResultValid (const Texture1DArrayView&         texture,
1628                                                           const Sampler&                                sampler,
1629                                                           const TexComparePrecision&    prec,
1630                                                           const Vec2&                                   coord,
1631                                                           const Vec2&                                   lodBounds,
1632                                                           const float                                   cmpReference,
1633                                                           const float                                   result)
1634 {
1635         const float             depthErr        = computeFloatingPointError(coord.y(), prec.coordBits.y()) + computeFixedPointError(prec.uvwBits.y()); //\todo: should we go with y in prec?
1636         const float             minZ            = coord.y()-depthErr;
1637         const float             maxZ            = coord.y()+depthErr;
1638         const int               minLayer        = de::clamp(deFloorFloatToInt32(minZ + 0.5f), 0, texture.getNumLayers()-1);
1639         const int               maxLayer        = de::clamp(deFloorFloatToInt32(maxZ + 0.5f), 0, texture.getNumLayers()-1);
1640
1641         DE_ASSERT(isSamplerSupported(sampler));
1642
1643         for (int layer = minLayer; layer <= maxLayer; layer++)
1644         {
1645                 const float             minLod                  = lodBounds.x();
1646                 const float             maxLod                  = lodBounds.y();
1647                 const bool              canBeMagnified  = minLod <= sampler.lodThreshold;
1648                 const bool              canBeMinified   = maxLod > sampler.lodThreshold;
1649
1650                 if (canBeMagnified)
1651                 {
1652                         if (isLevelCompareResultValid(texture.getLevel(0), sampler, sampler.magFilter, prec, Vec1(coord.x()), layer, cmpReference, result))
1653                                 return true;
1654                 }
1655
1656                 if (canBeMinified)
1657                 {
1658                         const bool      isNearestMipmap = isNearestMipmapFilter(sampler.minFilter);
1659                         const bool      isLinearMipmap  = isLinearMipmapFilter(sampler.minFilter);
1660                         const int       minTexLevel             = 0;
1661                         const int       maxTexLevel             = texture.getNumLevels()-1;
1662
1663                         DE_ASSERT(minTexLevel < maxTexLevel);
1664
1665                         if (isLinearMipmap)
1666                         {
1667                                 const int               minLevel                = de::clamp((int)deFloatFloor(minLod), minTexLevel, maxTexLevel-1);
1668                                 const int               maxLevel                = de::clamp((int)deFloatFloor(maxLod), minTexLevel, maxTexLevel-1);
1669
1670                                 DE_ASSERT(minLevel <= maxLevel);
1671
1672                                 for (int level = minLevel; level <= maxLevel; level++)
1673                                 {
1674                                         const float             minF    = de::clamp(minLod - float(level), 0.0f, 1.0f);
1675                                         const float             maxF    = de::clamp(maxLod - float(level), 0.0f, 1.0f);
1676
1677                                         if (isMipmapLinearCompareResultValid(texture.getLevel(level), texture.getLevel(level+1), sampler, getLevelFilter(sampler.minFilter), prec, Vec1(coord.x()), layer, Vec2(minF, maxF), cmpReference, result))
1678                                                 return true;
1679                                 }
1680                         }
1681                         else if (isNearestMipmap)
1682                         {
1683                                 // \note The accurate formula for nearest mipmapping is level = ceil(lod + 0.5) - 1 but Khronos has made
1684                                 //               decision to allow floor(lod + 0.5) as well.
1685                                 const int               minLevel                = de::clamp((int)deFloatCeil(minLod + 0.5f) - 1,        minTexLevel, maxTexLevel);
1686                                 const int               maxLevel                = de::clamp((int)deFloatFloor(maxLod + 0.5f),           minTexLevel, maxTexLevel);
1687
1688                                 DE_ASSERT(minLevel <= maxLevel);
1689
1690                                 for (int level = minLevel; level <= maxLevel; level++)
1691                                 {
1692                                         if (isLevelCompareResultValid(texture.getLevel(level), sampler, getLevelFilter(sampler.minFilter), prec, Vec1(coord.x()), layer, cmpReference, result))
1693                                                 return true;
1694                                 }
1695                         }
1696                         else
1697                         {
1698                                 if (isLevelCompareResultValid(texture.getLevel(0), sampler, sampler.minFilter, prec, Vec1(coord.x()), layer, cmpReference, result))
1699                                         return true;
1700                         }
1701                 }
1702         }
1703
1704         return false;
1705 }
1706
1707 bool isTexCompareResultValid (const TextureCubeArrayView& texture, const Sampler& sampler, const TexComparePrecision& prec, const Vec4& coord, const Vec2& lodBounds, const float cmpReference, const float result)
1708 {
1709         const Vec3      coord3                                                  = coord.swizzle(0,1,2);
1710         int                     numPossibleFaces                                = 0;
1711         CubeFace        possibleFaces[CUBEFACE_LAST];
1712
1713         DE_ASSERT(isSamplerSupported(sampler));
1714
1715         getPossibleCubeFaces(coord3, prec.coordBits, &possibleFaces[0], numPossibleFaces);
1716
1717         if (numPossibleFaces == 0)
1718                 return true; // Result is undefined.
1719
1720         for (int tryFaceNdx = 0; tryFaceNdx < numPossibleFaces; tryFaceNdx++)
1721         {
1722                 const CubeFaceFloatCoords       faceCoords              (possibleFaces[tryFaceNdx], projectToFace(possibleFaces[tryFaceNdx], coord3));
1723                 const float                                     minLod                  = lodBounds.x();
1724                 const float                                     maxLod                  = lodBounds.y();
1725                 const bool                                      canBeMagnified  = minLod <= sampler.lodThreshold;
1726                 const bool                                      canBeMinified   = maxLod > sampler.lodThreshold;
1727
1728                 if (canBeMagnified)
1729                 {
1730                         if (isCubeLevelCompareResultValid(texture, 0, sampler, sampler.magFilter, prec, faceCoords, coord.w(), cmpReference, result))
1731                                 return true;
1732                 }
1733
1734                 if (canBeMinified)
1735                 {
1736                         const bool      isNearestMipmap = isNearestMipmapFilter(sampler.minFilter);
1737                         const bool      isLinearMipmap  = isLinearMipmapFilter(sampler.minFilter);
1738                         const int       minTexLevel             = 0;
1739                         const int       maxTexLevel             = texture.getNumLevels()-1;
1740
1741                         DE_ASSERT(minTexLevel < maxTexLevel);
1742
1743                         if (isLinearMipmap)
1744                         {
1745                                 const int               minLevel                = de::clamp((int)deFloatFloor(minLod), minTexLevel, maxTexLevel-1);
1746                                 const int               maxLevel                = de::clamp((int)deFloatFloor(maxLod), minTexLevel, maxTexLevel-1);
1747
1748                                 DE_ASSERT(minLevel <= maxLevel);
1749
1750                                 for (int level = minLevel; level <= maxLevel; level++)
1751                                 {
1752                                         const float             minF    = de::clamp(minLod - float(level), 0.0f, 1.0f);
1753                                         const float             maxF    = de::clamp(maxLod - float(level), 0.0f, 1.0f);
1754
1755                                         if (isCubeMipmapLinearCompareResultValid(texture, level, sampler, getLevelFilter(sampler.minFilter), prec, faceCoords, coord.w(), Vec2(minF, maxF), cmpReference, result))
1756                                                 return true;
1757                                 }
1758                         }
1759                         else if (isNearestMipmap)
1760                         {
1761                                 // \note The accurate formula for nearest mipmapping is level = ceil(lod + 0.5) - 1 but Khronos has made
1762                                 //               decision to allow floor(lod + 0.5) as well.
1763                                 const int               minLevel                = de::clamp((int)deFloatCeil(minLod + 0.5f) - 1,        minTexLevel, maxTexLevel);
1764                                 const int               maxLevel                = de::clamp((int)deFloatFloor(maxLod + 0.5f),           minTexLevel, maxTexLevel);
1765
1766                                 DE_ASSERT(minLevel <= maxLevel);
1767
1768                                 for (int level = minLevel; level <= maxLevel; level++)
1769                                 {
1770                                         if (isCubeLevelCompareResultValid(texture, level, sampler, getLevelFilter(sampler.minFilter), prec, faceCoords, coord.w(), cmpReference, result))
1771                                                 return true;
1772                                 }
1773                         }
1774                         else
1775                         {
1776                                 if (isCubeLevelCompareResultValid(texture, 0, sampler, sampler.minFilter, prec, faceCoords, coord.w(), cmpReference, result))
1777                                         return true;
1778                         }
1779                 }
1780         }
1781
1782         return false;
1783 }
1784
1785 static bool isGatherOffsetsCompareResultValid (const ConstPixelBufferAccess&    texture,
1786                                                                                            const Sampler&                                       sampler,
1787                                                                                            const TexComparePrecision&           prec,
1788                                                                                            const Vec2&                                          coord,
1789                                                                                            int                                                          coordZ,
1790                                                                                            const IVec2                                          (&offsets)[4],
1791                                                                                            float                                                        cmpReference,
1792                                                                                            const Vec4&                                          result)
1793 {
1794         const bool      isFixedPointDepth       = isFixedPointDepthTextureFormat(texture.getFormat());
1795         const Vec2      uBounds                         = computeNonNormalizedCoordBounds(sampler.normalizedCoords, texture.getWidth(),         coord.x(), prec.coordBits.x(), prec.uvwBits.x());
1796         const Vec2      vBounds                         = computeNonNormalizedCoordBounds(sampler.normalizedCoords, texture.getHeight(),        coord.y(), prec.coordBits.y(), prec.uvwBits.y());
1797
1798         // Integer coordinate bounds for (x0, y0) - without wrap mode
1799         const int       minI                            = deFloorFloatToInt32(uBounds.x()-0.5f);
1800         const int       maxI                            = deFloorFloatToInt32(uBounds.y()-0.5f);
1801         const int       minJ                            = deFloorFloatToInt32(vBounds.x()-0.5f);
1802         const int       maxJ                            = deFloorFloatToInt32(vBounds.y()-0.5f);
1803
1804         const int       w                                       = texture.getWidth();
1805         const int       h                                       = texture.getHeight();
1806
1807         for (int j = minJ; j <= maxJ; j++)
1808         {
1809                 for (int i = minI; i <= maxI; i++)
1810                 {
1811                         bool isCurrentPixelValid = true;
1812
1813                         for (int offNdx = 0; offNdx < 4 && isCurrentPixelValid; offNdx++)
1814                         {
1815                                 // offNdx-th coordinate offset and then wrapped.
1816                                 const int                       x               = wrap(sampler.wrapS, i+offsets[offNdx].x(), w);
1817                                 const int                       y               = wrap(sampler.wrapT, j+offsets[offNdx].y(), h);
1818                                 const float                     depth   = lookupDepth(texture, sampler, x, y, coordZ);
1819                                 const CmpResultSet      resSet  = execCompare(sampler.compare, depth, cmpReference, prec.referenceBits, isFixedPointDepth);
1820
1821                                 if (!isResultInSet(resSet, result[offNdx], prec.resultBits))
1822                                         isCurrentPixelValid = false;
1823                         }
1824
1825                         if (isCurrentPixelValid)
1826                                 return true;
1827                 }
1828         }
1829
1830         return false;
1831 }
1832
1833 bool isGatherOffsetsCompareResultValid (const Texture2DView&            texture,
1834                                                                                 const Sampler&                          sampler,
1835                                                                                 const TexComparePrecision&      prec,
1836                                                                                 const Vec2&                                     coord,
1837                                                                                 const IVec2                                     (&offsets)[4],
1838                                                                                 float                                           cmpReference,
1839                                                                                 const Vec4&                                     result)
1840 {
1841         DE_ASSERT(isSamplerSupported(sampler));
1842
1843         return isGatherOffsetsCompareResultValid(texture.getLevel(0), sampler, prec, coord, 0, offsets, cmpReference, result);
1844 }
1845
1846 bool isGatherOffsetsCompareResultValid (const Texture2DArrayView&       texture,
1847                                                                                 const Sampler&                          sampler,
1848                                                                                 const TexComparePrecision&      prec,
1849                                                                                 const Vec3&                                     coord,
1850                                                                                 const IVec2                                     (&offsets)[4],
1851                                                                                 float                                           cmpReference,
1852                                                                                 const Vec4&                                     result)
1853 {
1854         const float             depthErr        = computeFloatingPointError(coord.z(), prec.coordBits.z()) + computeFixedPointError(prec.uvwBits.z());
1855         const float             minZ            = coord.z()-depthErr;
1856         const float             maxZ            = coord.z()+depthErr;
1857         const int               minLayer        = de::clamp(deFloorFloatToInt32(minZ + 0.5f), 0, texture.getNumLayers()-1);
1858         const int               maxLayer        = de::clamp(deFloorFloatToInt32(maxZ + 0.5f), 0, texture.getNumLayers()-1);
1859
1860         DE_ASSERT(isSamplerSupported(sampler));
1861
1862         for (int layer = minLayer; layer <= maxLayer; layer++)
1863         {
1864                 if (isGatherOffsetsCompareResultValid(texture.getLevel(0), sampler, prec, coord.swizzle(0,1), layer, offsets, cmpReference, result))
1865                         return true;
1866         }
1867         return false;
1868 }
1869
1870 static bool isGatherCompareResultValid (const TextureCubeView&          texture,
1871                                                                                 const Sampler&                          sampler,
1872                                                                                 const TexComparePrecision&      prec,
1873                                                                                 const CubeFaceFloatCoords&      coords,
1874                                                                                 float                                           cmpReference,
1875                                                                                 const Vec4&                                     result)
1876 {
1877         const bool      isFixedPointDepth       = isFixedPointDepthTextureFormat(texture.getLevelFace(0, coords.face).getFormat());
1878         const int       size                            = texture.getLevelFace(0, coords.face).getWidth();
1879         const Vec2      uBounds                         = computeNonNormalizedCoordBounds(sampler.normalizedCoords, size, coords.s, prec.coordBits.x(), prec.uvwBits.x());
1880         const Vec2      vBounds                         = computeNonNormalizedCoordBounds(sampler.normalizedCoords, size, coords.t, prec.coordBits.y(), prec.uvwBits.y());
1881
1882         // Integer coordinate bounds for (x0,y0) - without wrap mode
1883         const int       minI                            = deFloorFloatToInt32(uBounds.x()-0.5f);
1884         const int       maxI                            = deFloorFloatToInt32(uBounds.y()-0.5f);
1885         const int       minJ                            = deFloorFloatToInt32(vBounds.x()-0.5f);
1886         const int       maxJ                            = deFloorFloatToInt32(vBounds.y()-0.5f);
1887
1888         // Face accesses
1889         ConstPixelBufferAccess faces[CUBEFACE_LAST];
1890         for (int face = 0; face < CUBEFACE_LAST; face++)
1891                 faces[face] = texture.getLevelFace(0, CubeFace(face));
1892
1893         for (int j = minJ; j <= maxJ; j++)
1894         {
1895                 for (int i = minI; i <= maxI; i++)
1896                 {
1897                         static const IVec2 offsets[4] =
1898                         {
1899                                 IVec2(0, 1),
1900                                 IVec2(1, 1),
1901                                 IVec2(1, 0),
1902                                 IVec2(0, 0)
1903                         };
1904
1905                         bool isCurrentPixelValid = true;
1906
1907                         for (int offNdx = 0; offNdx < 4 && isCurrentPixelValid; offNdx++)
1908                         {
1909                                 const CubeFaceIntCoords c = remapCubeEdgeCoords(CubeFaceIntCoords(coords.face, i+offsets[offNdx].x(), j+offsets[offNdx].y()), size);
1910                                 // If any of samples is out of both edges, implementations can do pretty much anything according to spec.
1911                                 // \todo [2014-06-05 nuutti] Test the special case where all corner pixels have exactly the same color.
1912                                 //                                                       See also isSeamlessLinearCompareResultValid and similar.
1913                                 if (c.face == CUBEFACE_LAST)
1914                                         return true;
1915
1916                                 const float                     depth   = lookupDepthNoBorder(faces[c.face], sampler, c.s, c.t);
1917                                 const CmpResultSet      resSet  = execCompare(sampler.compare, depth, cmpReference, prec.referenceBits, isFixedPointDepth);
1918
1919                                 if (!isResultInSet(resSet, result[offNdx], prec.resultBits))
1920                                         isCurrentPixelValid = false;
1921                         }
1922
1923                         if (isCurrentPixelValid)
1924                                 return true;
1925                 }
1926         }
1927
1928         return false;
1929 }
1930
1931 bool isGatherCompareResultValid (const TextureCubeView&                 texture,
1932                                                                  const Sampler&                                 sampler,
1933                                                                  const TexComparePrecision&             prec,
1934                                                                  const Vec3&                                    coord,
1935                                                                  float                                                  cmpReference,
1936                                                                  const Vec4&                                    result)
1937 {
1938         int                     numPossibleFaces                                = 0;
1939         CubeFace        possibleFaces[CUBEFACE_LAST];
1940
1941         DE_ASSERT(isSamplerSupported(sampler));
1942
1943         getPossibleCubeFaces(coord, prec.coordBits, &possibleFaces[0], numPossibleFaces);
1944
1945         if (numPossibleFaces == 0)
1946                 return true; // Result is undefined.
1947
1948         for (int tryFaceNdx = 0; tryFaceNdx < numPossibleFaces; tryFaceNdx++)
1949         {
1950                 const CubeFaceFloatCoords faceCoords(possibleFaces[tryFaceNdx], projectToFace(possibleFaces[tryFaceNdx], coord));
1951
1952                 if (isGatherCompareResultValid(texture, sampler, prec, faceCoords, cmpReference, result))
1953                         return true;
1954         }
1955
1956         return false;
1957 }
1958
1959 } // tcu