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