• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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