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 // lookup depth value at a point that is guaranteed to not sample border such as cube map faces.
135 static float lookupDepthNoBorder (const tcu::ConstPixelBufferAccess& access, const Sampler& sampler, int i, int j, int k = 0)
138 DE_ASSERT(coordsInBounds(access, i, j, k));
139 DE_ASSERT( access.getFormat().order == TextureFormat::D || access.getFormat().order == TextureFormat::DS ||
140 access.getFormat().order == TextureFormat::R);
142 if (access.getFormat().order == TextureFormat::R)
143 return access.getPixel(i,j,k).x();
145 return access.getPixDepth(i, j, k);
148 static float lookupDepth (const tcu::ConstPixelBufferAccess& access, const Sampler& sampler, int i, int j, int k)
150 if (coordsInBounds(access, i, j, k))
151 return lookupDepthNoBorder(access, sampler, i, j, k);
153 return sampleTextureBorder<float>(access.getFormat(), sampler).x();
156 // Values are in order (0,0), (1,0), (0,1), (1,1)
157 static float bilinearInterpolate (const Vec4& values, const float x, const float y)
159 const float v00 = values[0];
160 const float v10 = values[1];
161 const float v01 = values[2];
162 const float v11 = values[3];
163 const float res = v00*(1.0f-x)*(1.0f-y) + v10*x*(1.0f-y) + v01*(1.0f-x)*y + v11*x*y;
167 static bool isFixedPointDepthTextureFormat (const tcu::TextureFormat& format)
169 const tcu::TextureChannelClass channelClass = tcu::getTextureChannelClass(format.type);
171 if (format.order == TextureFormat::D || format.order == TextureFormat::R)
173 // depth internal formats cannot be non-normalized integers
174 return channelClass != tcu::TEXTURECHANNELCLASS_FLOATING_POINT;
176 else if (format.order == TextureFormat::DS)
178 // combined formats have no single channel class, detect format manually
181 case tcu::TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV: return false;
182 case tcu::TextureFormat::UNSIGNED_INT_16_8_8: return true;
183 case tcu::TextureFormat::UNSIGNED_INT_24_8: return true;
184 case tcu::TextureFormat::UNSIGNED_INT_24_8_REV: return true;
198 static bool isLinearCompareValid (const Sampler::CompareMode compareMode,
199 const TexComparePrecision& prec,
202 const float cmpReference,
204 const bool isFixedPointDepth)
206 DE_ASSERT(0.0f <= fBounds.x() && fBounds.x() <= fBounds.y() && fBounds.y() <= 1.0f);
208 const float d0 = depths[0];
209 const float d1 = depths[1];
211 const CmpResultSet cmp0 = execCompare(compareMode, d0, cmpReference, prec.referenceBits, isFixedPointDepth);
212 const CmpResultSet cmp1 = execCompare(compareMode, d1, cmpReference, prec.referenceBits, isFixedPointDepth);
214 const deUint32 isTrue = (deUint32(cmp0.isTrue)<<0)
215 | (deUint32(cmp1.isTrue)<<1);
216 const deUint32 isFalse = (deUint32(cmp0.isFalse)<<0)
217 | (deUint32(cmp1.isFalse)<<1);
219 // Interpolation parameters
220 const float f0 = fBounds.x();
221 const float f1 = fBounds.y();
224 const float pcfErr = computeFixedPointError(prec.pcfBits);
225 const float resErr = computeFixedPointError(prec.resultBits);
226 const float totalErr = pcfErr+resErr;
228 // Iterate over all valid combinations.
229 for (deUint32 comb = 0; comb < (1<<2); comb++)
231 // Filter out invalid combinations.
232 if (((comb & isTrue) | (~comb & isFalse)) != (1<<2)-1)
235 const bool cmp0True = ((comb>>0)&1) != 0;
236 const bool cmp1True = ((comb>>1)&1) != 0;
238 const float ref0 = cmp0True ? 1.0f : 0.0f;
239 const float ref1 = cmp1True ? 1.0f : 0.0f;
241 const float v0 = ref0*(1.0f-f0) + ref1*f0;
242 const float v1 = ref0*(1.0f-f1) + ref1*f1;
243 const float minV = de::min(v0, v1);
244 const float maxV = de::max(v0, v1);
245 const float minR = minV-totalErr;
246 const float maxR = maxV+totalErr;
248 if (de::inRange(result, minR, maxR))
255 static inline BVec4 extractBVec4 (const deUint32 val, int offset)
257 return BVec4(((val>>(offset+0))&1) != 0,
258 ((val>>(offset+1))&1) != 0,
259 ((val>>(offset+2))&1) != 0,
260 ((val>>(offset+3))&1) != 0);
263 static bool isBilinearAnyCompareValid (const Sampler::CompareMode compareMode,
264 const TexComparePrecision& prec,
266 const float cmpReference,
268 const bool isFixedPointDepth)
270 DE_ASSERT(prec.pcfBits == 0);
272 const float d0 = depths[0];
273 const float d1 = depths[1];
274 const float d2 = depths[2];
275 const float d3 = depths[3];
277 const CmpResultSet cmp0 = execCompare(compareMode, d0, cmpReference, prec.referenceBits, isFixedPointDepth);
278 const CmpResultSet cmp1 = execCompare(compareMode, d1, cmpReference, prec.referenceBits, isFixedPointDepth);
279 const CmpResultSet cmp2 = execCompare(compareMode, d2, cmpReference, prec.referenceBits, isFixedPointDepth);
280 const CmpResultSet cmp3 = execCompare(compareMode, d3, cmpReference, prec.referenceBits, isFixedPointDepth);
282 const bool canBeTrue = cmp0.isTrue || cmp1.isTrue || cmp2.isTrue || cmp3.isTrue;
283 const bool canBeFalse = cmp0.isFalse || cmp1.isFalse || cmp2.isFalse || cmp3.isFalse;
285 const float resErr = computeFixedPointError(prec.resultBits);
287 const float minBound = canBeFalse ? 0.0f : 1.0f;
288 const float maxBound = canBeTrue ? 1.0f : 0.0f;
290 return de::inRange(result, minBound-resErr, maxBound+resErr);
293 static bool isBilinearPCFCompareValid (const Sampler::CompareMode compareMode,
294 const TexComparePrecision& prec,
298 const float cmpReference,
300 const bool isFixedPointDepth)
302 DE_ASSERT(0.0f <= xBounds.x() && xBounds.x() <= xBounds.y() && xBounds.y() <= 1.0f);
303 DE_ASSERT(0.0f <= yBounds.x() && yBounds.x() <= yBounds.y() && yBounds.y() <= 1.0f);
304 DE_ASSERT(prec.pcfBits > 0);
306 const float d0 = depths[0];
307 const float d1 = depths[1];
308 const float d2 = depths[2];
309 const float d3 = depths[3];
311 const CmpResultSet cmp0 = execCompare(compareMode, d0, cmpReference, prec.referenceBits, isFixedPointDepth);
312 const CmpResultSet cmp1 = execCompare(compareMode, d1, cmpReference, prec.referenceBits, isFixedPointDepth);
313 const CmpResultSet cmp2 = execCompare(compareMode, d2, cmpReference, prec.referenceBits, isFixedPointDepth);
314 const CmpResultSet cmp3 = execCompare(compareMode, d3, cmpReference, prec.referenceBits, isFixedPointDepth);
316 const deUint32 isTrue = (deUint32(cmp0.isTrue)<<0)
317 | (deUint32(cmp1.isTrue)<<1)
318 | (deUint32(cmp2.isTrue)<<2)
319 | (deUint32(cmp3.isTrue)<<3);
320 const deUint32 isFalse = (deUint32(cmp0.isFalse)<<0)
321 | (deUint32(cmp1.isFalse)<<1)
322 | (deUint32(cmp2.isFalse)<<2)
323 | (deUint32(cmp3.isFalse)<<3);
325 // Interpolation parameters
326 const float x0 = xBounds.x();
327 const float x1 = xBounds.y();
328 const float y0 = yBounds.x();
329 const float y1 = yBounds.y();
332 const float pcfErr = computeFixedPointError(prec.pcfBits);
333 const float resErr = computeFixedPointError(prec.resultBits);
334 const float totalErr = pcfErr+resErr;
336 // Iterate over all valid combinations.
337 // \note It is not enough to compute minmax over all possible result sets, as ranges may
338 // not necessarily overlap, i.e. there are gaps between valid ranges.
339 for (deUint32 comb = 0; comb < (1<<4); comb++)
341 // Filter out invalid combinations:
342 // 1) True bit is set in comb but not in isTrue => sample can not be true
343 // 2) True bit is NOT set in comb and not in isFalse => sample can not be false
344 if (((comb & isTrue) | (~comb & isFalse)) != (1<<4)-1)
347 const BVec4 cmpTrue = extractBVec4(comb, 0);
348 const Vec4 refVal = select(Vec4(1.0f), Vec4(0.0f), cmpTrue);
350 const float v0 = bilinearInterpolate(refVal, x0, y0);
351 const float v1 = bilinearInterpolate(refVal, x1, y0);
352 const float v2 = bilinearInterpolate(refVal, x0, y1);
353 const float v3 = bilinearInterpolate(refVal, x1, y1);
354 const float minV = de::min(v0, de::min(v1, de::min(v2, v3)));
355 const float maxV = de::max(v0, de::max(v1, de::max(v2, v3)));
356 const float minR = minV-totalErr;
357 const float maxR = maxV+totalErr;
359 if (de::inRange(result, minR, maxR))
366 static bool isBilinearCompareValid (const Sampler::CompareMode compareMode,
367 const TexComparePrecision& prec,
371 const float cmpReference,
373 const bool isFixedPointDepth)
375 if (prec.pcfBits > 0)
376 return isBilinearPCFCompareValid(compareMode, prec, depths, xBounds, yBounds, cmpReference, result, isFixedPointDepth);
378 return isBilinearAnyCompareValid(compareMode, prec, depths, cmpReference, result, isFixedPointDepth);
381 static bool isTrilinearAnyCompareValid (const Sampler::CompareMode compareMode,
382 const TexComparePrecision& prec,
385 const float cmpReference,
387 const bool isFixedPointDepth)
389 DE_ASSERT(prec.pcfBits == 0);
391 const CmpResultSet cmp00 = execCompare(compareMode, depths0[0], cmpReference, prec.referenceBits, isFixedPointDepth);
392 const CmpResultSet cmp01 = execCompare(compareMode, depths0[1], cmpReference, prec.referenceBits, isFixedPointDepth);
393 const CmpResultSet cmp02 = execCompare(compareMode, depths0[2], cmpReference, prec.referenceBits, isFixedPointDepth);
394 const CmpResultSet cmp03 = execCompare(compareMode, depths0[3], cmpReference, prec.referenceBits, isFixedPointDepth);
396 const CmpResultSet cmp10 = execCompare(compareMode, depths1[0], cmpReference, prec.referenceBits, isFixedPointDepth);
397 const CmpResultSet cmp11 = execCompare(compareMode, depths1[1], cmpReference, prec.referenceBits, isFixedPointDepth);
398 const CmpResultSet cmp12 = execCompare(compareMode, depths1[2], cmpReference, prec.referenceBits, isFixedPointDepth);
399 const CmpResultSet cmp13 = execCompare(compareMode, depths1[3], cmpReference, prec.referenceBits, isFixedPointDepth);
401 const bool canBeTrue = cmp00.isTrue ||
409 const bool canBeFalse = cmp00.isFalse ||
418 const float resErr = computeFixedPointError(prec.resultBits);
420 const float minBound = canBeFalse ? 0.0f : 1.0f;
421 const float maxBound = canBeTrue ? 1.0f : 0.0f;
423 return de::inRange(result, minBound-resErr, maxBound+resErr);
426 static bool isTrilinearPCFCompareValid (const Sampler::CompareMode compareMode,
427 const TexComparePrecision& prec,
430 const Vec2& xBounds0,
431 const Vec2& yBounds0,
432 const Vec2& xBounds1,
433 const Vec2& yBounds1,
435 const float cmpReference,
437 const bool isFixedPointDepth)
439 DE_ASSERT(0.0f <= xBounds0.x() && xBounds0.x() <= xBounds0.y() && xBounds0.y() <= 1.0f);
440 DE_ASSERT(0.0f <= yBounds0.x() && yBounds0.x() <= yBounds0.y() && yBounds0.y() <= 1.0f);
441 DE_ASSERT(0.0f <= xBounds1.x() && xBounds1.x() <= xBounds1.y() && xBounds1.y() <= 1.0f);
442 DE_ASSERT(0.0f <= yBounds1.x() && yBounds1.x() <= yBounds1.y() && yBounds1.y() <= 1.0f);
443 DE_ASSERT(0.0f <= fBounds.x() && fBounds.x() <= fBounds.y() && fBounds.y() <= 1.0f);
444 DE_ASSERT(prec.pcfBits > 0);
446 const CmpResultSet cmp00 = execCompare(compareMode, depths0[0], cmpReference, prec.referenceBits, isFixedPointDepth);
447 const CmpResultSet cmp01 = execCompare(compareMode, depths0[1], cmpReference, prec.referenceBits, isFixedPointDepth);
448 const CmpResultSet cmp02 = execCompare(compareMode, depths0[2], cmpReference, prec.referenceBits, isFixedPointDepth);
449 const CmpResultSet cmp03 = execCompare(compareMode, depths0[3], cmpReference, prec.referenceBits, isFixedPointDepth);
451 const CmpResultSet cmp10 = execCompare(compareMode, depths1[0], cmpReference, prec.referenceBits, isFixedPointDepth);
452 const CmpResultSet cmp11 = execCompare(compareMode, depths1[1], cmpReference, prec.referenceBits, isFixedPointDepth);
453 const CmpResultSet cmp12 = execCompare(compareMode, depths1[2], cmpReference, prec.referenceBits, isFixedPointDepth);
454 const CmpResultSet cmp13 = execCompare(compareMode, depths1[3], cmpReference, prec.referenceBits, isFixedPointDepth);
456 const deUint32 isTrue = (deUint32(cmp00.isTrue)<<0)
457 | (deUint32(cmp01.isTrue)<<1)
458 | (deUint32(cmp02.isTrue)<<2)
459 | (deUint32(cmp03.isTrue)<<3)
460 | (deUint32(cmp10.isTrue)<<4)
461 | (deUint32(cmp11.isTrue)<<5)
462 | (deUint32(cmp12.isTrue)<<6)
463 | (deUint32(cmp13.isTrue)<<7);
464 const deUint32 isFalse = (deUint32(cmp00.isFalse)<<0)
465 | (deUint32(cmp01.isFalse)<<1)
466 | (deUint32(cmp02.isFalse)<<2)
467 | (deUint32(cmp03.isFalse)<<3)
468 | (deUint32(cmp10.isFalse)<<4)
469 | (deUint32(cmp11.isFalse)<<5)
470 | (deUint32(cmp12.isFalse)<<6)
471 | (deUint32(cmp13.isFalse)<<7);
474 const float pcfErr = computeFixedPointError(prec.pcfBits);
475 const float resErr = computeFixedPointError(prec.resultBits);
476 const float totalErr = pcfErr+resErr;
478 // Iterate over all valid combinations.
479 for (deUint32 comb = 0; comb < (1<<8); comb++)
481 // Filter out invalid combinations.
482 if (((comb & isTrue) | (~comb & isFalse)) != (1<<8)-1)
485 const BVec4 cmpTrue0 = extractBVec4(comb, 0);
486 const BVec4 cmpTrue1 = extractBVec4(comb, 4);
487 const Vec4 refVal0 = select(Vec4(1.0f), Vec4(0.0f), cmpTrue0);
488 const Vec4 refVal1 = select(Vec4(1.0f), Vec4(0.0f), cmpTrue1);
490 // Bilinear interpolation within levels.
491 const float v00 = bilinearInterpolate(refVal0, xBounds0.x(), yBounds0.x());
492 const float v01 = bilinearInterpolate(refVal0, xBounds0.y(), yBounds0.x());
493 const float v02 = bilinearInterpolate(refVal0, xBounds0.x(), yBounds0.y());
494 const float v03 = bilinearInterpolate(refVal0, xBounds0.y(), yBounds0.y());
495 const float minV0 = de::min(v00, de::min(v01, de::min(v02, v03)));
496 const float maxV0 = de::max(v00, de::max(v01, de::max(v02, v03)));
498 const float v10 = bilinearInterpolate(refVal1, xBounds1.x(), yBounds1.x());
499 const float v11 = bilinearInterpolate(refVal1, xBounds1.y(), yBounds1.x());
500 const float v12 = bilinearInterpolate(refVal1, xBounds1.x(), yBounds1.y());
501 const float v13 = bilinearInterpolate(refVal1, xBounds1.y(), yBounds1.y());
502 const float minV1 = de::min(v10, de::min(v11, de::min(v12, v13)));
503 const float maxV1 = de::max(v10, de::max(v11, de::max(v12, v13)));
505 // Compute min-max bounds by filtering between minimum bounds and maximum bounds between levels.
506 // HW can end up choosing pretty much any of samples between levels, and thus interpolating
507 // between minimums should yield lower bound for range, and same for upper bound.
508 // \todo [2013-07-17 pyry] This seems separable? Can this be optimized? At least ranges could be pre-computed and later combined.
509 const float minF0 = minV0*(1.0f-fBounds.x()) + minV1*fBounds.x();
510 const float minF1 = minV0*(1.0f-fBounds.y()) + minV1*fBounds.y();
511 const float maxF0 = maxV0*(1.0f-fBounds.x()) + maxV1*fBounds.x();
512 const float maxF1 = maxV0*(1.0f-fBounds.y()) + maxV1*fBounds.y();
514 const float minF = de::min(minF0, minF1);
515 const float maxF = de::max(maxF0, maxF1);
517 const float minR = minF-totalErr;
518 const float maxR = maxF+totalErr;
520 if (de::inRange(result, minR, maxR))
527 static bool isTrilinearCompareValid (const Sampler::CompareMode compareMode,
528 const TexComparePrecision& prec,
531 const Vec2& xBounds0,
532 const Vec2& yBounds0,
533 const Vec2& xBounds1,
534 const Vec2& yBounds1,
536 const float cmpReference,
538 const bool isFixedPointDepth)
540 if (prec.pcfBits > 0)
541 return isTrilinearPCFCompareValid(compareMode, prec, depths0, depths1, xBounds0, yBounds0, xBounds1, yBounds1, fBounds, cmpReference, result, isFixedPointDepth);
543 return isTrilinearAnyCompareValid(compareMode, prec, depths0, depths1, cmpReference, result, isFixedPointDepth);
546 static bool isNearestCompareResultValid (const ConstPixelBufferAccess& level,
547 const Sampler& sampler,
548 const TexComparePrecision& prec,
551 const float cmpReference,
554 const bool isFixedPointDepth = isFixedPointDepthTextureFormat(level.getFormat());
555 const Vec2 uBounds = computeNonNormalizedCoordBounds(sampler.normalizedCoords, level.getWidth(), coord.x(), prec.coordBits.x(), prec.uvwBits.x());
556 const Vec2 vBounds = computeNonNormalizedCoordBounds(sampler.normalizedCoords, level.getHeight(), coord.y(), prec.coordBits.y(), prec.uvwBits.y());
558 // Integer coordinates - without wrap mode
559 const int minI = deFloorFloatToInt32(uBounds.x());
560 const int maxI = deFloorFloatToInt32(uBounds.y());
561 const int minJ = deFloorFloatToInt32(vBounds.x());
562 const int maxJ = deFloorFloatToInt32(vBounds.y());
564 for (int j = minJ; j <= maxJ; j++)
566 for (int i = minI; i <= maxI; i++)
568 const int x = wrap(sampler.wrapS, i, level.getWidth());
569 const int y = wrap(sampler.wrapT, j, level.getHeight());
570 const float depth = lookupDepth(level, sampler, x, y, coordZ);
571 const CmpResultSet resSet = execCompare(sampler.compare, depth, cmpReference, prec.referenceBits, isFixedPointDepth);
573 if (isResultInSet(resSet, result, prec.resultBits))
581 static bool isLinearCompareResultValid (const ConstPixelBufferAccess& level,
582 const Sampler& sampler,
583 const TexComparePrecision& prec,
586 const float cmpReference,
589 const bool isFixedPointDepth = isFixedPointDepthTextureFormat(level.getFormat());
590 const Vec2 uBounds = computeNonNormalizedCoordBounds(sampler.normalizedCoords, level.getWidth(), coord.x(), prec.coordBits.x(), prec.uvwBits.x());
591 const Vec2 vBounds = computeNonNormalizedCoordBounds(sampler.normalizedCoords, level.getHeight(), coord.y(), prec.coordBits.y(), prec.uvwBits.y());
593 // Integer coordinate bounds for (x0,y0) - without wrap mode
594 const int minI = deFloorFloatToInt32(uBounds.x()-0.5f);
595 const int maxI = deFloorFloatToInt32(uBounds.y()-0.5f);
596 const int minJ = deFloorFloatToInt32(vBounds.x()-0.5f);
597 const int maxJ = deFloorFloatToInt32(vBounds.y()-0.5f);
599 const int w = level.getWidth();
600 const int h = level.getHeight();
602 // \todo [2013-07-03 pyry] This could be optimized by first computing ranges based on wrap mode.
604 for (int j = minJ; j <= maxJ; j++)
606 for (int i = minI; i <= maxI; i++)
608 // Wrapped coordinates
609 const int x0 = wrap(sampler.wrapS, i , w);
610 const int x1 = wrap(sampler.wrapS, i+1, w);
611 const int y0 = wrap(sampler.wrapT, j , h);
612 const int y1 = wrap(sampler.wrapT, j+1, h);
614 // Bounds for filtering factors
615 const float minA = de::clamp((uBounds.x()-0.5f)-float(i), 0.0f, 1.0f);
616 const float maxA = de::clamp((uBounds.y()-0.5f)-float(i), 0.0f, 1.0f);
617 const float minB = de::clamp((vBounds.x()-0.5f)-float(j), 0.0f, 1.0f);
618 const float maxB = de::clamp((vBounds.y()-0.5f)-float(j), 0.0f, 1.0f);
620 const Vec4 depths (lookupDepth(level, sampler, x0, y0, coordZ),
621 lookupDepth(level, sampler, x1, y0, coordZ),
622 lookupDepth(level, sampler, x0, y1, coordZ),
623 lookupDepth(level, sampler, x1, y1, coordZ));
625 if (isBilinearCompareValid(sampler.compare, prec, depths, Vec2(minA, maxA), Vec2(minB, maxB), cmpReference, result, isFixedPointDepth))
633 static bool isLevelCompareResultValid (const ConstPixelBufferAccess& level,
634 const Sampler& sampler,
635 const Sampler::FilterMode filterMode,
636 const TexComparePrecision& prec,
639 const float cmpReference,
642 if (filterMode == Sampler::LINEAR)
643 return isLinearCompareResultValid(level, sampler, prec, coord, coordZ, cmpReference, result);
645 return isNearestCompareResultValid(level, sampler, prec, coord, coordZ, cmpReference, result);
648 static bool isNearestMipmapLinearCompareResultValid (const ConstPixelBufferAccess& level0,
649 const ConstPixelBufferAccess& level1,
650 const Sampler& sampler,
651 const TexComparePrecision& prec,
655 const float cmpReference,
658 const bool isFixedPointDepth = isFixedPointDepthTextureFormat(level0.getFormat());
660 const int w0 = level0.getWidth();
661 const int w1 = level1.getWidth();
662 const int h0 = level0.getHeight();
663 const int h1 = level1.getHeight();
665 const Vec2 uBounds0 = computeNonNormalizedCoordBounds(sampler.normalizedCoords, w0, coord.x(), prec.coordBits.x(), prec.uvwBits.x());
666 const Vec2 uBounds1 = computeNonNormalizedCoordBounds(sampler.normalizedCoords, w1, coord.x(), prec.coordBits.x(), prec.uvwBits.x());
667 const Vec2 vBounds0 = computeNonNormalizedCoordBounds(sampler.normalizedCoords, h0, coord.y(), prec.coordBits.y(), prec.uvwBits.y());
668 const Vec2 vBounds1 = computeNonNormalizedCoordBounds(sampler.normalizedCoords, h1, coord.y(), prec.coordBits.y(), prec.uvwBits.y());
670 // Integer coordinates - without wrap mode
671 const int minI0 = deFloorFloatToInt32(uBounds0.x());
672 const int maxI0 = deFloorFloatToInt32(uBounds0.y());
673 const int minI1 = deFloorFloatToInt32(uBounds1.x());
674 const int maxI1 = deFloorFloatToInt32(uBounds1.y());
675 const int minJ0 = deFloorFloatToInt32(vBounds0.x());
676 const int maxJ0 = deFloorFloatToInt32(vBounds0.y());
677 const int minJ1 = deFloorFloatToInt32(vBounds1.x());
678 const int maxJ1 = deFloorFloatToInt32(vBounds1.y());
680 for (int j0 = minJ0; j0 <= maxJ0; j0++)
682 for (int i0 = minI0; i0 <= maxI0; i0++)
684 const float depth0 = lookupDepth(level0, sampler, wrap(sampler.wrapS, i0, w0), wrap(sampler.wrapT, j0, h0), coordZ);
686 for (int j1 = minJ1; j1 <= maxJ1; j1++)
688 for (int i1 = minI1; i1 <= maxI1; i1++)
690 const float depth1 = lookupDepth(level1, sampler, wrap(sampler.wrapS, i1, w1), wrap(sampler.wrapT, j1, h1), coordZ);
692 if (isLinearCompareValid(sampler.compare, prec, Vec2(depth0, depth1), fBounds, cmpReference, result, isFixedPointDepth))
702 static bool isLinearMipmapLinearCompareResultValid (const ConstPixelBufferAccess& level0,
703 const ConstPixelBufferAccess& level1,
704 const Sampler& sampler,
705 const TexComparePrecision& prec,
709 const float cmpReference,
712 const bool isFixedPointDepth = isFixedPointDepthTextureFormat(level0.getFormat());
714 // \todo [2013-07-04 pyry] This is strictly not correct as coordinates between levels should be dependent.
715 // Right now this allows pairing any two valid bilinear quads.
717 const int w0 = level0.getWidth();
718 const int w1 = level1.getWidth();
719 const int h0 = level0.getHeight();
720 const int h1 = level1.getHeight();
722 const Vec2 uBounds0 = computeNonNormalizedCoordBounds(sampler.normalizedCoords, w0, coord.x(), prec.coordBits.x(), prec.uvwBits.x());
723 const Vec2 uBounds1 = computeNonNormalizedCoordBounds(sampler.normalizedCoords, w1, coord.x(), prec.coordBits.x(), prec.uvwBits.x());
724 const Vec2 vBounds0 = computeNonNormalizedCoordBounds(sampler.normalizedCoords, h0, coord.y(), prec.coordBits.y(), prec.uvwBits.y());
725 const Vec2 vBounds1 = computeNonNormalizedCoordBounds(sampler.normalizedCoords, h1, coord.y(), prec.coordBits.y(), prec.uvwBits.y());
727 // Integer coordinates - without wrap mode
728 const int minI0 = deFloorFloatToInt32(uBounds0.x()-0.5f);
729 const int maxI0 = deFloorFloatToInt32(uBounds0.y()-0.5f);
730 const int minI1 = deFloorFloatToInt32(uBounds1.x()-0.5f);
731 const int maxI1 = deFloorFloatToInt32(uBounds1.y()-0.5f);
732 const int minJ0 = deFloorFloatToInt32(vBounds0.x()-0.5f);
733 const int maxJ0 = deFloorFloatToInt32(vBounds0.y()-0.5f);
734 const int minJ1 = deFloorFloatToInt32(vBounds1.x()-0.5f);
735 const int maxJ1 = deFloorFloatToInt32(vBounds1.y()-0.5f);
737 for (int j0 = minJ0; j0 <= maxJ0; j0++)
739 for (int i0 = minI0; i0 <= maxI0; i0++)
741 const float minA0 = de::clamp((uBounds0.x()-0.5f)-float(i0), 0.0f, 1.0f);
742 const float maxA0 = de::clamp((uBounds0.y()-0.5f)-float(i0), 0.0f, 1.0f);
743 const float minB0 = de::clamp((vBounds0.x()-0.5f)-float(j0), 0.0f, 1.0f);
744 const float maxB0 = de::clamp((vBounds0.y()-0.5f)-float(j0), 0.0f, 1.0f);
748 const int x0 = wrap(sampler.wrapS, i0 , w0);
749 const int x1 = wrap(sampler.wrapS, i0+1, w0);
750 const int y0 = wrap(sampler.wrapT, j0 , h0);
751 const int y1 = wrap(sampler.wrapT, j0+1, h0);
753 depths0[0] = lookupDepth(level0, sampler, x0, y0, coordZ);
754 depths0[1] = lookupDepth(level0, sampler, x1, y0, coordZ);
755 depths0[2] = lookupDepth(level0, sampler, x0, y1, coordZ);
756 depths0[3] = lookupDepth(level0, sampler, x1, y1, coordZ);
759 for (int j1 = minJ1; j1 <= maxJ1; j1++)
761 for (int i1 = minI1; i1 <= maxI1; i1++)
763 const float minA1 = de::clamp((uBounds1.x()-0.5f)-float(i1), 0.0f, 1.0f);
764 const float maxA1 = de::clamp((uBounds1.y()-0.5f)-float(i1), 0.0f, 1.0f);
765 const float minB1 = de::clamp((vBounds1.x()-0.5f)-float(j1), 0.0f, 1.0f);
766 const float maxB1 = de::clamp((vBounds1.y()-0.5f)-float(j1), 0.0f, 1.0f);
770 const int x0 = wrap(sampler.wrapS, i1 , w1);
771 const int x1 = wrap(sampler.wrapS, i1+1, w1);
772 const int y0 = wrap(sampler.wrapT, j1 , h1);
773 const int y1 = wrap(sampler.wrapT, j1+1, h1);
775 depths1[0] = lookupDepth(level1, sampler, x0, y0, coordZ);
776 depths1[1] = lookupDepth(level1, sampler, x1, y0, coordZ);
777 depths1[2] = lookupDepth(level1, sampler, x0, y1, coordZ);
778 depths1[3] = lookupDepth(level1, sampler, x1, y1, coordZ);
781 if (isTrilinearCompareValid(sampler.compare, prec, depths0, depths1,
782 Vec2(minA0, maxA0), Vec2(minB0, maxB0),
783 Vec2(minA1, maxA1), Vec2(minB1, maxB1),
784 fBounds, cmpReference, result, isFixedPointDepth))
794 static bool isMipmapLinearCompareResultValid (const ConstPixelBufferAccess& level0,
795 const ConstPixelBufferAccess& level1,
796 const Sampler& sampler,
797 const Sampler::FilterMode levelFilter,
798 const TexComparePrecision& prec,
802 const float cmpReference,
805 if (levelFilter == Sampler::LINEAR)
806 return isLinearMipmapLinearCompareResultValid(level0, level1, sampler, prec, coord, coordZ, fBounds, cmpReference, result);
808 return isNearestMipmapLinearCompareResultValid(level0, level1, sampler, prec, coord, coordZ, fBounds, cmpReference, result);
811 bool isTexCompareResultValid (const Texture2DView& texture,
812 const Sampler& sampler,
813 const TexComparePrecision& prec,
815 const Vec2& lodBounds,
816 const float cmpReference,
819 const float minLod = lodBounds.x();
820 const float maxLod = lodBounds.y();
821 const bool canBeMagnified = minLod <= sampler.lodThreshold;
822 const bool canBeMinified = maxLod > sampler.lodThreshold;
824 DE_ASSERT(isSamplerSupported(sampler));
828 if (isLevelCompareResultValid(texture.getLevel(0), sampler, sampler.magFilter, prec, coord, 0, cmpReference, result))
834 const bool isNearestMipmap = isNearestMipmapFilter(sampler.minFilter);
835 const bool isLinearMipmap = isLinearMipmapFilter(sampler.minFilter);
836 const int minTexLevel = 0;
837 const int maxTexLevel = texture.getNumLevels()-1;
839 DE_ASSERT(minTexLevel < maxTexLevel);
843 const int minLevel = de::clamp((int)deFloatFloor(minLod), minTexLevel, maxTexLevel-1);
844 const int maxLevel = de::clamp((int)deFloatFloor(maxLod), minTexLevel, maxTexLevel-1);
846 DE_ASSERT(minLevel <= maxLevel);
848 for (int level = minLevel; level <= maxLevel; level++)
850 const float minF = de::clamp(minLod - float(level), 0.0f, 1.0f);
851 const float maxF = de::clamp(maxLod - float(level), 0.0f, 1.0f);
853 if (isMipmapLinearCompareResultValid(texture.getLevel(level), texture.getLevel(level+1), sampler, getLevelFilter(sampler.minFilter), prec, coord, 0, Vec2(minF, maxF), cmpReference, result))
857 else if (isNearestMipmap)
859 // \note The accurate formula for nearest mipmapping is level = ceil(lod + 0.5) - 1 but Khronos has made
860 // decision to allow floor(lod + 0.5) as well.
861 const int minLevel = de::clamp((int)deFloatCeil(minLod + 0.5f) - 1, minTexLevel, maxTexLevel);
862 const int maxLevel = de::clamp((int)deFloatFloor(maxLod + 0.5f), minTexLevel, maxTexLevel);
864 DE_ASSERT(minLevel <= maxLevel);
866 for (int level = minLevel; level <= maxLevel; level++)
868 if (isLevelCompareResultValid(texture.getLevel(level), sampler, getLevelFilter(sampler.minFilter), prec, coord, 0, cmpReference, result))
874 if (isLevelCompareResultValid(texture.getLevel(0), sampler, sampler.minFilter, prec, coord, 0, cmpReference, result))
882 static bool isSeamplessLinearMipmapLinearCompareResultValid (const TextureCubeView& texture,
883 const int baseLevelNdx,
884 const Sampler& sampler,
885 const TexComparePrecision& prec,
886 const CubeFaceFloatCoords& coords,
888 const float cmpReference,
891 const bool isFixedPointDepth = isFixedPointDepthTextureFormat(texture.getLevelFace(baseLevelNdx, CUBEFACE_NEGATIVE_X).getFormat());
892 const int size0 = texture.getLevelFace(baseLevelNdx, coords.face).getWidth();
893 const int size1 = texture.getLevelFace(baseLevelNdx+1, coords.face).getWidth();
895 const Vec2 uBounds0 = computeNonNormalizedCoordBounds(sampler.normalizedCoords, size0, coords.s, prec.coordBits.x(), prec.uvwBits.x());
896 const Vec2 uBounds1 = computeNonNormalizedCoordBounds(sampler.normalizedCoords, size1, coords.s, prec.coordBits.x(), prec.uvwBits.x());
897 const Vec2 vBounds0 = computeNonNormalizedCoordBounds(sampler.normalizedCoords, size0, coords.t, prec.coordBits.y(), prec.uvwBits.y());
898 const Vec2 vBounds1 = computeNonNormalizedCoordBounds(sampler.normalizedCoords, size1, coords.t, prec.coordBits.y(), prec.uvwBits.y());
900 // Integer coordinates - without wrap mode
901 const int minI0 = deFloorFloatToInt32(uBounds0.x()-0.5f);
902 const int maxI0 = deFloorFloatToInt32(uBounds0.y()-0.5f);
903 const int minI1 = deFloorFloatToInt32(uBounds1.x()-0.5f);
904 const int maxI1 = deFloorFloatToInt32(uBounds1.y()-0.5f);
905 const int minJ0 = deFloorFloatToInt32(vBounds0.x()-0.5f);
906 const int maxJ0 = deFloorFloatToInt32(vBounds0.y()-0.5f);
907 const int minJ1 = deFloorFloatToInt32(vBounds1.x()-0.5f);
908 const int maxJ1 = deFloorFloatToInt32(vBounds1.y()-0.5f);
910 tcu::ConstPixelBufferAccess faces0[CUBEFACE_LAST];
911 tcu::ConstPixelBufferAccess faces1[CUBEFACE_LAST];
913 for (int face = 0; face < CUBEFACE_LAST; face++)
915 faces0[face] = texture.getLevelFace(baseLevelNdx, CubeFace(face));
916 faces1[face] = texture.getLevelFace(baseLevelNdx+1, CubeFace(face));
919 for (int j0 = minJ0; j0 <= maxJ0; j0++)
921 for (int i0 = minI0; i0 <= maxI0; i0++)
923 const float minA0 = de::clamp((uBounds0.x()-0.5f)-float(i0), 0.0f, 1.0f);
924 const float maxA0 = de::clamp((uBounds0.y()-0.5f)-float(i0), 0.0f, 1.0f);
925 const float minB0 = de::clamp((vBounds0.x()-0.5f)-float(j0), 0.0f, 1.0f);
926 const float maxB0 = de::clamp((vBounds0.y()-0.5f)-float(j0), 0.0f, 1.0f);
930 const CubeFaceIntCoords c00 = remapCubeEdgeCoords(CubeFaceIntCoords(coords.face, IVec2(i0+0, j0+0)), size0);
931 const CubeFaceIntCoords c10 = remapCubeEdgeCoords(CubeFaceIntCoords(coords.face, IVec2(i0+1, j0+0)), size0);
932 const CubeFaceIntCoords c01 = remapCubeEdgeCoords(CubeFaceIntCoords(coords.face, IVec2(i0+0, j0+1)), size0);
933 const CubeFaceIntCoords c11 = remapCubeEdgeCoords(CubeFaceIntCoords(coords.face, IVec2(i0+1, j0+1)), size0);
935 // If any of samples is out of both edges, implementations can do pretty much anything according to spec.
936 // \todo [2013-07-08 pyry] Test the special case where all corner pixels have exactly the same color.
937 if (c00.face == CUBEFACE_LAST || c01.face == CUBEFACE_LAST || c10.face == CUBEFACE_LAST || c11.face == CUBEFACE_LAST)
940 depths0[0] = lookupDepthNoBorder(faces0[c00.face], sampler, c00.s, c00.t);
941 depths0[1] = lookupDepthNoBorder(faces0[c10.face], sampler, c10.s, c10.t);
942 depths0[2] = lookupDepthNoBorder(faces0[c01.face], sampler, c01.s, c01.t);
943 depths0[3] = lookupDepthNoBorder(faces0[c11.face], sampler, c11.s, c11.t);
946 for (int j1 = minJ1; j1 <= maxJ1; j1++)
948 for (int i1 = minI1; i1 <= maxI1; i1++)
950 const float minA1 = de::clamp((uBounds1.x()-0.5f)-float(i1), 0.0f, 1.0f);
951 const float maxA1 = de::clamp((uBounds1.y()-0.5f)-float(i1), 0.0f, 1.0f);
952 const float minB1 = de::clamp((vBounds1.x()-0.5f)-float(j1), 0.0f, 1.0f);
953 const float maxB1 = de::clamp((vBounds1.y()-0.5f)-float(j1), 0.0f, 1.0f);
957 const CubeFaceIntCoords c00 = remapCubeEdgeCoords(CubeFaceIntCoords(coords.face, IVec2(i1+0, j1+0)), size1);
958 const CubeFaceIntCoords c10 = remapCubeEdgeCoords(CubeFaceIntCoords(coords.face, IVec2(i1+1, j1+0)), size1);
959 const CubeFaceIntCoords c01 = remapCubeEdgeCoords(CubeFaceIntCoords(coords.face, IVec2(i1+0, j1+1)), size1);
960 const CubeFaceIntCoords c11 = remapCubeEdgeCoords(CubeFaceIntCoords(coords.face, IVec2(i1+1, j1+1)), size1);
962 if (c00.face == CUBEFACE_LAST || c01.face == CUBEFACE_LAST || c10.face == CUBEFACE_LAST || c11.face == CUBEFACE_LAST)
965 depths1[0] = lookupDepthNoBorder(faces1[c00.face], sampler, c00.s, c00.t);
966 depths1[1] = lookupDepthNoBorder(faces1[c10.face], sampler, c10.s, c10.t);
967 depths1[2] = lookupDepthNoBorder(faces1[c01.face], sampler, c01.s, c01.t);
968 depths1[3] = lookupDepthNoBorder(faces1[c11.face], sampler, c11.s, c11.t);
972 if (isTrilinearCompareValid(sampler.compare, prec, depths0, depths1,
973 Vec2(minA0, maxA0), Vec2(minB0, maxB0),
974 Vec2(minA1, maxA1), Vec2(minB1, maxB1),
975 fBounds, cmpReference, result, isFixedPointDepth))
985 static bool isCubeMipmapLinearCompareResultValid (const TextureCubeView& texture,
986 const int baseLevelNdx,
987 const Sampler& sampler,
988 const Sampler::FilterMode levelFilter,
989 const TexComparePrecision& prec,
990 const CubeFaceFloatCoords& coords,
992 const float cmpReference,
995 if (levelFilter == Sampler::LINEAR)
997 if (sampler.seamlessCubeMap)
998 return isSeamplessLinearMipmapLinearCompareResultValid(texture, baseLevelNdx, sampler, prec, coords, fBounds, cmpReference, result);
1000 return isLinearMipmapLinearCompareResultValid(texture.getLevelFace(baseLevelNdx, coords.face),
1001 texture.getLevelFace(baseLevelNdx+1, coords.face),
1002 sampler, prec, Vec2(coords.s, coords.t), 0, fBounds, cmpReference, result);
1005 return isNearestMipmapLinearCompareResultValid(texture.getLevelFace(baseLevelNdx, coords.face),
1006 texture.getLevelFace(baseLevelNdx+1, coords.face),
1007 sampler, prec, Vec2(coords.s, coords.t), 0, fBounds, cmpReference, result);
1010 static bool isSeamlessLinearCompareResultValid (const TextureCubeView& texture,
1012 const Sampler& sampler,
1013 const TexComparePrecision& prec,
1014 const CubeFaceFloatCoords& coords,
1015 const float cmpReference,
1018 const bool isFixedPointDepth = isFixedPointDepthTextureFormat(texture.getLevelFace(levelNdx, CUBEFACE_NEGATIVE_X).getFormat());
1019 const int size = texture.getLevelFace(levelNdx, coords.face).getWidth();
1021 const Vec2 uBounds = computeNonNormalizedCoordBounds(sampler.normalizedCoords, size, coords.s, prec.coordBits.x(), prec.uvwBits.x());
1022 const Vec2 vBounds = computeNonNormalizedCoordBounds(sampler.normalizedCoords, size, coords.t, prec.coordBits.y(), prec.uvwBits.y());
1024 // Integer coordinate bounds for (x0,y0) - without wrap mode
1025 const int minI = deFloorFloatToInt32(uBounds.x()-0.5f);
1026 const int maxI = deFloorFloatToInt32(uBounds.y()-0.5f);
1027 const int minJ = deFloorFloatToInt32(vBounds.x()-0.5f);
1028 const int maxJ = deFloorFloatToInt32(vBounds.y()-0.5f);
1031 ConstPixelBufferAccess faces[CUBEFACE_LAST];
1032 for (int face = 0; face < CUBEFACE_LAST; face++)
1033 faces[face] = texture.getLevelFace(levelNdx, CubeFace(face));
1035 for (int j = minJ; j <= maxJ; j++)
1037 for (int i = minI; i <= maxI; i++)
1039 const CubeFaceIntCoords c00 = remapCubeEdgeCoords(CubeFaceIntCoords(coords.face, IVec2(i+0, j+0)), size);
1040 const CubeFaceIntCoords c10 = remapCubeEdgeCoords(CubeFaceIntCoords(coords.face, IVec2(i+1, j+0)), size);
1041 const CubeFaceIntCoords c01 = remapCubeEdgeCoords(CubeFaceIntCoords(coords.face, IVec2(i+0, j+1)), size);
1042 const CubeFaceIntCoords c11 = remapCubeEdgeCoords(CubeFaceIntCoords(coords.face, IVec2(i+1, j+1)), size);
1044 // If any of samples is out of both edges, implementations can do pretty much anything according to spec.
1045 // \todo [2013-07-08 pyry] Test the special case where all corner pixels have exactly the same color.
1046 if (c00.face == CUBEFACE_LAST || c01.face == CUBEFACE_LAST || c10.face == CUBEFACE_LAST || c11.face == CUBEFACE_LAST)
1049 // Bounds for filtering factors
1050 const float minA = de::clamp((uBounds.x()-0.5f)-float(i), 0.0f, 1.0f);
1051 const float maxA = de::clamp((uBounds.y()-0.5f)-float(i), 0.0f, 1.0f);
1052 const float minB = de::clamp((vBounds.x()-0.5f)-float(j), 0.0f, 1.0f);
1053 const float maxB = de::clamp((vBounds.y()-0.5f)-float(j), 0.0f, 1.0f);
1056 depths[0] = lookupDepthNoBorder(faces[c00.face], sampler, c00.s, c00.t);
1057 depths[1] = lookupDepthNoBorder(faces[c10.face], sampler, c10.s, c10.t);
1058 depths[2] = lookupDepthNoBorder(faces[c01.face], sampler, c01.s, c01.t);
1059 depths[3] = lookupDepthNoBorder(faces[c11.face], sampler, c11.s, c11.t);
1061 if (isBilinearCompareValid(sampler.compare, prec, depths, Vec2(minA, maxA), Vec2(minB, maxB), cmpReference, result, isFixedPointDepth))
1069 static bool isCubeLevelCompareResultValid (const TextureCubeView& texture,
1071 const Sampler& sampler,
1072 const Sampler::FilterMode filterMode,
1073 const TexComparePrecision& prec,
1074 const CubeFaceFloatCoords& coords,
1075 const float cmpReference,
1078 if (filterMode == Sampler::LINEAR)
1080 if (sampler.seamlessCubeMap)
1081 return isSeamlessLinearCompareResultValid(texture, levelNdx, sampler, prec, coords, cmpReference, result);
1083 return isLinearCompareResultValid(texture.getLevelFace(levelNdx, coords.face), sampler, prec, Vec2(coords.s, coords.t), 0, cmpReference, result);
1086 return isNearestCompareResultValid(texture.getLevelFace(levelNdx, coords.face), sampler, prec, Vec2(coords.s, coords.t), 0, cmpReference, result);
1089 static bool isCubeLevelCompareResultValid (const TextureCubeArrayView& texture,
1090 const int baseLevelNdx,
1091 const Sampler& sampler,
1092 const Sampler::FilterMode filterMode,
1093 const TexComparePrecision& prec,
1094 const CubeFaceFloatCoords& coords,
1096 const float cmpReference,
1099 const float depthErr = computeFloatingPointError(depth, prec.coordBits.z()) + computeFixedPointError(prec.uvwBits.z());
1100 const float minZ = depth - depthErr;
1101 const float maxZ = depth + depthErr;
1102 const int minLayer = de::clamp(deFloorFloatToInt32(minZ + 0.5f), 0, texture.getNumLayers() - 1);
1103 const int maxLayer = de::clamp(deFloorFloatToInt32(maxZ + 0.5f), 0, texture.getNumLayers() - 1);
1104 const int numLevels = texture.getNumLevels();
1106 for (int layer = minLayer; layer <= maxLayer; layer++)
1108 std::vector<tcu::ConstPixelBufferAccess> levelsAtLayer[CUBEFACE_LAST];
1110 for (int faceNdx = 0; faceNdx < CUBEFACE_LAST; faceNdx++)
1112 levelsAtLayer[faceNdx].resize(numLevels);
1114 for (int levelNdx = 0; levelNdx < numLevels; ++levelNdx)
1116 const tcu::ConstPixelBufferAccess& level = texture.getLevel(levelNdx);
1118 levelsAtLayer[faceNdx][levelNdx] = ConstPixelBufferAccess(level.getFormat(), level.getWidth(), level.getHeight(), 1, level.getPixelPtr(0, 0, CUBEFACE_LAST * layer + faceNdx));
1122 const tcu::ConstPixelBufferAccess* levels[CUBEFACE_LAST]
1124 // Such a strange order due to sampleCompare TextureCubeArrayView uses getCubeArrayFaceIndex while in TextureCubeView does not
1125 &levelsAtLayer[1][0],
1126 &levelsAtLayer[0][0],
1127 &levelsAtLayer[3][0],
1128 &levelsAtLayer[2][0],
1129 &levelsAtLayer[5][0],
1130 &levelsAtLayer[4][0],
1133 if (isCubeLevelCompareResultValid(TextureCubeView(numLevels, levels), baseLevelNdx, sampler, filterMode, prec, coords, cmpReference, result))
1140 static bool isCubeMipmapLinearCompareResultValid (const TextureCubeArrayView& texture,
1141 const int baseLevelNdx,
1142 const Sampler& sampler,
1143 const Sampler::FilterMode levelFilter,
1144 const TexComparePrecision& prec,
1145 const CubeFaceFloatCoords& coords,
1147 const Vec2& fBounds,
1148 const float cmpReference,
1151 const float depthErr = computeFloatingPointError(depth, prec.coordBits.z()) + computeFixedPointError(prec.uvwBits.z());
1152 const float minZ = depth - depthErr;
1153 const float maxZ = depth + depthErr;
1154 const int minLayer = de::clamp(deFloorFloatToInt32(minZ + 0.5f), 0, texture.getNumLayers() - 1);
1155 const int maxLayer = de::clamp(deFloorFloatToInt32(maxZ + 0.5f), 0, texture.getNumLayers() - 1);
1156 const int numLevels = texture.getNumLevels();
1158 for (int layer = minLayer; layer <= maxLayer; layer++)
1160 std::vector<tcu::ConstPixelBufferAccess> levelsAtLayer[CUBEFACE_LAST];
1162 for (int faceNdx = 0; faceNdx < CUBEFACE_LAST; faceNdx++)
1164 levelsAtLayer[faceNdx].resize(numLevels);
1166 for (int levelNdx = 0; levelNdx < numLevels; ++levelNdx)
1168 const tcu::ConstPixelBufferAccess& level = texture.getLevel(levelNdx);
1170 levelsAtLayer[faceNdx][levelNdx] = ConstPixelBufferAccess(level.getFormat(), level.getWidth(), level.getHeight(), 1, level.getPixelPtr(0, 0, CUBEFACE_LAST * layer + faceNdx));
1174 const tcu::ConstPixelBufferAccess* levels[CUBEFACE_LAST]
1176 // Such a strange order due to sampleCompare TextureCubeArrayView uses getCubeArrayFaceIndex while in TextureCubeView does not
1177 &levelsAtLayer[1][0],
1178 &levelsAtLayer[0][0],
1179 &levelsAtLayer[3][0],
1180 &levelsAtLayer[2][0],
1181 &levelsAtLayer[5][0],
1182 &levelsAtLayer[4][0],
1185 if (isCubeMipmapLinearCompareResultValid(TextureCubeView(numLevels, levels), baseLevelNdx, sampler, levelFilter, prec, coords, fBounds, cmpReference, result))
1192 static bool isNearestCompareResultValid (const ConstPixelBufferAccess& level,
1193 const Sampler& sampler,
1194 const TexComparePrecision& prec,
1197 const float cmpReference,
1200 const bool isFixedPointDepth = isFixedPointDepthTextureFormat(level.getFormat());
1201 const Vec2 uBounds = computeNonNormalizedCoordBounds(sampler.normalizedCoords, level.getWidth(), coord.x(), prec.coordBits.x(), prec.uvwBits.x());
1203 // Integer coordinates - without wrap mode
1204 const int minI = deFloorFloatToInt32(uBounds.x());
1205 const int maxI = deFloorFloatToInt32(uBounds.y());
1207 for (int i = minI; i <= maxI; i++)
1209 const int x = wrap(sampler.wrapS, i, level.getWidth());
1210 const float depth = lookupDepth(level, sampler, x, coordZ, 0);
1211 const CmpResultSet resSet = execCompare(sampler.compare, depth, cmpReference, prec.referenceBits, isFixedPointDepth);
1213 if (isResultInSet(resSet, result, prec.resultBits))
1220 static bool isLinearCompareResultValid (const ConstPixelBufferAccess& level,
1221 const Sampler& sampler,
1222 const TexComparePrecision& prec,
1225 const float cmpReference,
1228 const bool isFixedPointDepth = isFixedPointDepthTextureFormat(level.getFormat());
1229 const Vec2 uBounds = computeNonNormalizedCoordBounds(sampler.normalizedCoords, level.getWidth(), coord.x(), prec.coordBits.x(), prec.uvwBits.x());
1231 // Integer coordinate bounds for (x0,y0) - without wrap mode
1232 const int minI = deFloorFloatToInt32(uBounds.x() - 0.5f);
1233 const int maxI = deFloorFloatToInt32(uBounds.y() - 0.5f);
1235 const int w = level.getWidth();
1237 // \todo [2013-07-03 pyry] This could be optimized by first computing ranges based on wrap mode.
1239 for (int i = minI; i <= maxI; i++)
1241 // Wrapped coordinates
1242 const int x0 = wrap(sampler.wrapS, i , w);
1243 const int x1 = wrap(sampler.wrapS, i + 1, w);
1245 // Bounds for filtering factors
1246 const float minA = de::clamp((uBounds.x() - 0.5f) - float(i), 0.0f, 1.0f);
1247 const float maxA = de::clamp((uBounds.y() - 0.5f) - float(i), 0.0f, 1.0f);
1249 const Vec2 depths (lookupDepth(level, sampler, x0, coordZ, 0),
1250 lookupDepth(level, sampler, x1, coordZ, 0));
1252 if (isLinearCompareValid(sampler.compare, prec, depths, Vec2(minA, maxA), cmpReference, result, isFixedPointDepth))
1259 static bool isLevelCompareResultValid (const ConstPixelBufferAccess& level,
1260 const Sampler& sampler,
1261 const Sampler::FilterMode filterMode,
1262 const TexComparePrecision& prec,
1265 const float cmpReference,
1268 if (filterMode == Sampler::LINEAR)
1269 return isLinearCompareResultValid(level, sampler, prec, coord, coordZ, cmpReference, result);
1271 return isNearestCompareResultValid(level, sampler, prec, coord, coordZ, cmpReference, result);
1274 static bool isNearestMipmapLinearCompareResultValid (const ConstPixelBufferAccess& level0,
1275 const ConstPixelBufferAccess& level1,
1276 const Sampler& sampler,
1277 const TexComparePrecision& prec,
1280 const Vec2& fBounds,
1281 const float cmpReference,
1285 const bool isFixedPointDepth = isFixedPointDepthTextureFormat(level0.getFormat());
1287 const int w0 = level0.getWidth();
1288 const int w1 = level1.getWidth();
1290 const Vec2 uBounds0 = computeNonNormalizedCoordBounds(sampler.normalizedCoords, w0, coord.x(), prec.coordBits.x(), prec.uvwBits.x());
1291 const Vec2 uBounds1 = computeNonNormalizedCoordBounds(sampler.normalizedCoords, w1, coord.x(), prec.coordBits.x(), prec.uvwBits.x());
1293 // Integer coordinates - without wrap mode
1294 const int minI0 = deFloorFloatToInt32(uBounds0.x());
1295 const int maxI0 = deFloorFloatToInt32(uBounds0.y());
1296 const int minI1 = deFloorFloatToInt32(uBounds1.x());
1297 const int maxI1 = deFloorFloatToInt32(uBounds1.y());
1299 for (int i0 = minI0; i0 <= maxI0; i0++)
1301 const float depth0 = lookupDepth(level0, sampler, wrap(sampler.wrapS, i0, w0), coordZ, 0);
1303 for (int i1 = minI1; i1 <= maxI1; i1++)
1305 const float depth1 = lookupDepth(level1, sampler, wrap(sampler.wrapS, i1, w1), coordZ, 0);
1307 if (isLinearCompareValid(sampler.compare, prec, Vec2(depth0, depth1), fBounds, cmpReference, result, isFixedPointDepth))
1316 static bool isLinearMipmapLinearCompareResultValid (const ConstPixelBufferAccess& level0,
1317 const ConstPixelBufferAccess& level1,
1318 const Sampler& sampler,
1319 const TexComparePrecision& prec,
1322 const Vec2& fBounds,
1323 const float cmpReference,
1327 const bool isFixedPointDepth = isFixedPointDepthTextureFormat(level0.getFormat());
1329 // \todo [2013-07-04 pyry] This is strictly not correct as coordinates between levels should be dependent.
1330 // Right now this allows pairing any two valid bilinear quads.
1332 const int w0 = level0.getWidth();
1333 const int w1 = level1.getWidth();
1335 const Vec2 uBounds0 = computeNonNormalizedCoordBounds(sampler.normalizedCoords, w0, coord.x(), prec.coordBits.x(), prec.uvwBits.x());
1336 const Vec2 uBounds1 = computeNonNormalizedCoordBounds(sampler.normalizedCoords, w1, coord.x(), prec.coordBits.x(), prec.uvwBits.x());
1338 // Integer coordinates - without wrap mode
1339 const int minI0 = deFloorFloatToInt32(uBounds0.x()-0.5f);
1340 const int maxI0 = deFloorFloatToInt32(uBounds0.y()-0.5f);
1341 const int minI1 = deFloorFloatToInt32(uBounds1.x()-0.5f);
1342 const int maxI1 = deFloorFloatToInt32(uBounds1.y()-0.5f);
1344 for (int i0 = minI0; i0 <= maxI0; i0++)
1346 const float minA0 = de::clamp((uBounds0.x() - 0.5f) - float(i0), 0.0f, 1.0f);
1347 const float maxA0 = de::clamp((uBounds0.y() - 0.5f) - float(i0), 0.0f, 1.0f);
1348 const Vec2 ptA0 = Vec2(minA0, maxA0);
1352 const int x0 = wrap(sampler.wrapS, i0 , w0);
1353 const int x1 = wrap(sampler.wrapS, i0 + 1, w0);
1355 depths[0] = lookupDepth(level0, sampler, x0, coordZ, 0);
1356 depths[1] = lookupDepth(level0, sampler, x1, coordZ, 0);
1359 for (int i1 = minI1; i1 <= maxI1; i1++)
1361 const float minA1 = de::clamp((uBounds1.x() - 0.5f) - float(i1), 0.0f, 1.0f);
1362 const float maxA1 = de::clamp((uBounds1.y() - 0.5f) - float(i1), 0.0f, 1.0f);
1363 const Vec2 ptA1 = Vec2(minA1, maxA1);
1366 const int x0 = wrap(sampler.wrapS, i1 , w1);
1367 const int x1 = wrap(sampler.wrapS, i1 + 1, w1);
1369 depths[2] = lookupDepth(level1, sampler, x0, coordZ, 0);
1370 depths[3] = lookupDepth(level1, sampler, x1, coordZ, 0);
1373 if (isBilinearCompareValid(sampler.compare,
1388 static bool isMipmapLinearCompareResultValid (const ConstPixelBufferAccess& level0,
1389 const ConstPixelBufferAccess& level1,
1390 const Sampler& sampler,
1391 const Sampler::FilterMode levelFilter,
1392 const TexComparePrecision& prec,
1395 const Vec2& fBounds,
1396 const float cmpReference,
1399 if (levelFilter == Sampler::LINEAR)
1400 return isLinearMipmapLinearCompareResultValid(level0, level1, sampler, prec, coord, coordZ, fBounds, cmpReference, result);
1402 return isNearestMipmapLinearCompareResultValid(level0, level1, sampler, prec, coord, coordZ, fBounds, cmpReference, result);
1405 bool isTexCompareResultValid (const TextureCubeView& texture, const Sampler& sampler, const TexComparePrecision& prec, const Vec3& coord, const Vec2& lodBounds, const float cmpReference, const float result)
1407 int numPossibleFaces = 0;
1408 CubeFace possibleFaces[CUBEFACE_LAST];
1410 DE_ASSERT(isSamplerSupported(sampler));
1412 getPossibleCubeFaces(coord, prec.coordBits, &possibleFaces[0], numPossibleFaces);
1414 if (numPossibleFaces == 0)
1415 return true; // Result is undefined.
1417 for (int tryFaceNdx = 0; tryFaceNdx < numPossibleFaces; tryFaceNdx++)
1419 const CubeFaceFloatCoords faceCoords (possibleFaces[tryFaceNdx], projectToFace(possibleFaces[tryFaceNdx], coord));
1420 const float minLod = lodBounds.x();
1421 const float maxLod = lodBounds.y();
1422 const bool canBeMagnified = minLod <= sampler.lodThreshold;
1423 const bool canBeMinified = maxLod > sampler.lodThreshold;
1427 if (isCubeLevelCompareResultValid(texture, 0, sampler, sampler.magFilter, prec, faceCoords, cmpReference, result))
1433 const bool isNearestMipmap = isNearestMipmapFilter(sampler.minFilter);
1434 const bool isLinearMipmap = isLinearMipmapFilter(sampler.minFilter);
1435 const int minTexLevel = 0;
1436 const int maxTexLevel = texture.getNumLevels()-1;
1438 DE_ASSERT(minTexLevel < maxTexLevel);
1442 const int minLevel = de::clamp((int)deFloatFloor(minLod), minTexLevel, maxTexLevel-1);
1443 const int maxLevel = de::clamp((int)deFloatFloor(maxLod), minTexLevel, maxTexLevel-1);
1445 DE_ASSERT(minLevel <= maxLevel);
1447 for (int level = minLevel; level <= maxLevel; level++)
1449 const float minF = de::clamp(minLod - float(level), 0.0f, 1.0f);
1450 const float maxF = de::clamp(maxLod - float(level), 0.0f, 1.0f);
1452 if (isCubeMipmapLinearCompareResultValid(texture, level, sampler, getLevelFilter(sampler.minFilter), prec, faceCoords, Vec2(minF, maxF), cmpReference, result))
1456 else if (isNearestMipmap)
1458 // \note The accurate formula for nearest mipmapping is level = ceil(lod + 0.5) - 1 but Khronos has made
1459 // decision to allow floor(lod + 0.5) as well.
1460 const int minLevel = de::clamp((int)deFloatCeil(minLod + 0.5f) - 1, minTexLevel, maxTexLevel);
1461 const int maxLevel = de::clamp((int)deFloatFloor(maxLod + 0.5f), minTexLevel, maxTexLevel);
1463 DE_ASSERT(minLevel <= maxLevel);
1465 for (int level = minLevel; level <= maxLevel; level++)
1467 if (isCubeLevelCompareResultValid(texture, level, sampler, getLevelFilter(sampler.minFilter), prec, faceCoords, cmpReference, result))
1473 if (isCubeLevelCompareResultValid(texture, 0, sampler, sampler.minFilter, prec, faceCoords, cmpReference, result))
1482 bool isTexCompareResultValid (const Texture2DArrayView& texture, const Sampler& sampler, const TexComparePrecision& prec, const Vec3& coord, const Vec2& lodBounds, const float cmpReference, const float result)
1484 const float depthErr = computeFloatingPointError(coord.z(), prec.coordBits.z()) + computeFixedPointError(prec.uvwBits.z());
1485 const float minZ = coord.z()-depthErr;
1486 const float maxZ = coord.z()+depthErr;
1487 const int minLayer = de::clamp(deFloorFloatToInt32(minZ + 0.5f), 0, texture.getNumLayers()-1);
1488 const int maxLayer = de::clamp(deFloorFloatToInt32(maxZ + 0.5f), 0, texture.getNumLayers()-1);
1490 DE_ASSERT(isSamplerSupported(sampler));
1492 for (int layer = minLayer; layer <= maxLayer; layer++)
1494 const float minLod = lodBounds.x();
1495 const float maxLod = lodBounds.y();
1496 const bool canBeMagnified = minLod <= sampler.lodThreshold;
1497 const bool canBeMinified = maxLod > sampler.lodThreshold;
1501 if (isLevelCompareResultValid(texture.getLevel(0), sampler, sampler.magFilter, prec, coord.swizzle(0,1), layer, cmpReference, result))
1507 const bool isNearestMipmap = isNearestMipmapFilter(sampler.minFilter);
1508 const bool isLinearMipmap = isLinearMipmapFilter(sampler.minFilter);
1509 const int minTexLevel = 0;
1510 const int maxTexLevel = texture.getNumLevels()-1;
1512 DE_ASSERT(minTexLevel < maxTexLevel);
1516 const int minLevel = de::clamp((int)deFloatFloor(minLod), minTexLevel, maxTexLevel-1);
1517 const int maxLevel = de::clamp((int)deFloatFloor(maxLod), minTexLevel, maxTexLevel-1);
1519 DE_ASSERT(minLevel <= maxLevel);
1521 for (int level = minLevel; level <= maxLevel; level++)
1523 const float minF = de::clamp(minLod - float(level), 0.0f, 1.0f);
1524 const float maxF = de::clamp(maxLod - float(level), 0.0f, 1.0f);
1526 if (isMipmapLinearCompareResultValid(texture.getLevel(level), texture.getLevel(level+1), sampler, getLevelFilter(sampler.minFilter), prec, coord.swizzle(0,1), layer, Vec2(minF, maxF), cmpReference, result))
1530 else if (isNearestMipmap)
1532 // \note The accurate formula for nearest mipmapping is level = ceil(lod + 0.5) - 1 but Khronos has made
1533 // decision to allow floor(lod + 0.5) as well.
1534 const int minLevel = de::clamp((int)deFloatCeil(minLod + 0.5f) - 1, minTexLevel, maxTexLevel);
1535 const int maxLevel = de::clamp((int)deFloatFloor(maxLod + 0.5f), minTexLevel, maxTexLevel);
1537 DE_ASSERT(minLevel <= maxLevel);
1539 for (int level = minLevel; level <= maxLevel; level++)
1541 if (isLevelCompareResultValid(texture.getLevel(level), sampler, getLevelFilter(sampler.minFilter), prec, coord.swizzle(0,1), layer, cmpReference, result))
1547 if (isLevelCompareResultValid(texture.getLevel(0), sampler, sampler.minFilter, prec, coord.swizzle(0,1), layer, cmpReference, result))
1556 bool isTexCompareResultValid (const Texture1DView& texture,
1557 const Sampler& sampler,
1558 const TexComparePrecision& prec,
1560 const Vec2& lodBounds,
1561 const float cmpReference,
1564 const float minLod = lodBounds.x();
1565 const float maxLod = lodBounds.y();
1566 const bool canBeMagnified = minLod <= sampler.lodThreshold;
1567 const bool canBeMinified = maxLod > sampler.lodThreshold;
1569 DE_ASSERT(isSamplerSupported(sampler));
1573 if (isLevelCompareResultValid(texture.getLevel(0), sampler, sampler.magFilter, prec, coord, 0, cmpReference, result))
1579 const bool isNearestMipmap = isNearestMipmapFilter(sampler.minFilter);
1580 const bool isLinearMipmap = isLinearMipmapFilter(sampler.minFilter);
1581 const int minTexLevel = 0;
1582 const int maxTexLevel = texture.getNumLevels()-1;
1584 DE_ASSERT(minTexLevel < maxTexLevel);
1588 const int minLevel = de::clamp((int)deFloatFloor(minLod), minTexLevel, maxTexLevel-1);
1589 const int maxLevel = de::clamp((int)deFloatFloor(maxLod), minTexLevel, maxTexLevel-1);
1591 DE_ASSERT(minLevel <= maxLevel);
1593 for (int level = minLevel; level <= maxLevel; level++)
1595 const float minF = de::clamp(minLod - float(level), 0.0f, 1.0f);
1596 const float maxF = de::clamp(maxLod - float(level), 0.0f, 1.0f);
1598 if (isMipmapLinearCompareResultValid(texture.getLevel(level), texture.getLevel(level+1), sampler, getLevelFilter(sampler.minFilter), prec, coord, 0, Vec2(minF, maxF), cmpReference, result))
1602 else if (isNearestMipmap)
1604 // \note The accurate formula for nearest mipmapping is level = ceil(lod + 0.5) - 1 but Khronos has made
1605 // decision to allow floor(lod + 0.5) as well.
1606 const int minLevel = de::clamp((int)deFloatCeil(minLod + 0.5f) - 1, minTexLevel, maxTexLevel);
1607 const int maxLevel = de::clamp((int)deFloatFloor(maxLod + 0.5f), minTexLevel, maxTexLevel);
1609 DE_ASSERT(minLevel <= maxLevel);
1611 for (int level = minLevel; level <= maxLevel; level++)
1613 if (isLevelCompareResultValid(texture.getLevel(level), sampler, getLevelFilter(sampler.minFilter), prec, coord, 0, cmpReference, result))
1619 if (isLevelCompareResultValid(texture.getLevel(0), sampler, sampler.minFilter, prec, coord, 0, cmpReference, result))
1627 bool isTexCompareResultValid (const Texture1DArrayView& texture,
1628 const Sampler& sampler,
1629 const TexComparePrecision& prec,
1631 const Vec2& lodBounds,
1632 const float cmpReference,
1635 const float depthErr = computeFloatingPointError(coord.y(), prec.coordBits.y()) + computeFixedPointError(prec.uvwBits.y()); //\todo: should we go with y in prec?
1636 const float minZ = coord.y()-depthErr;
1637 const float maxZ = coord.y()+depthErr;
1638 const int minLayer = de::clamp(deFloorFloatToInt32(minZ + 0.5f), 0, texture.getNumLayers()-1);
1639 const int maxLayer = de::clamp(deFloorFloatToInt32(maxZ + 0.5f), 0, texture.getNumLayers()-1);
1641 DE_ASSERT(isSamplerSupported(sampler));
1643 for (int layer = minLayer; layer <= maxLayer; layer++)
1645 const float minLod = lodBounds.x();
1646 const float maxLod = lodBounds.y();
1647 const bool canBeMagnified = minLod <= sampler.lodThreshold;
1648 const bool canBeMinified = maxLod > sampler.lodThreshold;
1652 if (isLevelCompareResultValid(texture.getLevel(0), sampler, sampler.magFilter, prec, Vec1(coord.x()), layer, cmpReference, result))
1658 const bool isNearestMipmap = isNearestMipmapFilter(sampler.minFilter);
1659 const bool isLinearMipmap = isLinearMipmapFilter(sampler.minFilter);
1660 const int minTexLevel = 0;
1661 const int maxTexLevel = texture.getNumLevels()-1;
1663 DE_ASSERT(minTexLevel < maxTexLevel);
1667 const int minLevel = de::clamp((int)deFloatFloor(minLod), minTexLevel, maxTexLevel-1);
1668 const int maxLevel = de::clamp((int)deFloatFloor(maxLod), minTexLevel, maxTexLevel-1);
1670 DE_ASSERT(minLevel <= maxLevel);
1672 for (int level = minLevel; level <= maxLevel; level++)
1674 const float minF = de::clamp(minLod - float(level), 0.0f, 1.0f);
1675 const float maxF = de::clamp(maxLod - float(level), 0.0f, 1.0f);
1677 if (isMipmapLinearCompareResultValid(texture.getLevel(level), texture.getLevel(level+1), sampler, getLevelFilter(sampler.minFilter), prec, Vec1(coord.x()), layer, Vec2(minF, maxF), cmpReference, result))
1681 else if (isNearestMipmap)
1683 // \note The accurate formula for nearest mipmapping is level = ceil(lod + 0.5) - 1 but Khronos has made
1684 // decision to allow floor(lod + 0.5) as well.
1685 const int minLevel = de::clamp((int)deFloatCeil(minLod + 0.5f) - 1, minTexLevel, maxTexLevel);
1686 const int maxLevel = de::clamp((int)deFloatFloor(maxLod + 0.5f), minTexLevel, maxTexLevel);
1688 DE_ASSERT(minLevel <= maxLevel);
1690 for (int level = minLevel; level <= maxLevel; level++)
1692 if (isLevelCompareResultValid(texture.getLevel(level), sampler, getLevelFilter(sampler.minFilter), prec, Vec1(coord.x()), layer, cmpReference, result))
1698 if (isLevelCompareResultValid(texture.getLevel(0), sampler, sampler.minFilter, prec, Vec1(coord.x()), layer, cmpReference, result))
1707 bool isTexCompareResultValid (const TextureCubeArrayView& texture, const Sampler& sampler, const TexComparePrecision& prec, const Vec4& coord, const Vec2& lodBounds, const float cmpReference, const float result)
1709 const Vec3 coord3 = coord.swizzle(0,1,2);
1710 int numPossibleFaces = 0;
1711 CubeFace possibleFaces[CUBEFACE_LAST];
1713 DE_ASSERT(isSamplerSupported(sampler));
1715 getPossibleCubeFaces(coord3, prec.coordBits, &possibleFaces[0], numPossibleFaces);
1717 if (numPossibleFaces == 0)
1718 return true; // Result is undefined.
1720 for (int tryFaceNdx = 0; tryFaceNdx < numPossibleFaces; tryFaceNdx++)
1722 const CubeFaceFloatCoords faceCoords (possibleFaces[tryFaceNdx], projectToFace(possibleFaces[tryFaceNdx], coord3));
1723 const float minLod = lodBounds.x();
1724 const float maxLod = lodBounds.y();
1725 const bool canBeMagnified = minLod <= sampler.lodThreshold;
1726 const bool canBeMinified = maxLod > sampler.lodThreshold;
1730 if (isCubeLevelCompareResultValid(texture, 0, sampler, sampler.magFilter, prec, faceCoords, coord.w(), cmpReference, result))
1736 const bool isNearestMipmap = isNearestMipmapFilter(sampler.minFilter);
1737 const bool isLinearMipmap = isLinearMipmapFilter(sampler.minFilter);
1738 const int minTexLevel = 0;
1739 const int maxTexLevel = texture.getNumLevels()-1;
1741 DE_ASSERT(minTexLevel < maxTexLevel);
1745 const int minLevel = de::clamp((int)deFloatFloor(minLod), minTexLevel, maxTexLevel-1);
1746 const int maxLevel = de::clamp((int)deFloatFloor(maxLod), minTexLevel, maxTexLevel-1);
1748 DE_ASSERT(minLevel <= maxLevel);
1750 for (int level = minLevel; level <= maxLevel; level++)
1752 const float minF = de::clamp(minLod - float(level), 0.0f, 1.0f);
1753 const float maxF = de::clamp(maxLod - float(level), 0.0f, 1.0f);
1755 if (isCubeMipmapLinearCompareResultValid(texture, level, sampler, getLevelFilter(sampler.minFilter), prec, faceCoords, coord.w(), Vec2(minF, maxF), cmpReference, result))
1759 else if (isNearestMipmap)
1761 // \note The accurate formula for nearest mipmapping is level = ceil(lod + 0.5) - 1 but Khronos has made
1762 // decision to allow floor(lod + 0.5) as well.
1763 const int minLevel = de::clamp((int)deFloatCeil(minLod + 0.5f) - 1, minTexLevel, maxTexLevel);
1764 const int maxLevel = de::clamp((int)deFloatFloor(maxLod + 0.5f), minTexLevel, maxTexLevel);
1766 DE_ASSERT(minLevel <= maxLevel);
1768 for (int level = minLevel; level <= maxLevel; level++)
1770 if (isCubeLevelCompareResultValid(texture, level, sampler, getLevelFilter(sampler.minFilter), prec, faceCoords, coord.w(), cmpReference, result))
1776 if (isCubeLevelCompareResultValid(texture, 0, sampler, sampler.minFilter, prec, faceCoords, coord.w(), cmpReference, result))
1785 static bool isGatherOffsetsCompareResultValid (const ConstPixelBufferAccess& texture,
1786 const Sampler& sampler,
1787 const TexComparePrecision& prec,
1790 const IVec2 (&offsets)[4],
1794 const bool isFixedPointDepth = isFixedPointDepthTextureFormat(texture.getFormat());
1795 const Vec2 uBounds = computeNonNormalizedCoordBounds(sampler.normalizedCoords, texture.getWidth(), coord.x(), prec.coordBits.x(), prec.uvwBits.x());
1796 const Vec2 vBounds = computeNonNormalizedCoordBounds(sampler.normalizedCoords, texture.getHeight(), coord.y(), prec.coordBits.y(), prec.uvwBits.y());
1798 // Integer coordinate bounds for (x0, y0) - without wrap mode
1799 const int minI = deFloorFloatToInt32(uBounds.x()-0.5f);
1800 const int maxI = deFloorFloatToInt32(uBounds.y()-0.5f);
1801 const int minJ = deFloorFloatToInt32(vBounds.x()-0.5f);
1802 const int maxJ = deFloorFloatToInt32(vBounds.y()-0.5f);
1804 const int w = texture.getWidth();
1805 const int h = texture.getHeight();
1807 for (int j = minJ; j <= maxJ; j++)
1809 for (int i = minI; i <= maxI; i++)
1811 bool isCurrentPixelValid = true;
1813 for (int offNdx = 0; offNdx < 4 && isCurrentPixelValid; offNdx++)
1815 // offNdx-th coordinate offset and then wrapped.
1816 const int x = wrap(sampler.wrapS, i+offsets[offNdx].x(), w);
1817 const int y = wrap(sampler.wrapT, j+offsets[offNdx].y(), h);
1818 const float depth = lookupDepth(texture, sampler, x, y, coordZ);
1819 const CmpResultSet resSet = execCompare(sampler.compare, depth, cmpReference, prec.referenceBits, isFixedPointDepth);
1821 if (!isResultInSet(resSet, result[offNdx], prec.resultBits))
1822 isCurrentPixelValid = false;
1825 if (isCurrentPixelValid)
1833 bool isGatherOffsetsCompareResultValid (const Texture2DView& texture,
1834 const Sampler& sampler,
1835 const TexComparePrecision& prec,
1837 const IVec2 (&offsets)[4],
1841 DE_ASSERT(isSamplerSupported(sampler));
1843 return isGatherOffsetsCompareResultValid(texture.getLevel(0), sampler, prec, coord, 0, offsets, cmpReference, result);
1846 bool isGatherOffsetsCompareResultValid (const Texture2DArrayView& texture,
1847 const Sampler& sampler,
1848 const TexComparePrecision& prec,
1850 const IVec2 (&offsets)[4],
1854 const float depthErr = computeFloatingPointError(coord.z(), prec.coordBits.z()) + computeFixedPointError(prec.uvwBits.z());
1855 const float minZ = coord.z()-depthErr;
1856 const float maxZ = coord.z()+depthErr;
1857 const int minLayer = de::clamp(deFloorFloatToInt32(minZ + 0.5f), 0, texture.getNumLayers()-1);
1858 const int maxLayer = de::clamp(deFloorFloatToInt32(maxZ + 0.5f), 0, texture.getNumLayers()-1);
1860 DE_ASSERT(isSamplerSupported(sampler));
1862 for (int layer = minLayer; layer <= maxLayer; layer++)
1864 if (isGatherOffsetsCompareResultValid(texture.getLevel(0), sampler, prec, coord.swizzle(0,1), layer, offsets, cmpReference, result))
1870 static bool isGatherCompareResultValid (const TextureCubeView& texture,
1871 const Sampler& sampler,
1872 const TexComparePrecision& prec,
1873 const CubeFaceFloatCoords& coords,
1877 const bool isFixedPointDepth = isFixedPointDepthTextureFormat(texture.getLevelFace(0, coords.face).getFormat());
1878 const int size = texture.getLevelFace(0, coords.face).getWidth();
1879 const Vec2 uBounds = computeNonNormalizedCoordBounds(sampler.normalizedCoords, size, coords.s, prec.coordBits.x(), prec.uvwBits.x());
1880 const Vec2 vBounds = computeNonNormalizedCoordBounds(sampler.normalizedCoords, size, coords.t, prec.coordBits.y(), prec.uvwBits.y());
1882 // Integer coordinate bounds for (x0,y0) - without wrap mode
1883 const int minI = deFloorFloatToInt32(uBounds.x()-0.5f);
1884 const int maxI = deFloorFloatToInt32(uBounds.y()-0.5f);
1885 const int minJ = deFloorFloatToInt32(vBounds.x()-0.5f);
1886 const int maxJ = deFloorFloatToInt32(vBounds.y()-0.5f);
1889 ConstPixelBufferAccess faces[CUBEFACE_LAST];
1890 for (int face = 0; face < CUBEFACE_LAST; face++)
1891 faces[face] = texture.getLevelFace(0, CubeFace(face));
1893 for (int j = minJ; j <= maxJ; j++)
1895 for (int i = minI; i <= maxI; i++)
1897 static const IVec2 offsets[4] =
1905 bool isCurrentPixelValid = true;
1907 for (int offNdx = 0; offNdx < 4 && isCurrentPixelValid; offNdx++)
1909 const CubeFaceIntCoords c = remapCubeEdgeCoords(CubeFaceIntCoords(coords.face, i+offsets[offNdx].x(), j+offsets[offNdx].y()), size);
1910 // If any of samples is out of both edges, implementations can do pretty much anything according to spec.
1911 // \todo [2014-06-05 nuutti] Test the special case where all corner pixels have exactly the same color.
1912 // See also isSeamlessLinearCompareResultValid and similar.
1913 if (c.face == CUBEFACE_LAST)
1916 const float depth = lookupDepthNoBorder(faces[c.face], sampler, c.s, c.t);
1917 const CmpResultSet resSet = execCompare(sampler.compare, depth, cmpReference, prec.referenceBits, isFixedPointDepth);
1919 if (!isResultInSet(resSet, result[offNdx], prec.resultBits))
1920 isCurrentPixelValid = false;
1923 if (isCurrentPixelValid)
1931 bool isGatherCompareResultValid (const TextureCubeView& texture,
1932 const Sampler& sampler,
1933 const TexComparePrecision& prec,
1938 int numPossibleFaces = 0;
1939 CubeFace possibleFaces[CUBEFACE_LAST];
1941 DE_ASSERT(isSamplerSupported(sampler));
1943 getPossibleCubeFaces(coord, prec.coordBits, &possibleFaces[0], numPossibleFaces);
1945 if (numPossibleFaces == 0)
1946 return true; // Result is undefined.
1948 for (int tryFaceNdx = 0; tryFaceNdx < numPossibleFaces; tryFaceNdx++)
1950 const CubeFaceFloatCoords faceCoords(possibleFaces[tryFaceNdx], projectToFace(possibleFaces[tryFaceNdx], coord));
1952 if (isGatherCompareResultValid(texture, sampler, prec, faceCoords, cmpReference, result))