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