1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program Tester Core
3 * ----------------------------------------
5 * Copyright 2014 The Android Open Source Project
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 * \brief Texture compare (shadow) result verifier.
22 *//*--------------------------------------------------------------------*/
24 #include "tcuTexCompareVerifier.hpp"
25 #include "tcuTexVerifierUtil.hpp"
26 #include "tcuTextureUtil.hpp"
27 #include "tcuVectorUtil.hpp"
33 using namespace TexVerifierUtil;
38 static bool isSamplerSupported (const Sampler& sampler)
40 return sampler.compare != Sampler::COMPAREMODE_NONE &&
41 isWrapModeSupported(sampler.wrapS) &&
42 isWrapModeSupported(sampler.wrapT) &&
43 isWrapModeSupported(sampler.wrapR);
59 static CmpResultSet execCompare (const Sampler::CompareMode compareMode,
60 const float cmpValue_,
61 const float cmpReference_,
62 const int referenceBits,
63 const bool isFixedPoint)
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);
73 case Sampler::COMPAREMODE_LESS:
74 res.isTrue = cmpReference-err < cmpValue;
75 res.isFalse = cmpReference+err >= cmpValue;
78 case Sampler::COMPAREMODE_LESS_OR_EQUAL:
79 res.isTrue = cmpReference-err <= cmpValue;
80 res.isFalse = cmpReference+err > cmpValue;
83 case Sampler::COMPAREMODE_GREATER:
84 res.isTrue = cmpReference+err > cmpValue;
85 res.isFalse = cmpReference-err <= cmpValue;
88 case Sampler::COMPAREMODE_GREATER_OR_EQUAL:
89 res.isTrue = cmpReference+err >= cmpValue;
90 res.isFalse = cmpReference-err < cmpValue;
93 case Sampler::COMPAREMODE_EQUAL:
94 res.isTrue = de::inRange(cmpValue, cmpReference-err, cmpReference+err);
95 res.isFalse = err != 0.0f || cmpValue != cmpReference;
98 case Sampler::COMPAREMODE_NOT_EQUAL:
99 res.isTrue = err != 0.0f || cmpValue != cmpReference;
100 res.isFalse = de::inRange(cmpValue, cmpReference-err, cmpReference+err);
103 case Sampler::COMPAREMODE_ALWAYS:
107 case Sampler::COMPAREMODE_NEVER:
115 DE_ASSERT(res.isTrue || res.isFalse);
119 static inline bool isResultInSet (const CmpResultSet resultSet, const float result, const int resultBits)
121 const float err = computeFixedPointError(resultBits);
122 const float minR = result-err;
123 const float maxR = result+err;
125 return (resultSet.isTrue && de::inRange(1.0f, minR, maxR)) ||
126 (resultSet.isFalse && de::inRange(0.0f, minR, maxR));
129 static inline bool coordsInBounds (const ConstPixelBufferAccess& access, int x, int y, int z)
131 return de::inBounds(x, 0, access.getWidth()) && de::inBounds(y, 0, access.getHeight()) && de::inBounds(z, 0, access.getDepth());
134 static float lookupDepth (const tcu::ConstPixelBufferAccess& access, const Sampler& sampler, int i, int j, int k)
136 if (coordsInBounds(access, i, j, k))
137 return access.getPixDepth(i, j, k);
139 return sampleTextureBorder<float>(access.getFormat(), sampler).x();
142 // lookup depth value at a point that is guaranteed to not sample border such as cube map faces.
143 static float lookupDepthNoBorder (const tcu::ConstPixelBufferAccess& access, const Sampler& sampler, int i, int j, int k = 0)
146 DE_ASSERT(coordsInBounds(access, i, j, k));
147 return access.getPixDepth(i, j, k);
150 // Values are in order (0,0), (1,0), (0,1), (1,1)
151 static float bilinearInterpolate (const Vec4& values, const float x, const float y)
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;
161 static bool isFixedPointDepthTextureFormat (const tcu::TextureFormat& format)
163 const tcu::TextureChannelClass channelClass = tcu::getTextureChannelClass(format.type);
165 if (format.order == TextureFormat::D)
167 // depth internal formats cannot be non-normalized integers
168 return channelClass != tcu::TEXTURECHANNELCLASS_FLOATING_POINT;
170 else if (format.order == TextureFormat::DS)
172 // combined formats have no single channel class, detect format manually
175 case tcu::TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV: return false;
176 case tcu::TextureFormat::UNSIGNED_INT_16_8_8: return true;
177 case tcu::TextureFormat::UNSIGNED_INT_24_8: return true;
178 case tcu::TextureFormat::UNSIGNED_INT_24_8_REV: return true;
192 static bool isLinearCompareValid (const Sampler::CompareMode compareMode,
193 const TexComparePrecision& prec,
196 const float cmpReference,
198 const bool isFixedPointDepth)
200 DE_ASSERT(0.0f <= fBounds.x() && fBounds.x() <= fBounds.y() && fBounds.y() <= 1.0f);
202 const float d0 = depths[0];
203 const float d1 = depths[1];
205 const CmpResultSet cmp0 = execCompare(compareMode, d0, cmpReference, prec.referenceBits, isFixedPointDepth);
206 const CmpResultSet cmp1 = execCompare(compareMode, d1, cmpReference, prec.referenceBits, isFixedPointDepth);
208 const deUint32 isTrue = (deUint32(cmp0.isTrue)<<0)
209 | (deUint32(cmp1.isTrue)<<1);
210 const deUint32 isFalse = (deUint32(cmp0.isFalse)<<0)
211 | (deUint32(cmp1.isFalse)<<1);
213 // Interpolation parameters
214 const float f0 = fBounds.x();
215 const float f1 = fBounds.y();
218 const float pcfErr = computeFixedPointError(prec.pcfBits);
219 const float resErr = computeFixedPointError(prec.resultBits);
220 const float totalErr = pcfErr+resErr;
222 // Iterate over all valid combinations.
223 for (deUint32 comb = 0; comb < (1<<2); comb++)
225 // Filter out invalid combinations.
226 if (((comb & isTrue) | (~comb & isFalse)) != (1<<2)-1)
229 const bool cmp0True = ((comb>>0)&1) != 0;
230 const bool cmp1True = ((comb>>1)&1) != 0;
232 const float ref0 = cmp0True ? 1.0f : 0.0f;
233 const float ref1 = cmp1True ? 1.0f : 0.0f;
235 const float v0 = ref0*(1.0f-f0) + ref1*f0;
236 const float v1 = ref0*(1.0f-f1) + ref1*f1;
237 const float minV = de::min(v0, v1);
238 const float maxV = de::max(v0, v1);
239 const float minR = minV-totalErr;
240 const float maxR = maxV+totalErr;
242 if (de::inRange(result, minR, maxR))
249 static inline BVec4 extractBVec4 (const deUint32 val, int offset)
251 return BVec4(((val>>(offset+0))&1) != 0,
252 ((val>>(offset+1))&1) != 0,
253 ((val>>(offset+2))&1) != 0,
254 ((val>>(offset+3))&1) != 0);
257 static bool isBilinearAnyCompareValid (const Sampler::CompareMode compareMode,
258 const TexComparePrecision& prec,
260 const float cmpReference,
262 const bool isFixedPointDepth)
264 DE_ASSERT(prec.pcfBits == 0);
266 const float d0 = depths[0];
267 const float d1 = depths[1];
268 const float d2 = depths[2];
269 const float d3 = depths[3];
271 const CmpResultSet cmp0 = execCompare(compareMode, d0, cmpReference, prec.referenceBits, isFixedPointDepth);
272 const CmpResultSet cmp1 = execCompare(compareMode, d1, cmpReference, prec.referenceBits, isFixedPointDepth);
273 const CmpResultSet cmp2 = execCompare(compareMode, d2, cmpReference, prec.referenceBits, isFixedPointDepth);
274 const CmpResultSet cmp3 = execCompare(compareMode, d3, cmpReference, prec.referenceBits, isFixedPointDepth);
276 const bool canBeTrue = cmp0.isTrue || cmp1.isTrue || cmp2.isTrue || cmp3.isTrue;
277 const bool canBeFalse = cmp0.isFalse || cmp1.isFalse || cmp2.isFalse || cmp3.isFalse;
279 const float resErr = computeFixedPointError(prec.resultBits);
281 const float minBound = canBeFalse ? 0.0f : 1.0f;
282 const float maxBound = canBeTrue ? 1.0f : 0.0f;
284 return de::inRange(result, minBound-resErr, maxBound+resErr);
287 static bool isBilinearPCFCompareValid (const Sampler::CompareMode compareMode,
288 const TexComparePrecision& prec,
292 const float cmpReference,
294 const bool isFixedPointDepth)
296 DE_ASSERT(0.0f <= xBounds.x() && xBounds.x() <= xBounds.y() && xBounds.y() <= 1.0f);
297 DE_ASSERT(0.0f <= yBounds.x() && yBounds.x() <= yBounds.y() && yBounds.y() <= 1.0f);
298 DE_ASSERT(prec.pcfBits > 0);
300 const float d0 = depths[0];
301 const float d1 = depths[1];
302 const float d2 = depths[2];
303 const float d3 = depths[3];
305 const CmpResultSet cmp0 = execCompare(compareMode, d0, cmpReference, prec.referenceBits, isFixedPointDepth);
306 const CmpResultSet cmp1 = execCompare(compareMode, d1, cmpReference, prec.referenceBits, isFixedPointDepth);
307 const CmpResultSet cmp2 = execCompare(compareMode, d2, cmpReference, prec.referenceBits, isFixedPointDepth);
308 const CmpResultSet cmp3 = execCompare(compareMode, d3, cmpReference, prec.referenceBits, isFixedPointDepth);
310 const deUint32 isTrue = (deUint32(cmp0.isTrue)<<0)
311 | (deUint32(cmp1.isTrue)<<1)
312 | (deUint32(cmp2.isTrue)<<2)
313 | (deUint32(cmp3.isTrue)<<3);
314 const deUint32 isFalse = (deUint32(cmp0.isFalse)<<0)
315 | (deUint32(cmp1.isFalse)<<1)
316 | (deUint32(cmp2.isFalse)<<2)
317 | (deUint32(cmp3.isFalse)<<3);
319 // Interpolation parameters
320 const float x0 = xBounds.x();
321 const float x1 = xBounds.y();
322 const float y0 = yBounds.x();
323 const float y1 = yBounds.y();
326 const float pcfErr = computeFixedPointError(prec.pcfBits);
327 const float resErr = computeFixedPointError(prec.resultBits);
328 const float totalErr = pcfErr+resErr;
330 // Iterate over all valid combinations.
331 // \note It is not enough to compute minmax over all possible result sets, as ranges may
332 // not necessarily overlap, i.e. there are gaps between valid ranges.
333 for (deUint32 comb = 0; comb < (1<<4); comb++)
335 // Filter out invalid combinations:
336 // 1) True bit is set in comb but not in isTrue => sample can not be true
337 // 2) True bit is NOT set in comb and not in isFalse => sample can not be false
338 if (((comb & isTrue) | (~comb & isFalse)) != (1<<4)-1)
341 const BVec4 cmpTrue = extractBVec4(comb, 0);
342 const Vec4 refVal = select(Vec4(1.0f), Vec4(0.0f), cmpTrue);
344 const float v0 = bilinearInterpolate(refVal, x0, y0);
345 const float v1 = bilinearInterpolate(refVal, x1, y0);
346 const float v2 = bilinearInterpolate(refVal, x0, y1);
347 const float v3 = bilinearInterpolate(refVal, x1, y1);
348 const float minV = de::min(v0, de::min(v1, de::min(v2, v3)));
349 const float maxV = de::max(v0, de::max(v1, de::max(v2, v3)));
350 const float minR = minV-totalErr;
351 const float maxR = maxV+totalErr;
353 if (de::inRange(result, minR, maxR))
360 static bool isBilinearCompareValid (const Sampler::CompareMode compareMode,
361 const TexComparePrecision& prec,
365 const float cmpReference,
367 const bool isFixedPointDepth)
369 if (prec.pcfBits > 0)
370 return isBilinearPCFCompareValid(compareMode, prec, depths, xBounds, yBounds, cmpReference, result, isFixedPointDepth);
372 return isBilinearAnyCompareValid(compareMode, prec, depths, cmpReference, result, isFixedPointDepth);
375 static bool isTrilinearAnyCompareValid (const Sampler::CompareMode compareMode,
376 const TexComparePrecision& prec,
379 const float cmpReference,
381 const bool isFixedPointDepth)
383 DE_ASSERT(prec.pcfBits == 0);
385 const CmpResultSet cmp00 = execCompare(compareMode, depths0[0], cmpReference, prec.referenceBits, isFixedPointDepth);
386 const CmpResultSet cmp01 = execCompare(compareMode, depths0[1], cmpReference, prec.referenceBits, isFixedPointDepth);
387 const CmpResultSet cmp02 = execCompare(compareMode, depths0[2], cmpReference, prec.referenceBits, isFixedPointDepth);
388 const CmpResultSet cmp03 = execCompare(compareMode, depths0[3], cmpReference, prec.referenceBits, isFixedPointDepth);
390 const CmpResultSet cmp10 = execCompare(compareMode, depths1[0], cmpReference, prec.referenceBits, isFixedPointDepth);
391 const CmpResultSet cmp11 = execCompare(compareMode, depths1[1], cmpReference, prec.referenceBits, isFixedPointDepth);
392 const CmpResultSet cmp12 = execCompare(compareMode, depths1[2], cmpReference, prec.referenceBits, isFixedPointDepth);
393 const CmpResultSet cmp13 = execCompare(compareMode, depths1[3], cmpReference, prec.referenceBits, isFixedPointDepth);
395 const bool canBeTrue = cmp00.isTrue ||
403 const bool canBeFalse = cmp00.isFalse ||
412 const float resErr = computeFixedPointError(prec.resultBits);
414 const float minBound = canBeFalse ? 0.0f : 1.0f;
415 const float maxBound = canBeTrue ? 1.0f : 0.0f;
417 return de::inRange(result, minBound-resErr, maxBound+resErr);
420 static bool isTrilinearPCFCompareValid (const Sampler::CompareMode compareMode,
421 const TexComparePrecision& prec,
424 const Vec2& xBounds0,
425 const Vec2& yBounds0,
426 const Vec2& xBounds1,
427 const Vec2& yBounds1,
429 const float cmpReference,
431 const bool isFixedPointDepth)
433 DE_ASSERT(0.0f <= xBounds0.x() && xBounds0.x() <= xBounds0.y() && xBounds0.y() <= 1.0f);
434 DE_ASSERT(0.0f <= yBounds0.x() && yBounds0.x() <= yBounds0.y() && yBounds0.y() <= 1.0f);
435 DE_ASSERT(0.0f <= xBounds1.x() && xBounds1.x() <= xBounds1.y() && xBounds1.y() <= 1.0f);
436 DE_ASSERT(0.0f <= yBounds1.x() && yBounds1.x() <= yBounds1.y() && yBounds1.y() <= 1.0f);
437 DE_ASSERT(0.0f <= fBounds.x() && fBounds.x() <= fBounds.y() && fBounds.y() <= 1.0f);
438 DE_ASSERT(prec.pcfBits > 0);
440 const CmpResultSet cmp00 = execCompare(compareMode, depths0[0], cmpReference, prec.referenceBits, isFixedPointDepth);
441 const CmpResultSet cmp01 = execCompare(compareMode, depths0[1], cmpReference, prec.referenceBits, isFixedPointDepth);
442 const CmpResultSet cmp02 = execCompare(compareMode, depths0[2], cmpReference, prec.referenceBits, isFixedPointDepth);
443 const CmpResultSet cmp03 = execCompare(compareMode, depths0[3], cmpReference, prec.referenceBits, isFixedPointDepth);
445 const CmpResultSet cmp10 = execCompare(compareMode, depths1[0], cmpReference, prec.referenceBits, isFixedPointDepth);
446 const CmpResultSet cmp11 = execCompare(compareMode, depths1[1], cmpReference, prec.referenceBits, isFixedPointDepth);
447 const CmpResultSet cmp12 = execCompare(compareMode, depths1[2], cmpReference, prec.referenceBits, isFixedPointDepth);
448 const CmpResultSet cmp13 = execCompare(compareMode, depths1[3], cmpReference, prec.referenceBits, isFixedPointDepth);
450 const deUint32 isTrue = (deUint32(cmp00.isTrue)<<0)
451 | (deUint32(cmp01.isTrue)<<1)
452 | (deUint32(cmp02.isTrue)<<2)
453 | (deUint32(cmp03.isTrue)<<3)
454 | (deUint32(cmp10.isTrue)<<4)
455 | (deUint32(cmp11.isTrue)<<5)
456 | (deUint32(cmp12.isTrue)<<6)
457 | (deUint32(cmp13.isTrue)<<7);
458 const deUint32 isFalse = (deUint32(cmp00.isFalse)<<0)
459 | (deUint32(cmp01.isFalse)<<1)
460 | (deUint32(cmp02.isFalse)<<2)
461 | (deUint32(cmp03.isFalse)<<3)
462 | (deUint32(cmp10.isFalse)<<4)
463 | (deUint32(cmp11.isFalse)<<5)
464 | (deUint32(cmp12.isFalse)<<6)
465 | (deUint32(cmp13.isFalse)<<7);
468 const float pcfErr = computeFixedPointError(prec.pcfBits);
469 const float resErr = computeFixedPointError(prec.resultBits);
470 const float totalErr = pcfErr+resErr;
472 // Iterate over all valid combinations.
473 for (deUint32 comb = 0; comb < (1<<8); comb++)
475 // Filter out invalid combinations.
476 if (((comb & isTrue) | (~comb & isFalse)) != (1<<8)-1)
479 const BVec4 cmpTrue0 = extractBVec4(comb, 0);
480 const BVec4 cmpTrue1 = extractBVec4(comb, 4);
481 const Vec4 refVal0 = select(Vec4(1.0f), Vec4(0.0f), cmpTrue0);
482 const Vec4 refVal1 = select(Vec4(1.0f), Vec4(0.0f), cmpTrue1);
484 // Bilinear interpolation within levels.
485 const float v00 = bilinearInterpolate(refVal0, xBounds0.x(), yBounds0.x());
486 const float v01 = bilinearInterpolate(refVal0, xBounds0.y(), yBounds0.x());
487 const float v02 = bilinearInterpolate(refVal0, xBounds0.x(), yBounds0.y());
488 const float v03 = bilinearInterpolate(refVal0, xBounds0.y(), yBounds0.y());
489 const float minV0 = de::min(v00, de::min(v01, de::min(v02, v03)));
490 const float maxV0 = de::max(v00, de::max(v01, de::max(v02, v03)));
492 const float v10 = bilinearInterpolate(refVal1, xBounds1.x(), yBounds1.x());
493 const float v11 = bilinearInterpolate(refVal1, xBounds1.y(), yBounds1.x());
494 const float v12 = bilinearInterpolate(refVal1, xBounds1.x(), yBounds1.y());
495 const float v13 = bilinearInterpolate(refVal1, xBounds1.y(), yBounds1.y());
496 const float minV1 = de::min(v10, de::min(v11, de::min(v12, v13)));
497 const float maxV1 = de::max(v10, de::max(v11, de::max(v12, v13)));
499 // Compute min-max bounds by filtering between minimum bounds and maximum bounds between levels.
500 // HW can end up choosing pretty much any of samples between levels, and thus interpolating
501 // between minimums should yield lower bound for range, and same for upper bound.
502 // \todo [2013-07-17 pyry] This seems separable? Can this be optimized? At least ranges could be pre-computed and later combined.
503 const float minF0 = minV0*(1.0f-fBounds.x()) + minV1*fBounds.x();
504 const float minF1 = minV0*(1.0f-fBounds.y()) + minV1*fBounds.y();
505 const float maxF0 = maxV0*(1.0f-fBounds.x()) + maxV1*fBounds.x();
506 const float maxF1 = maxV0*(1.0f-fBounds.y()) + maxV1*fBounds.y();
508 const float minF = de::min(minF0, minF1);
509 const float maxF = de::max(maxF0, maxF1);
511 const float minR = minF-totalErr;
512 const float maxR = maxF+totalErr;
514 if (de::inRange(result, minR, maxR))
521 static bool isTrilinearCompareValid (const Sampler::CompareMode compareMode,
522 const TexComparePrecision& prec,
525 const Vec2& xBounds0,
526 const Vec2& yBounds0,
527 const Vec2& xBounds1,
528 const Vec2& yBounds1,
530 const float cmpReference,
532 const bool isFixedPointDepth)
534 if (prec.pcfBits > 0)
535 return isTrilinearPCFCompareValid(compareMode, prec, depths0, depths1, xBounds0, yBounds0, xBounds1, yBounds1, fBounds, cmpReference, result, isFixedPointDepth);
537 return isTrilinearAnyCompareValid(compareMode, prec, depths0, depths1, cmpReference, result, isFixedPointDepth);
540 static bool isNearestCompareResultValid (const ConstPixelBufferAccess& level,
541 const Sampler& sampler,
542 const TexComparePrecision& prec,
545 const float cmpReference,
548 const bool isFixedPointDepth = isFixedPointDepthTextureFormat(level.getFormat());
549 const Vec2 uBounds = computeNonNormalizedCoordBounds(sampler.normalizedCoords, level.getWidth(), coord.x(), prec.coordBits.x(), prec.uvwBits.x());
550 const Vec2 vBounds = computeNonNormalizedCoordBounds(sampler.normalizedCoords, level.getHeight(), coord.y(), prec.coordBits.y(), prec.uvwBits.y());
552 // Integer coordinates - without wrap mode
553 const int minI = deFloorFloatToInt32(uBounds.x());
554 const int maxI = deFloorFloatToInt32(uBounds.y());
555 const int minJ = deFloorFloatToInt32(vBounds.x());
556 const int maxJ = deFloorFloatToInt32(vBounds.y());
558 for (int j = minJ; j <= maxJ; j++)
560 for (int i = minI; i <= maxI; i++)
562 const int x = wrap(sampler.wrapS, i, level.getWidth());
563 const int y = wrap(sampler.wrapT, j, level.getHeight());
564 const float depth = lookupDepth(level, sampler, x, y, coordZ);
565 const CmpResultSet resSet = execCompare(sampler.compare, depth, cmpReference, prec.referenceBits, isFixedPointDepth);
567 if (isResultInSet(resSet, result, prec.resultBits))
575 static bool isLinearCompareResultValid (const ConstPixelBufferAccess& level,
576 const Sampler& sampler,
577 const TexComparePrecision& prec,
580 const float cmpReference,
583 const bool isFixedPointDepth = isFixedPointDepthTextureFormat(level.getFormat());
584 const Vec2 uBounds = computeNonNormalizedCoordBounds(sampler.normalizedCoords, level.getWidth(), coord.x(), prec.coordBits.x(), prec.uvwBits.x());
585 const Vec2 vBounds = computeNonNormalizedCoordBounds(sampler.normalizedCoords, level.getHeight(), coord.y(), prec.coordBits.y(), prec.uvwBits.y());
587 // Integer coordinate bounds for (x0,y0) - without wrap mode
588 const int minI = deFloorFloatToInt32(uBounds.x()-0.5f);
589 const int maxI = deFloorFloatToInt32(uBounds.y()-0.5f);
590 const int minJ = deFloorFloatToInt32(vBounds.x()-0.5f);
591 const int maxJ = deFloorFloatToInt32(vBounds.y()-0.5f);
593 const int w = level.getWidth();
594 const int h = level.getHeight();
596 // \todo [2013-07-03 pyry] This could be optimized by first computing ranges based on wrap mode.
598 for (int j = minJ; j <= maxJ; j++)
600 for (int i = minI; i <= maxI; i++)
602 // Wrapped coordinates
603 const int x0 = wrap(sampler.wrapS, i , w);
604 const int x1 = wrap(sampler.wrapS, i+1, w);
605 const int y0 = wrap(sampler.wrapT, j , h);
606 const int y1 = wrap(sampler.wrapT, j+1, h);
608 // Bounds for filtering factors
609 const float minA = de::clamp((uBounds.x()-0.5f)-float(i), 0.0f, 1.0f);
610 const float maxA = de::clamp((uBounds.y()-0.5f)-float(i), 0.0f, 1.0f);
611 const float minB = de::clamp((vBounds.x()-0.5f)-float(j), 0.0f, 1.0f);
612 const float maxB = de::clamp((vBounds.y()-0.5f)-float(j), 0.0f, 1.0f);
614 const Vec4 depths (lookupDepth(level, sampler, x0, y0, coordZ),
615 lookupDepth(level, sampler, x1, y0, coordZ),
616 lookupDepth(level, sampler, x0, y1, coordZ),
617 lookupDepth(level, sampler, x1, y1, coordZ));
619 if (isBilinearCompareValid(sampler.compare, prec, depths, Vec2(minA, maxA), Vec2(minB, maxB), cmpReference, result, isFixedPointDepth))
627 static bool isLevelCompareResultValid (const ConstPixelBufferAccess& level,
628 const Sampler& sampler,
629 const Sampler::FilterMode filterMode,
630 const TexComparePrecision& prec,
633 const float cmpReference,
636 if (filterMode == Sampler::LINEAR)
637 return isLinearCompareResultValid(level, sampler, prec, coord, coordZ, cmpReference, result);
639 return isNearestCompareResultValid(level, sampler, prec, coord, coordZ, cmpReference, result);
642 static bool isNearestMipmapLinearCompareResultValid (const ConstPixelBufferAccess& level0,
643 const ConstPixelBufferAccess& level1,
644 const Sampler& sampler,
645 const TexComparePrecision& prec,
649 const float cmpReference,
652 const bool isFixedPointDepth = isFixedPointDepthTextureFormat(level0.getFormat());
654 const int w0 = level0.getWidth();
655 const int w1 = level1.getWidth();
656 const int h0 = level0.getHeight();
657 const int h1 = level1.getHeight();
659 const Vec2 uBounds0 = computeNonNormalizedCoordBounds(sampler.normalizedCoords, w0, coord.x(), prec.coordBits.x(), prec.uvwBits.x());
660 const Vec2 uBounds1 = computeNonNormalizedCoordBounds(sampler.normalizedCoords, w1, coord.x(), prec.coordBits.x(), prec.uvwBits.x());
661 const Vec2 vBounds0 = computeNonNormalizedCoordBounds(sampler.normalizedCoords, h0, coord.y(), prec.coordBits.y(), prec.uvwBits.y());
662 const Vec2 vBounds1 = computeNonNormalizedCoordBounds(sampler.normalizedCoords, h1, coord.y(), prec.coordBits.y(), prec.uvwBits.y());
664 // Integer coordinates - without wrap mode
665 const int minI0 = deFloorFloatToInt32(uBounds0.x());
666 const int maxI0 = deFloorFloatToInt32(uBounds0.y());
667 const int minI1 = deFloorFloatToInt32(uBounds1.x());
668 const int maxI1 = deFloorFloatToInt32(uBounds1.y());
669 const int minJ0 = deFloorFloatToInt32(vBounds0.x());
670 const int maxJ0 = deFloorFloatToInt32(vBounds0.y());
671 const int minJ1 = deFloorFloatToInt32(vBounds1.x());
672 const int maxJ1 = deFloorFloatToInt32(vBounds1.y());
674 for (int j0 = minJ0; j0 <= maxJ0; j0++)
676 for (int i0 = minI0; i0 <= maxI0; i0++)
678 const float depth0 = lookupDepth(level0, sampler, wrap(sampler.wrapS, i0, w0), wrap(sampler.wrapT, j0, h0), coordZ);
680 for (int j1 = minJ1; j1 <= maxJ1; j1++)
682 for (int i1 = minI1; i1 <= maxI1; i1++)
684 const float depth1 = lookupDepth(level1, sampler, wrap(sampler.wrapS, i1, w1), wrap(sampler.wrapT, j1, h1), coordZ);
686 if (isLinearCompareValid(sampler.compare, prec, Vec2(depth0, depth1), fBounds, cmpReference, result, isFixedPointDepth))
696 static bool isLinearMipmapLinearCompareResultValid (const ConstPixelBufferAccess& level0,
697 const ConstPixelBufferAccess& level1,
698 const Sampler& sampler,
699 const TexComparePrecision& prec,
703 const float cmpReference,
706 const bool isFixedPointDepth = isFixedPointDepthTextureFormat(level0.getFormat());
708 // \todo [2013-07-04 pyry] This is strictly not correct as coordinates between levels should be dependent.
709 // Right now this allows pairing any two valid bilinear quads.
711 const int w0 = level0.getWidth();
712 const int w1 = level1.getWidth();
713 const int h0 = level0.getHeight();
714 const int h1 = level1.getHeight();
716 const Vec2 uBounds0 = computeNonNormalizedCoordBounds(sampler.normalizedCoords, w0, coord.x(), prec.coordBits.x(), prec.uvwBits.x());
717 const Vec2 uBounds1 = computeNonNormalizedCoordBounds(sampler.normalizedCoords, w1, coord.x(), prec.coordBits.x(), prec.uvwBits.x());
718 const Vec2 vBounds0 = computeNonNormalizedCoordBounds(sampler.normalizedCoords, h0, coord.y(), prec.coordBits.y(), prec.uvwBits.y());
719 const Vec2 vBounds1 = computeNonNormalizedCoordBounds(sampler.normalizedCoords, h1, coord.y(), prec.coordBits.y(), prec.uvwBits.y());
721 // Integer coordinates - without wrap mode
722 const int minI0 = deFloorFloatToInt32(uBounds0.x()-0.5f);
723 const int maxI0 = deFloorFloatToInt32(uBounds0.y()-0.5f);
724 const int minI1 = deFloorFloatToInt32(uBounds1.x()-0.5f);
725 const int maxI1 = deFloorFloatToInt32(uBounds1.y()-0.5f);
726 const int minJ0 = deFloorFloatToInt32(vBounds0.x()-0.5f);
727 const int maxJ0 = deFloorFloatToInt32(vBounds0.y()-0.5f);
728 const int minJ1 = deFloorFloatToInt32(vBounds1.x()-0.5f);
729 const int maxJ1 = deFloorFloatToInt32(vBounds1.y()-0.5f);
731 for (int j0 = minJ0; j0 <= maxJ0; j0++)
733 for (int i0 = minI0; i0 <= maxI0; i0++)
735 const float minA0 = de::clamp((uBounds0.x()-0.5f)-float(i0), 0.0f, 1.0f);
736 const float maxA0 = de::clamp((uBounds0.y()-0.5f)-float(i0), 0.0f, 1.0f);
737 const float minB0 = de::clamp((vBounds0.x()-0.5f)-float(j0), 0.0f, 1.0f);
738 const float maxB0 = de::clamp((vBounds0.y()-0.5f)-float(j0), 0.0f, 1.0f);
742 const int x0 = wrap(sampler.wrapS, i0 , w0);
743 const int x1 = wrap(sampler.wrapS, i0+1, w0);
744 const int y0 = wrap(sampler.wrapT, j0 , h0);
745 const int y1 = wrap(sampler.wrapT, j0+1, h0);
747 depths0[0] = lookupDepth(level0, sampler, x0, y0, coordZ);
748 depths0[1] = lookupDepth(level0, sampler, x1, y0, coordZ);
749 depths0[2] = lookupDepth(level0, sampler, x0, y1, coordZ);
750 depths0[3] = lookupDepth(level0, sampler, x1, y1, coordZ);
753 for (int j1 = minJ1; j1 <= maxJ1; j1++)
755 for (int i1 = minI1; i1 <= maxI1; i1++)
757 const float minA1 = de::clamp((uBounds1.x()-0.5f)-float(i1), 0.0f, 1.0f);
758 const float maxA1 = de::clamp((uBounds1.y()-0.5f)-float(i1), 0.0f, 1.0f);
759 const float minB1 = de::clamp((vBounds1.x()-0.5f)-float(j1), 0.0f, 1.0f);
760 const float maxB1 = de::clamp((vBounds1.y()-0.5f)-float(j1), 0.0f, 1.0f);
764 const int x0 = wrap(sampler.wrapS, i1 , w1);
765 const int x1 = wrap(sampler.wrapS, i1+1, w1);
766 const int y0 = wrap(sampler.wrapT, j1 , h1);
767 const int y1 = wrap(sampler.wrapT, j1+1, h1);
769 depths1[0] = lookupDepth(level1, sampler, x0, y0, coordZ);
770 depths1[1] = lookupDepth(level1, sampler, x1, y0, coordZ);
771 depths1[2] = lookupDepth(level1, sampler, x0, y1, coordZ);
772 depths1[3] = lookupDepth(level1, sampler, x1, y1, coordZ);
775 if (isTrilinearCompareValid(sampler.compare, prec, depths0, depths1,
776 Vec2(minA0, maxA0), Vec2(minB0, maxB0),
777 Vec2(minA1, maxA1), Vec2(minB1, maxB1),
778 fBounds, cmpReference, result, isFixedPointDepth))
788 static bool isMipmapLinearCompareResultValid (const ConstPixelBufferAccess& level0,
789 const ConstPixelBufferAccess& level1,
790 const Sampler& sampler,
791 const Sampler::FilterMode levelFilter,
792 const TexComparePrecision& prec,
796 const float cmpReference,
799 if (levelFilter == Sampler::LINEAR)
800 return isLinearMipmapLinearCompareResultValid(level0, level1, sampler, prec, coord, coordZ, fBounds, cmpReference, result);
802 return isNearestMipmapLinearCompareResultValid(level0, level1, sampler, prec, coord, coordZ, fBounds, cmpReference, result);
805 bool isTexCompareResultValid (const Texture2DView& texture,
806 const Sampler& sampler,
807 const TexComparePrecision& prec,
809 const Vec2& lodBounds,
810 const float cmpReference,
813 const float minLod = lodBounds.x();
814 const float maxLod = lodBounds.y();
815 const bool canBeMagnified = minLod <= sampler.lodThreshold;
816 const bool canBeMinified = maxLod > sampler.lodThreshold;
818 DE_ASSERT(isSamplerSupported(sampler));
822 if (isLevelCompareResultValid(texture.getLevel(0), sampler, sampler.magFilter, prec, coord, 0, cmpReference, result))
828 const bool isNearestMipmap = isNearestMipmapFilter(sampler.minFilter);
829 const bool isLinearMipmap = isLinearMipmapFilter(sampler.minFilter);
830 const int minTexLevel = 0;
831 const int maxTexLevel = texture.getNumLevels()-1;
833 DE_ASSERT(minTexLevel < maxTexLevel);
837 const int minLevel = de::clamp((int)deFloatFloor(minLod), minTexLevel, maxTexLevel-1);
838 const int maxLevel = de::clamp((int)deFloatFloor(maxLod), minTexLevel, maxTexLevel-1);
840 DE_ASSERT(minLevel <= maxLevel);
842 for (int level = minLevel; level <= maxLevel; level++)
844 const float minF = de::clamp(minLod - float(level), 0.0f, 1.0f);
845 const float maxF = de::clamp(maxLod - float(level), 0.0f, 1.0f);
847 if (isMipmapLinearCompareResultValid(texture.getLevel(level), texture.getLevel(level+1), sampler, getLevelFilter(sampler.minFilter), prec, coord, 0, Vec2(minF, maxF), cmpReference, result))
851 else if (isNearestMipmap)
853 // \note The accurate formula for nearest mipmapping is level = ceil(lod + 0.5) - 1 but Khronos has made
854 // decision to allow floor(lod + 0.5) as well.
855 const int minLevel = de::clamp((int)deFloatCeil(minLod + 0.5f) - 1, minTexLevel, maxTexLevel);
856 const int maxLevel = de::clamp((int)deFloatFloor(maxLod + 0.5f), minTexLevel, maxTexLevel);
858 DE_ASSERT(minLevel <= maxLevel);
860 for (int level = minLevel; level <= maxLevel; level++)
862 if (isLevelCompareResultValid(texture.getLevel(level), sampler, getLevelFilter(sampler.minFilter), prec, coord, 0, cmpReference, result))
868 if (isLevelCompareResultValid(texture.getLevel(0), sampler, sampler.minFilter, prec, coord, 0, cmpReference, result))
876 static bool isSeamplessLinearMipmapLinearCompareResultValid (const TextureCubeView& texture,
877 const int baseLevelNdx,
878 const Sampler& sampler,
879 const TexComparePrecision& prec,
880 const CubeFaceFloatCoords& coords,
882 const float cmpReference,
885 const bool isFixedPointDepth = isFixedPointDepthTextureFormat(texture.getLevelFace(baseLevelNdx, CUBEFACE_NEGATIVE_X).getFormat());
886 const int size0 = texture.getLevelFace(baseLevelNdx, coords.face).getWidth();
887 const int size1 = texture.getLevelFace(baseLevelNdx+1, coords.face).getWidth();
889 const Vec2 uBounds0 = computeNonNormalizedCoordBounds(sampler.normalizedCoords, size0, coords.s, prec.coordBits.x(), prec.uvwBits.x());
890 const Vec2 uBounds1 = computeNonNormalizedCoordBounds(sampler.normalizedCoords, size1, coords.s, prec.coordBits.x(), prec.uvwBits.x());
891 const Vec2 vBounds0 = computeNonNormalizedCoordBounds(sampler.normalizedCoords, size0, coords.t, prec.coordBits.y(), prec.uvwBits.y());
892 const Vec2 vBounds1 = computeNonNormalizedCoordBounds(sampler.normalizedCoords, size1, coords.t, prec.coordBits.y(), prec.uvwBits.y());
894 // Integer coordinates - without wrap mode
895 const int minI0 = deFloorFloatToInt32(uBounds0.x()-0.5f);
896 const int maxI0 = deFloorFloatToInt32(uBounds0.y()-0.5f);
897 const int minI1 = deFloorFloatToInt32(uBounds1.x()-0.5f);
898 const int maxI1 = deFloorFloatToInt32(uBounds1.y()-0.5f);
899 const int minJ0 = deFloorFloatToInt32(vBounds0.x()-0.5f);
900 const int maxJ0 = deFloorFloatToInt32(vBounds0.y()-0.5f);
901 const int minJ1 = deFloorFloatToInt32(vBounds1.x()-0.5f);
902 const int maxJ1 = deFloorFloatToInt32(vBounds1.y()-0.5f);
904 tcu::ConstPixelBufferAccess faces0[CUBEFACE_LAST];
905 tcu::ConstPixelBufferAccess faces1[CUBEFACE_LAST];
907 for (int face = 0; face < CUBEFACE_LAST; face++)
909 faces0[face] = texture.getLevelFace(baseLevelNdx, CubeFace(face));
910 faces1[face] = texture.getLevelFace(baseLevelNdx+1, CubeFace(face));
913 for (int j0 = minJ0; j0 <= maxJ0; j0++)
915 for (int i0 = minI0; i0 <= maxI0; i0++)
917 const float minA0 = de::clamp((uBounds0.x()-0.5f)-float(i0), 0.0f, 1.0f);
918 const float maxA0 = de::clamp((uBounds0.y()-0.5f)-float(i0), 0.0f, 1.0f);
919 const float minB0 = de::clamp((vBounds0.x()-0.5f)-float(j0), 0.0f, 1.0f);
920 const float maxB0 = de::clamp((vBounds0.y()-0.5f)-float(j0), 0.0f, 1.0f);
924 const CubeFaceIntCoords c00 = remapCubeEdgeCoords(CubeFaceIntCoords(coords.face, IVec2(i0+0, j0+0)), size0);
925 const CubeFaceIntCoords c10 = remapCubeEdgeCoords(CubeFaceIntCoords(coords.face, IVec2(i0+1, j0+0)), size0);
926 const CubeFaceIntCoords c01 = remapCubeEdgeCoords(CubeFaceIntCoords(coords.face, IVec2(i0+0, j0+1)), size0);
927 const CubeFaceIntCoords c11 = remapCubeEdgeCoords(CubeFaceIntCoords(coords.face, IVec2(i0+1, j0+1)), size0);
929 // If any of samples is out of both edges, implementations can do pretty much anything according to spec.
930 // \todo [2013-07-08 pyry] Test the special case where all corner pixels have exactly the same color.
931 if (c00.face == CUBEFACE_LAST || c01.face == CUBEFACE_LAST || c10.face == CUBEFACE_LAST || c11.face == CUBEFACE_LAST)
934 depths0[0] = lookupDepthNoBorder(faces0[c00.face], sampler, c00.s, c00.t);
935 depths0[1] = lookupDepthNoBorder(faces0[c10.face], sampler, c10.s, c10.t);
936 depths0[2] = lookupDepthNoBorder(faces0[c01.face], sampler, c01.s, c01.t);
937 depths0[3] = lookupDepthNoBorder(faces0[c11.face], sampler, c11.s, c11.t);
940 for (int j1 = minJ1; j1 <= maxJ1; j1++)
942 for (int i1 = minI1; i1 <= maxI1; i1++)
944 const float minA1 = de::clamp((uBounds1.x()-0.5f)-float(i1), 0.0f, 1.0f);
945 const float maxA1 = de::clamp((uBounds1.y()-0.5f)-float(i1), 0.0f, 1.0f);
946 const float minB1 = de::clamp((vBounds1.x()-0.5f)-float(j1), 0.0f, 1.0f);
947 const float maxB1 = de::clamp((vBounds1.y()-0.5f)-float(j1), 0.0f, 1.0f);
951 const CubeFaceIntCoords c00 = remapCubeEdgeCoords(CubeFaceIntCoords(coords.face, IVec2(i1+0, j1+0)), size1);
952 const CubeFaceIntCoords c10 = remapCubeEdgeCoords(CubeFaceIntCoords(coords.face, IVec2(i1+1, j1+0)), size1);
953 const CubeFaceIntCoords c01 = remapCubeEdgeCoords(CubeFaceIntCoords(coords.face, IVec2(i1+0, j1+1)), size1);
954 const CubeFaceIntCoords c11 = remapCubeEdgeCoords(CubeFaceIntCoords(coords.face, IVec2(i1+1, j1+1)), size1);
956 if (c00.face == CUBEFACE_LAST || c01.face == CUBEFACE_LAST || c10.face == CUBEFACE_LAST || c11.face == CUBEFACE_LAST)
959 depths1[0] = lookupDepthNoBorder(faces1[c00.face], sampler, c00.s, c00.t);
960 depths1[1] = lookupDepthNoBorder(faces1[c10.face], sampler, c10.s, c10.t);
961 depths1[2] = lookupDepthNoBorder(faces1[c01.face], sampler, c01.s, c01.t);
962 depths1[3] = lookupDepthNoBorder(faces1[c11.face], sampler, c11.s, c11.t);
966 if (isTrilinearCompareValid(sampler.compare, prec, depths0, depths1,
967 Vec2(minA0, maxA0), Vec2(minB0, maxB0),
968 Vec2(minA1, maxA1), Vec2(minB1, maxB1),
969 fBounds, cmpReference, result, isFixedPointDepth))
979 static bool isCubeMipmapLinearCompareResultValid (const TextureCubeView& texture,
980 const int baseLevelNdx,
981 const Sampler& sampler,
982 const Sampler::FilterMode levelFilter,
983 const TexComparePrecision& prec,
984 const CubeFaceFloatCoords& coords,
986 const float cmpReference,
989 if (levelFilter == Sampler::LINEAR)
991 if (sampler.seamlessCubeMap)
992 return isSeamplessLinearMipmapLinearCompareResultValid(texture, baseLevelNdx, sampler, prec, coords, fBounds, cmpReference, result);
994 return isLinearMipmapLinearCompareResultValid(texture.getLevelFace(baseLevelNdx, coords.face),
995 texture.getLevelFace(baseLevelNdx+1, coords.face),
996 sampler, prec, Vec2(coords.s, coords.t), 0, fBounds, cmpReference, result);
999 return isNearestMipmapLinearCompareResultValid(texture.getLevelFace(baseLevelNdx, coords.face),
1000 texture.getLevelFace(baseLevelNdx+1, coords.face),
1001 sampler, prec, Vec2(coords.s, coords.t), 0, fBounds, cmpReference, result);
1004 static bool isSeamlessLinearCompareResultValid (const TextureCubeView& texture,
1006 const Sampler& sampler,
1007 const TexComparePrecision& prec,
1008 const CubeFaceFloatCoords& coords,
1009 const float cmpReference,
1012 const bool isFixedPointDepth = isFixedPointDepthTextureFormat(texture.getLevelFace(levelNdx, CUBEFACE_NEGATIVE_X).getFormat());
1013 const int size = texture.getLevelFace(levelNdx, coords.face).getWidth();
1015 const Vec2 uBounds = computeNonNormalizedCoordBounds(sampler.normalizedCoords, size, coords.s, prec.coordBits.x(), prec.uvwBits.x());
1016 const Vec2 vBounds = computeNonNormalizedCoordBounds(sampler.normalizedCoords, size, coords.t, prec.coordBits.y(), prec.uvwBits.y());
1018 // Integer coordinate bounds for (x0,y0) - without wrap mode
1019 const int minI = deFloorFloatToInt32(uBounds.x()-0.5f);
1020 const int maxI = deFloorFloatToInt32(uBounds.y()-0.5f);
1021 const int minJ = deFloorFloatToInt32(vBounds.x()-0.5f);
1022 const int maxJ = deFloorFloatToInt32(vBounds.y()-0.5f);
1025 ConstPixelBufferAccess faces[CUBEFACE_LAST];
1026 for (int face = 0; face < CUBEFACE_LAST; face++)
1027 faces[face] = texture.getLevelFace(levelNdx, CubeFace(face));
1029 for (int j = minJ; j <= maxJ; j++)
1031 for (int i = minI; i <= maxI; i++)
1033 const CubeFaceIntCoords c00 = remapCubeEdgeCoords(CubeFaceIntCoords(coords.face, IVec2(i+0, j+0)), size);
1034 const CubeFaceIntCoords c10 = remapCubeEdgeCoords(CubeFaceIntCoords(coords.face, IVec2(i+1, j+0)), size);
1035 const CubeFaceIntCoords c01 = remapCubeEdgeCoords(CubeFaceIntCoords(coords.face, IVec2(i+0, j+1)), size);
1036 const CubeFaceIntCoords c11 = remapCubeEdgeCoords(CubeFaceIntCoords(coords.face, IVec2(i+1, j+1)), size);
1038 // If any of samples is out of both edges, implementations can do pretty much anything according to spec.
1039 // \todo [2013-07-08 pyry] Test the special case where all corner pixels have exactly the same color.
1040 if (c00.face == CUBEFACE_LAST || c01.face == CUBEFACE_LAST || c10.face == CUBEFACE_LAST || c11.face == CUBEFACE_LAST)
1043 // Bounds for filtering factors
1044 const float minA = de::clamp((uBounds.x()-0.5f)-float(i), 0.0f, 1.0f);
1045 const float maxA = de::clamp((uBounds.y()-0.5f)-float(i), 0.0f, 1.0f);
1046 const float minB = de::clamp((vBounds.x()-0.5f)-float(j), 0.0f, 1.0f);
1047 const float maxB = de::clamp((vBounds.y()-0.5f)-float(j), 0.0f, 1.0f);
1050 depths[0] = lookupDepthNoBorder(faces[c00.face], sampler, c00.s, c00.t);
1051 depths[1] = lookupDepthNoBorder(faces[c10.face], sampler, c10.s, c10.t);
1052 depths[2] = lookupDepthNoBorder(faces[c01.face], sampler, c01.s, c01.t);
1053 depths[3] = lookupDepthNoBorder(faces[c11.face], sampler, c11.s, c11.t);
1055 if (isBilinearCompareValid(sampler.compare, prec, depths, Vec2(minA, maxA), Vec2(minB, maxB), cmpReference, result, isFixedPointDepth))
1063 static bool isCubeLevelCompareResultValid (const TextureCubeView& texture,
1065 const Sampler& sampler,
1066 const Sampler::FilterMode filterMode,
1067 const TexComparePrecision& prec,
1068 const CubeFaceFloatCoords& coords,
1069 const float cmpReference,
1072 if (filterMode == Sampler::LINEAR)
1074 if (sampler.seamlessCubeMap)
1075 return isSeamlessLinearCompareResultValid(texture, levelNdx, sampler, prec, coords, cmpReference, result);
1077 return isLinearCompareResultValid(texture.getLevelFace(levelNdx, coords.face), sampler, prec, Vec2(coords.s, coords.t), 0, cmpReference, result);
1080 return isNearestCompareResultValid(texture.getLevelFace(levelNdx, coords.face), sampler, prec, Vec2(coords.s, coords.t), 0, cmpReference, result);
1083 bool isTexCompareResultValid (const TextureCubeView& texture, const Sampler& sampler, const TexComparePrecision& prec, const Vec3& coord, const Vec2& lodBounds, const float cmpReference, const float result)
1085 int numPossibleFaces = 0;
1086 CubeFace possibleFaces[CUBEFACE_LAST];
1088 DE_ASSERT(isSamplerSupported(sampler));
1090 getPossibleCubeFaces(coord, prec.coordBits, &possibleFaces[0], numPossibleFaces);
1092 if (numPossibleFaces == 0)
1093 return true; // Result is undefined.
1095 for (int tryFaceNdx = 0; tryFaceNdx < numPossibleFaces; tryFaceNdx++)
1097 const CubeFaceFloatCoords faceCoords (possibleFaces[tryFaceNdx], projectToFace(possibleFaces[tryFaceNdx], coord));
1098 const float minLod = lodBounds.x();
1099 const float maxLod = lodBounds.y();
1100 const bool canBeMagnified = minLod <= sampler.lodThreshold;
1101 const bool canBeMinified = maxLod > sampler.lodThreshold;
1105 if (isCubeLevelCompareResultValid(texture, 0, sampler, sampler.magFilter, prec, faceCoords, cmpReference, result))
1111 const bool isNearestMipmap = isNearestMipmapFilter(sampler.minFilter);
1112 const bool isLinearMipmap = isLinearMipmapFilter(sampler.minFilter);
1113 const int minTexLevel = 0;
1114 const int maxTexLevel = texture.getNumLevels()-1;
1116 DE_ASSERT(minTexLevel < maxTexLevel);
1120 const int minLevel = de::clamp((int)deFloatFloor(minLod), minTexLevel, maxTexLevel-1);
1121 const int maxLevel = de::clamp((int)deFloatFloor(maxLod), minTexLevel, maxTexLevel-1);
1123 DE_ASSERT(minLevel <= maxLevel);
1125 for (int level = minLevel; level <= maxLevel; level++)
1127 const float minF = de::clamp(minLod - float(level), 0.0f, 1.0f);
1128 const float maxF = de::clamp(maxLod - float(level), 0.0f, 1.0f);
1130 if (isCubeMipmapLinearCompareResultValid(texture, level, sampler, getLevelFilter(sampler.minFilter), prec, faceCoords, Vec2(minF, maxF), cmpReference, result))
1134 else if (isNearestMipmap)
1136 // \note The accurate formula for nearest mipmapping is level = ceil(lod + 0.5) - 1 but Khronos has made
1137 // decision to allow floor(lod + 0.5) as well.
1138 const int minLevel = de::clamp((int)deFloatCeil(minLod + 0.5f) - 1, minTexLevel, maxTexLevel);
1139 const int maxLevel = de::clamp((int)deFloatFloor(maxLod + 0.5f), minTexLevel, maxTexLevel);
1141 DE_ASSERT(minLevel <= maxLevel);
1143 for (int level = minLevel; level <= maxLevel; level++)
1145 if (isCubeLevelCompareResultValid(texture, level, sampler, getLevelFilter(sampler.minFilter), prec, faceCoords, cmpReference, result))
1151 if (isCubeLevelCompareResultValid(texture, 0, sampler, sampler.minFilter, prec, faceCoords, cmpReference, result))
1160 bool isTexCompareResultValid (const Texture2DArrayView& texture, const Sampler& sampler, const TexComparePrecision& prec, const Vec3& coord, const Vec2& lodBounds, const float cmpReference, const float result)
1162 const float depthErr = computeFloatingPointError(coord.z(), prec.coordBits.z()) + computeFixedPointError(prec.uvwBits.z());
1163 const float minZ = coord.z()-depthErr;
1164 const float maxZ = coord.z()+depthErr;
1165 const int minLayer = de::clamp(deFloorFloatToInt32(minZ + 0.5f), 0, texture.getNumLayers()-1);
1166 const int maxLayer = de::clamp(deFloorFloatToInt32(maxZ + 0.5f), 0, texture.getNumLayers()-1);
1168 DE_ASSERT(isSamplerSupported(sampler));
1170 for (int layer = minLayer; layer <= maxLayer; layer++)
1172 const float minLod = lodBounds.x();
1173 const float maxLod = lodBounds.y();
1174 const bool canBeMagnified = minLod <= sampler.lodThreshold;
1175 const bool canBeMinified = maxLod > sampler.lodThreshold;
1179 if (isLevelCompareResultValid(texture.getLevel(0), sampler, sampler.magFilter, prec, coord.swizzle(0,1), layer, cmpReference, result))
1185 const bool isNearestMipmap = isNearestMipmapFilter(sampler.minFilter);
1186 const bool isLinearMipmap = isLinearMipmapFilter(sampler.minFilter);
1187 const int minTexLevel = 0;
1188 const int maxTexLevel = texture.getNumLevels()-1;
1190 DE_ASSERT(minTexLevel < maxTexLevel);
1194 const int minLevel = de::clamp((int)deFloatFloor(minLod), minTexLevel, maxTexLevel-1);
1195 const int maxLevel = de::clamp((int)deFloatFloor(maxLod), minTexLevel, maxTexLevel-1);
1197 DE_ASSERT(minLevel <= maxLevel);
1199 for (int level = minLevel; level <= maxLevel; level++)
1201 const float minF = de::clamp(minLod - float(level), 0.0f, 1.0f);
1202 const float maxF = de::clamp(maxLod - float(level), 0.0f, 1.0f);
1204 if (isMipmapLinearCompareResultValid(texture.getLevel(level), texture.getLevel(level+1), sampler, getLevelFilter(sampler.minFilter), prec, coord.swizzle(0,1), layer, Vec2(minF, maxF), cmpReference, result))
1208 else if (isNearestMipmap)
1210 // \note The accurate formula for nearest mipmapping is level = ceil(lod + 0.5) - 1 but Khronos has made
1211 // decision to allow floor(lod + 0.5) as well.
1212 const int minLevel = de::clamp((int)deFloatCeil(minLod + 0.5f) - 1, minTexLevel, maxTexLevel);
1213 const int maxLevel = de::clamp((int)deFloatFloor(maxLod + 0.5f), minTexLevel, maxTexLevel);
1215 DE_ASSERT(minLevel <= maxLevel);
1217 for (int level = minLevel; level <= maxLevel; level++)
1219 if (isLevelCompareResultValid(texture.getLevel(level), sampler, getLevelFilter(sampler.minFilter), prec, coord.swizzle(0,1), layer, cmpReference, result))
1225 if (isLevelCompareResultValid(texture.getLevel(0), sampler, sampler.minFilter, prec, coord.swizzle(0,1), layer, cmpReference, result))
1234 static bool isGatherOffsetsCompareResultValid (const ConstPixelBufferAccess& texture,
1235 const Sampler& sampler,
1236 const TexComparePrecision& prec,
1239 const IVec2 (&offsets)[4],
1243 const bool isFixedPointDepth = isFixedPointDepthTextureFormat(texture.getFormat());
1244 const Vec2 uBounds = computeNonNormalizedCoordBounds(sampler.normalizedCoords, texture.getWidth(), coord.x(), prec.coordBits.x(), prec.uvwBits.x());
1245 const Vec2 vBounds = computeNonNormalizedCoordBounds(sampler.normalizedCoords, texture.getHeight(), coord.y(), prec.coordBits.y(), prec.uvwBits.y());
1247 // Integer coordinate bounds for (x0, y0) - without wrap mode
1248 const int minI = deFloorFloatToInt32(uBounds.x()-0.5f);
1249 const int maxI = deFloorFloatToInt32(uBounds.y()-0.5f);
1250 const int minJ = deFloorFloatToInt32(vBounds.x()-0.5f);
1251 const int maxJ = deFloorFloatToInt32(vBounds.y()-0.5f);
1253 const int w = texture.getWidth();
1254 const int h = texture.getHeight();
1256 for (int j = minJ; j <= maxJ; j++)
1258 for (int i = minI; i <= maxI; i++)
1260 bool isCurrentPixelValid = true;
1262 for (int offNdx = 0; offNdx < 4 && isCurrentPixelValid; offNdx++)
1264 // offNdx-th coordinate offset and then wrapped.
1265 const int x = wrap(sampler.wrapS, i+offsets[offNdx].x(), w);
1266 const int y = wrap(sampler.wrapT, j+offsets[offNdx].y(), h);
1267 const float depth = lookupDepth(texture, sampler, x, y, coordZ);
1268 const CmpResultSet resSet = execCompare(sampler.compare, depth, cmpReference, prec.referenceBits, isFixedPointDepth);
1270 if (!isResultInSet(resSet, result[offNdx], prec.resultBits))
1271 isCurrentPixelValid = false;
1274 if (isCurrentPixelValid)
1282 bool isGatherOffsetsCompareResultValid (const Texture2DView& texture,
1283 const Sampler& sampler,
1284 const TexComparePrecision& prec,
1286 const IVec2 (&offsets)[4],
1290 DE_ASSERT(isSamplerSupported(sampler));
1292 return isGatherOffsetsCompareResultValid(texture.getLevel(0), sampler, prec, coord, 0, offsets, cmpReference, result);
1295 bool isGatherOffsetsCompareResultValid (const Texture2DArrayView& texture,
1296 const Sampler& sampler,
1297 const TexComparePrecision& prec,
1299 const IVec2 (&offsets)[4],
1303 const float depthErr = computeFloatingPointError(coord.z(), prec.coordBits.z()) + computeFixedPointError(prec.uvwBits.z());
1304 const float minZ = coord.z()-depthErr;
1305 const float maxZ = coord.z()+depthErr;
1306 const int minLayer = de::clamp(deFloorFloatToInt32(minZ + 0.5f), 0, texture.getNumLayers()-1);
1307 const int maxLayer = de::clamp(deFloorFloatToInt32(maxZ + 0.5f), 0, texture.getNumLayers()-1);
1309 DE_ASSERT(isSamplerSupported(sampler));
1311 for (int layer = minLayer; layer <= maxLayer; layer++)
1313 if (isGatherOffsetsCompareResultValid(texture.getLevel(0), sampler, prec, coord.swizzle(0,1), layer, offsets, cmpReference, result))
1319 static bool isGatherCompareResultValid (const TextureCubeView& texture,
1320 const Sampler& sampler,
1321 const TexComparePrecision& prec,
1322 const CubeFaceFloatCoords& coords,
1326 const bool isFixedPointDepth = isFixedPointDepthTextureFormat(texture.getLevelFace(0, coords.face).getFormat());
1327 const int size = texture.getLevelFace(0, coords.face).getWidth();
1328 const Vec2 uBounds = computeNonNormalizedCoordBounds(sampler.normalizedCoords, size, coords.s, prec.coordBits.x(), prec.uvwBits.x());
1329 const Vec2 vBounds = computeNonNormalizedCoordBounds(sampler.normalizedCoords, size, coords.t, prec.coordBits.y(), prec.uvwBits.y());
1331 // Integer coordinate bounds for (x0,y0) - without wrap mode
1332 const int minI = deFloorFloatToInt32(uBounds.x()-0.5f);
1333 const int maxI = deFloorFloatToInt32(uBounds.y()-0.5f);
1334 const int minJ = deFloorFloatToInt32(vBounds.x()-0.5f);
1335 const int maxJ = deFloorFloatToInt32(vBounds.y()-0.5f);
1338 ConstPixelBufferAccess faces[CUBEFACE_LAST];
1339 for (int face = 0; face < CUBEFACE_LAST; face++)
1340 faces[face] = texture.getLevelFace(0, CubeFace(face));
1342 for (int j = minJ; j <= maxJ; j++)
1344 for (int i = minI; i <= maxI; i++)
1346 static const IVec2 offsets[4] =
1354 bool isCurrentPixelValid = true;
1356 for (int offNdx = 0; offNdx < 4 && isCurrentPixelValid; offNdx++)
1358 const CubeFaceIntCoords c = remapCubeEdgeCoords(CubeFaceIntCoords(coords.face, i+offsets[offNdx].x(), j+offsets[offNdx].y()), size);
1359 // If any of samples is out of both edges, implementations can do pretty much anything according to spec.
1360 // \todo [2014-06-05 nuutti] Test the special case where all corner pixels have exactly the same color.
1361 // See also isSeamlessLinearCompareResultValid and similar.
1362 if (c.face == CUBEFACE_LAST)
1365 const float depth = lookupDepthNoBorder(faces[c.face], sampler, c.s, c.t);
1366 const CmpResultSet resSet = execCompare(sampler.compare, depth, cmpReference, prec.referenceBits, isFixedPointDepth);
1368 if (!isResultInSet(resSet, result[offNdx], prec.resultBits))
1369 isCurrentPixelValid = false;
1372 if (isCurrentPixelValid)
1380 bool isGatherCompareResultValid (const TextureCubeView& texture,
1381 const Sampler& sampler,
1382 const TexComparePrecision& prec,
1387 int numPossibleFaces = 0;
1388 CubeFace possibleFaces[CUBEFACE_LAST];
1390 DE_ASSERT(isSamplerSupported(sampler));
1392 getPossibleCubeFaces(coord, prec.coordBits, &possibleFaces[0], numPossibleFaces);
1394 if (numPossibleFaces == 0)
1395 return true; // Result is undefined.
1397 for (int tryFaceNdx = 0; tryFaceNdx < numPossibleFaces; tryFaceNdx++)
1399 const CubeFaceFloatCoords faceCoords(possibleFaces[tryFaceNdx], projectToFace(possibleFaces[tryFaceNdx], coord));
1401 if (isGatherCompareResultValid(texture, sampler, prec, faceCoords, cmpReference, result))