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