1/*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 3.1 Module
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 Common built-in function tests.
22 *//*--------------------------------------------------------------------*/
23
24#include "es31fShaderCommonFunctionTests.hpp"
25#include "gluContextInfo.hpp"
26#include "glsShaderExecUtil.hpp"
27#include "tcuTestLog.hpp"
28#include "tcuFormatUtil.hpp"
29#include "tcuFloat.hpp"
30#include "tcuInterval.hpp"
31#include "tcuFloatFormat.hpp"
32#include "deRandom.hpp"
33#include "deMath.h"
34#include "deString.h"
35#include "deArrayUtil.hpp"
36
37namespace deqp
38{
39namespace gles31
40{
41namespace Functional
42{
43
44using std::vector;
45using std::string;
46using tcu::TestLog;
47using namespace gls::ShaderExecUtil;
48
49using tcu::Vec2;
50using tcu::Vec3;
51using tcu::Vec4;
52using tcu::IVec2;
53using tcu::IVec3;
54using tcu::IVec4;
55
56// Utilities
57
58template<typename T, int Size>
59struct VecArrayAccess
60{
61public:
62									VecArrayAccess	(const void* ptr) : m_array((tcu::Vector<T, Size>*)ptr) {}
63									~VecArrayAccess	(void) {}
64
65	const tcu::Vector<T, Size>&		operator[]		(size_t offset) const	{ return m_array[offset];	}
66	tcu::Vector<T, Size>&			operator[]		(size_t offset)			{ return m_array[offset];	}
67
68private:
69	tcu::Vector<T, Size>*			m_array;
70};
71
72template<typename T>	T			randomScalar	(de::Random& rnd, T minValue, T maxValue);
73template<> inline		float		randomScalar	(de::Random& rnd, float minValue, float maxValue)		{ return rnd.getFloat(minValue, maxValue);	}
74template<> inline		deInt32		randomScalar	(de::Random& rnd, deInt32 minValue, deInt32 maxValue)	{ return rnd.getInt(minValue, maxValue);	}
75template<> inline		deUint32	randomScalar	(de::Random& rnd, deUint32 minValue, deUint32 maxValue)	{ return minValue + rnd.getUint32() % (maxValue - minValue + 1); }
76
77template<typename T, int Size>
78inline tcu::Vector<T, Size> randomVector (de::Random& rnd, const tcu::Vector<T, Size>& minValue, const tcu::Vector<T, Size>& maxValue)
79{
80	tcu::Vector<T, Size> res;
81	for (int ndx = 0; ndx < Size; ndx++)
82		res[ndx] = randomScalar<T>(rnd, minValue[ndx], maxValue[ndx]);
83	return res;
84}
85
86template<typename T, int Size>
87static void fillRandomVectors (de::Random& rnd, const tcu::Vector<T, Size>& minValue, const tcu::Vector<T, Size>& maxValue, void* dst, int numValues, int offset = 0)
88{
89	VecArrayAccess<T, Size> access(dst);
90	for (int ndx = 0; ndx < numValues; ndx++)
91		access[offset + ndx] = randomVector<T, Size>(rnd, minValue, maxValue);
92}
93
94template<typename T>
95static void fillRandomScalars (de::Random& rnd, T minValue, T maxValue, void* dst, int numValues, int offset = 0)
96{
97	T* typedPtr = (T*)dst;
98	for (int ndx = 0; ndx < numValues; ndx++)
99		typedPtr[offset + ndx] = randomScalar<T>(rnd, minValue, maxValue);
100}
101
102inline int numBitsLostInOp (float input, float output)
103{
104	const int	inExp		= tcu::Float32(input).exponent();
105	const int	outExp		= tcu::Float32(output).exponent();
106
107	return de::max(0, inExp-outExp); // Lost due to mantissa shift.
108}
109
110inline deUint32 getUlpDiff (float a, float b)
111{
112	const deUint32	aBits	= tcu::Float32(a).bits();
113	const deUint32	bBits	= tcu::Float32(b).bits();
114	return aBits > bBits ? aBits - bBits : bBits - aBits;
115}
116
117inline deUint32 getUlpDiffIgnoreZeroSign (float a, float b)
118{
119	if (tcu::Float32(a).isZero())
120		return getUlpDiff(tcu::Float32::construct(tcu::Float32(b).sign(), 0, 0).asFloat(), b);
121	else if (tcu::Float32(b).isZero())
122		return getUlpDiff(a, tcu::Float32::construct(tcu::Float32(a).sign(), 0, 0).asFloat());
123	else
124		return getUlpDiff(a, b);
125}
126
127inline bool supportsSignedZero (glu::Precision precision)
128{
129	// \note GLSL ES 3.1 doesn't really require support for -0, but we require it for highp
130	//		 as it is very widely supported.
131	return precision == glu::PRECISION_HIGHP;
132}
133
134inline float getEpsFromMaxUlpDiff (float value, deUint32 ulpDiff)
135{
136	const int exp = tcu::Float32(value).exponent();
137	return tcu::Float32::construct(+1, exp, (1u<<23) | ulpDiff).asFloat() - tcu::Float32::construct(+1, exp, 1u<<23).asFloat();
138}
139
140inline deUint32 getMaxUlpDiffFromBits (int numAccurateBits)
141{
142	const int		numGarbageBits	= 23-numAccurateBits;
143	const deUint32	mask			= (1u<<numGarbageBits)-1u;
144
145	return mask;
146}
147
148inline float getEpsFromBits (float value, int numAccurateBits)
149{
150	return getEpsFromMaxUlpDiff(value, getMaxUlpDiffFromBits(numAccurateBits));
151}
152
153static int getMinMantissaBits (glu::Precision precision)
154{
155	const int bits[] =
156	{
157		7,		// lowp
158		10,		// mediump
159		23		// highp
160	};
161	DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(bits) == glu::PRECISION_LAST);
162	DE_ASSERT(de::inBounds<int>(precision, 0, DE_LENGTH_OF_ARRAY(bits)));
163	return bits[precision];
164}
165
166static int getMaxNormalizedValueExponent (glu::Precision precision)
167{
168	const int exponent[] =
169	{
170		0,		// lowp
171		13,		// mediump
172		127		// highp
173	};
174	DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(exponent) == glu::PRECISION_LAST);
175	DE_ASSERT(de::inBounds<int>(precision, 0, DE_LENGTH_OF_ARRAY(exponent)));
176	return exponent[precision];
177}
178
179static int getMinNormalizedValueExponent (glu::Precision precision)
180{
181	const int exponent[] =
182	{
183		-7,		// lowp
184		-13,	// mediump
185		-126	// highp
186	};
187	DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(exponent) == glu::PRECISION_LAST);
188	DE_ASSERT(de::inBounds<int>(precision, 0, DE_LENGTH_OF_ARRAY(exponent)));
189	return exponent[precision];
190}
191
192static float makeFloatRepresentable (float f, glu::Precision precision)
193{
194	if (precision == glu::PRECISION_HIGHP)
195	{
196		// \note: assuming f is not extended-precision
197		return f;
198	}
199	else
200	{
201		const int			numMantissaBits				= getMinMantissaBits(precision);
202		const int			maxNormalizedValueExponent	= getMaxNormalizedValueExponent(precision);
203		const int			minNormalizedValueExponent	= getMinNormalizedValueExponent(precision);
204		const deUint32		representableMantissaMask	= ((deUint32(1) << numMantissaBits) - 1) << (23 - (deUint32)numMantissaBits);
205		const float			largestRepresentableValue	= tcu::Float32::constructBits(+1, maxNormalizedValueExponent, ((1u << numMantissaBits) - 1u) << (23u - (deUint32)numMantissaBits)).asFloat();
206		const bool			zeroNotRepresentable		= (precision == glu::PRECISION_LOWP);
207
208		// if zero is not required to be representable, use smallest positive non-subnormal value
209		const float			zeroValue					= (zeroNotRepresentable) ? (tcu::Float32::constructBits(+1, minNormalizedValueExponent, 1).asFloat()) : (0.0f);
210
211		const tcu::Float32	float32Representation		(f);
212
213		if (float32Representation.exponent() < minNormalizedValueExponent)
214		{
215			// flush too small values to zero
216			return zeroValue;
217		}
218		else if (float32Representation.exponent() > maxNormalizedValueExponent)
219		{
220			// clamp too large values
221			return (float32Representation.sign() == +1) ? (largestRepresentableValue) : (-largestRepresentableValue);
222		}
223		else
224		{
225			// remove unrepresentable mantissa bits
226			const tcu::Float32 targetRepresentation(tcu::Float32::constructBits(float32Representation.sign(),
227													float32Representation.exponent(),
228													float32Representation.mantissaBits() & representableMantissaMask));
229
230			return targetRepresentation.asFloat();
231		}
232	}
233}
234
235// CommonFunctionCase
236
237class CommonFunctionCase : public TestCase
238{
239public:
240							CommonFunctionCase		(Context& context, const char* name, const char* description, glu::ShaderType shaderType);
241							~CommonFunctionCase		(void);
242
243	void					init					(void);
244	void					deinit					(void);
245	IterateResult			iterate					(void);
246
247protected:
248							CommonFunctionCase		(const CommonFunctionCase& other);
249	CommonFunctionCase&		operator=				(const CommonFunctionCase& other);
250
251	virtual void			getInputValues			(int numValues, void* const* values) const = 0;
252	virtual bool			compare					(const void* const* inputs, const void* const* outputs) = 0;
253
254	glu::ShaderType			m_shaderType;
255	ShaderSpec				m_spec;
256	int						m_numValues;
257
258	std::ostringstream		m_failMsg;				//!< Comparison failure help message.
259
260private:
261	ShaderExecutor*			m_executor;
262};
263
264CommonFunctionCase::CommonFunctionCase (Context& context, const char* name, const char* description, glu::ShaderType shaderType)
265	: TestCase		(context, name, description)
266	, m_shaderType	(shaderType)
267	, m_numValues	(100)
268	, m_executor	(DE_NULL)
269{
270}
271
272CommonFunctionCase::~CommonFunctionCase (void)
273{
274	CommonFunctionCase::deinit();
275}
276
277void CommonFunctionCase::init (void)
278{
279	DE_ASSERT(!m_executor);
280
281	m_spec.version = contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)) ? glu::GLSL_VERSION_320_ES : glu::GLSL_VERSION_310_ES;
282
283	m_executor = createExecutor(m_context.getRenderContext(), m_shaderType, m_spec);
284	m_testCtx.getLog() << m_executor;
285
286	if (!m_executor->isOk())
287		throw tcu::TestError("Compile failed");
288}
289
290void CommonFunctionCase::deinit (void)
291{
292	delete m_executor;
293	m_executor = DE_NULL;
294}
295
296static vector<int> getScalarSizes (const vector<Symbol>& symbols)
297{
298	vector<int> sizes(symbols.size());
299	for (int ndx = 0; ndx < (int)symbols.size(); ++ndx)
300		sizes[ndx] = symbols[ndx].varType.getScalarSize();
301	return sizes;
302}
303
304static int computeTotalScalarSize (const vector<Symbol>& symbols)
305{
306	int totalSize = 0;
307	for (vector<Symbol>::const_iterator sym = symbols.begin(); sym != symbols.end(); ++sym)
308		totalSize += sym->varType.getScalarSize();
309	return totalSize;
310}
311
312static vector<void*> getInputOutputPointers (const vector<Symbol>& symbols, vector<deUint32>& data, const int numValues)
313{
314	vector<void*>	pointers		(symbols.size());
315	int				curScalarOffset	= 0;
316
317	for (int varNdx = 0; varNdx < (int)symbols.size(); ++varNdx)
318	{
319		const Symbol&	var				= symbols[varNdx];
320		const int		scalarSize		= var.varType.getScalarSize();
321
322		// Uses planar layout as input/output specs do not support strides.
323		pointers[varNdx] = &data[curScalarOffset];
324		curScalarOffset += scalarSize*numValues;
325	}
326
327	DE_ASSERT(curScalarOffset == (int)data.size());
328
329	return pointers;
330}
331
332// \todo [2013-08-08 pyry] Make generic utility and move to glu?
333
334struct HexFloat
335{
336	const float value;
337	HexFloat (const float value_) : value(value_) {}
338};
339
340std::ostream& operator<< (std::ostream& str, const HexFloat& v)
341{
342	return str << v.value << " / " << tcu::toHex(tcu::Float32(v.value).bits());
343}
344
345struct HexBool
346{
347	const deUint32 value;
348	HexBool (const deUint32 value_) : value(value_) {}
349};
350
351std::ostream& operator<< (std::ostream& str, const HexBool& v)
352{
353	return str << (v.value ? "true" : "false") << " / " << tcu::toHex(v.value);
354}
355
356struct VarValue
357{
358	const glu::VarType&	type;
359	const void*			value;
360
361	VarValue (const glu::VarType& type_, const void* value_) : type(type_), value(value_) {}
362};
363
364std::ostream& operator<< (std::ostream& str, const VarValue& varValue)
365{
366	DE_ASSERT(varValue.type.isBasicType());
367
368	const glu::DataType		basicType		= varValue.type.getBasicType();
369	const glu::DataType		scalarType		= glu::getDataTypeScalarType(basicType);
370	const int				numComponents	= glu::getDataTypeScalarSize(basicType);
371
372	if (numComponents > 1)
373		str << glu::getDataTypeName(basicType) << "(";
374
375	for (int compNdx = 0; compNdx < numComponents; compNdx++)
376	{
377		if (compNdx != 0)
378			str << ", ";
379
380		switch (scalarType)
381		{
382			case glu::TYPE_FLOAT:	str << HexFloat(((const float*)varValue.value)[compNdx]);			break;
383			case glu::TYPE_INT:		str << ((const deInt32*)varValue.value)[compNdx];					break;
384			case glu::TYPE_UINT:	str << tcu::toHex(((const deUint32*)varValue.value)[compNdx]);		break;
385			case glu::TYPE_BOOL:	str << HexBool(((const deUint32*)varValue.value)[compNdx]);			break;
386
387			default:
388				DE_ASSERT(false);
389		}
390	}
391
392	if (numComponents > 1)
393		str << ")";
394
395	return str;
396}
397
398CommonFunctionCase::IterateResult CommonFunctionCase::iterate (void)
399{
400	const int				numInputScalars			= computeTotalScalarSize(m_spec.inputs);
401	const int				numOutputScalars		= computeTotalScalarSize(m_spec.outputs);
402	vector<deUint32>		inputData				(numInputScalars * m_numValues);
403	vector<deUint32>		outputData				(numOutputScalars * m_numValues);
404	const vector<void*>		inputPointers			= getInputOutputPointers(m_spec.inputs, inputData, m_numValues);
405	const vector<void*>		outputPointers			= getInputOutputPointers(m_spec.outputs, outputData, m_numValues);
406
407	// Initialize input data.
408	getInputValues(m_numValues, &inputPointers[0]);
409
410	// Execute shader.
411	m_executor->useProgram();
412	m_executor->execute(m_numValues, &inputPointers[0], &outputPointers[0]);
413
414	// Compare results.
415	{
416		const vector<int>		inScalarSizes		= getScalarSizes(m_spec.inputs);
417		const vector<int>		outScalarSizes		= getScalarSizes(m_spec.outputs);
418		vector<void*>			curInputPtr			(inputPointers.size());
419		vector<void*>			curOutputPtr		(outputPointers.size());
420		int						numFailed			= 0;
421
422		for (int valNdx = 0; valNdx < m_numValues; valNdx++)
423		{
424			// Set up pointers for comparison.
425			for (int inNdx = 0; inNdx < (int)curInputPtr.size(); ++inNdx)
426				curInputPtr[inNdx] = (deUint32*)inputPointers[inNdx] + inScalarSizes[inNdx]*valNdx;
427
428			for (int outNdx = 0; outNdx < (int)curOutputPtr.size(); ++outNdx)
429				curOutputPtr[outNdx] = (deUint32*)outputPointers[outNdx] + outScalarSizes[outNdx]*valNdx;
430
431			if (!compare(&curInputPtr[0], &curOutputPtr[0]))
432			{
433				// \todo [2013-08-08 pyry] We probably want to log reference value as well?
434
435				m_testCtx.getLog() << TestLog::Message << "ERROR: comparison failed for value " << valNdx << ":\n  " << m_failMsg.str() << TestLog::EndMessage;
436
437				m_testCtx.getLog() << TestLog::Message << "  inputs:" << TestLog::EndMessage;
438				for (int inNdx = 0; inNdx < (int)curInputPtr.size(); inNdx++)
439					m_testCtx.getLog() << TestLog::Message << "    " << m_spec.inputs[inNdx].name << " = "
440														   << VarValue(m_spec.inputs[inNdx].varType, curInputPtr[inNdx])
441									   << TestLog::EndMessage;
442
443				m_testCtx.getLog() << TestLog::Message << "  outputs:" << TestLog::EndMessage;
444				for (int outNdx = 0; outNdx < (int)curOutputPtr.size(); outNdx++)
445					m_testCtx.getLog() << TestLog::Message << "    " << m_spec.outputs[outNdx].name << " = "
446														   << VarValue(m_spec.outputs[outNdx].varType, curOutputPtr[outNdx])
447									   << TestLog::EndMessage;
448
449				m_failMsg.str("");
450				m_failMsg.clear();
451				numFailed += 1;
452			}
453		}
454
455		m_testCtx.getLog() << TestLog::Message << (m_numValues - numFailed) << " / " << m_numValues << " values passed" << TestLog::EndMessage;
456
457		m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS	: QP_TEST_RESULT_FAIL,
458								numFailed == 0 ? "Pass"					: "Result comparison failed");
459	}
460
461	return STOP;
462}
463
464static const char* getPrecisionPostfix (glu::Precision precision)
465{
466	static const char* s_postfix[] =
467	{
468		"_lowp",
469		"_mediump",
470		"_highp"
471	};
472	DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_postfix) == glu::PRECISION_LAST);
473	DE_ASSERT(de::inBounds<int>(precision, 0, DE_LENGTH_OF_ARRAY(s_postfix)));
474	return s_postfix[precision];
475}
476
477static const char* getShaderTypePostfix (glu::ShaderType shaderType)
478{
479	static const char* s_postfix[] =
480	{
481		"_vertex",
482		"_fragment",
483		"_geometry",
484		"_tess_control",
485		"_tess_eval",
486		"_compute"
487	};
488	DE_ASSERT(de::inBounds<int>(shaderType, 0, DE_LENGTH_OF_ARRAY(s_postfix)));
489	return s_postfix[shaderType];
490}
491
492static std::string getCommonFuncCaseName (glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
493{
494	return string(glu::getDataTypeName(baseType)) + getPrecisionPostfix(precision) + getShaderTypePostfix(shaderType);
495}
496
497class AbsCase : public CommonFunctionCase
498{
499public:
500	AbsCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
501		: CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "abs", shaderType)
502	{
503		m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
504		m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision)));
505		m_spec.source = "out0 = abs(in0);";
506	}
507
508	void getInputValues (int numValues, void* const* values) const
509	{
510		const Vec2 floatRanges[] =
511		{
512			Vec2(-2.0f,		2.0f),	// lowp
513			Vec2(-1e3f,		1e3f),	// mediump
514			Vec2(-1e7f,		1e7f)	// highp
515		};
516		const IVec2 intRanges[] =
517		{
518			IVec2(-(1<<7)+1,	(1<<7)-1),
519			IVec2(-(1<<15)+1,	(1<<15)-1),
520			IVec2(0x80000001,	0x7fffffff)
521		};
522
523		de::Random				rnd			(deStringHash(getName()) ^ 0x235facu);
524		const glu::DataType		type		= m_spec.inputs[0].varType.getBasicType();
525		const glu::Precision	precision	= m_spec.inputs[0].varType.getPrecision();
526		const int				scalarSize	= glu::getDataTypeScalarSize(type);
527
528		if (glu::isDataTypeFloatOrVec(type))
529			fillRandomScalars(rnd, floatRanges[precision].x(), floatRanges[precision].y(), values[0], numValues*scalarSize);
530		else
531			fillRandomScalars(rnd, intRanges[precision].x(), intRanges[precision].y(), values[0], numValues*scalarSize);
532	}
533
534	bool compare (const void* const* inputs, const void* const* outputs)
535	{
536		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
537		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
538		const int				scalarSize		= glu::getDataTypeScalarSize(type);
539
540		if (glu::isDataTypeFloatOrVec(type))
541		{
542			const int		mantissaBits	= getMinMantissaBits(precision);
543			const deUint32	maxUlpDiff		= (1u<<(23-mantissaBits))-1u;
544
545			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
546			{
547				const float		in0			= ((const float*)inputs[0])[compNdx];
548				const float		out0		= ((const float*)outputs[0])[compNdx];
549				const float		ref0		= de::abs(in0);
550				const deUint32	ulpDiff0	= getUlpDiff(out0, ref0);
551
552				if (ulpDiff0 > maxUlpDiff)
553				{
554					m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref0) << " with ULP threshold " << maxUlpDiff << ", got ULP diff " << ulpDiff0;
555					return false;
556				}
557			}
558		}
559		else
560		{
561			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
562			{
563				const int	in0		= ((const int*)inputs[0])[compNdx];
564				const int	out0	= ((const int*)outputs[0])[compNdx];
565				const int	ref0	= de::abs(in0);
566
567				if (out0 != ref0)
568				{
569					m_failMsg << "Expected [" << compNdx << "] = " << ref0;
570					return false;
571				}
572			}
573		}
574
575		return true;
576	}
577};
578
579class SignCase : public CommonFunctionCase
580{
581public:
582	SignCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
583		: CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "sign", shaderType)
584	{
585		m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
586		m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision)));
587		m_spec.source = "out0 = sign(in0);";
588	}
589
590	void getInputValues (int numValues, void* const* values) const
591	{
592		const Vec2 floatRanges[] =
593		{
594			Vec2(-2.0f,		2.0f),	// lowp
595			Vec2(-1e4f,		1e4f),	// mediump	- note: may end up as inf
596			Vec2(-1e8f,		1e8f)	// highp	- note: may end up as inf
597		};
598		const IVec2 intRanges[] =
599		{
600			IVec2(-(1<<7),		(1<<7)-1),
601			IVec2(-(1<<15),		(1<<15)-1),
602			IVec2(0x80000000,	0x7fffffff)
603		};
604
605		de::Random				rnd			(deStringHash(getName()) ^ 0x324u);
606		const glu::DataType		type		= m_spec.inputs[0].varType.getBasicType();
607		const glu::Precision	precision	= m_spec.inputs[0].varType.getPrecision();
608		const int				scalarSize	= glu::getDataTypeScalarSize(type);
609
610		if (glu::isDataTypeFloatOrVec(type))
611		{
612			// Special cases.
613			std::fill((float*)values[0],				(float*)values[0] + scalarSize,		+1.0f);
614			std::fill((float*)values[0] + scalarSize*1,	(float*)values[0] + scalarSize*2,	-1.0f);
615			std::fill((float*)values[0] + scalarSize*2,	(float*)values[0] + scalarSize*3,	0.0f);
616			fillRandomScalars(rnd, floatRanges[precision].x(), floatRanges[precision].y(), (float*)values[0] + scalarSize*3, (numValues-3)*scalarSize);
617		}
618		else
619		{
620			std::fill((int*)values[0],					(int*)values[0] + scalarSize,		+1);
621			std::fill((int*)values[0] + scalarSize*1,	(int*)values[0] + scalarSize*2,		-1);
622			std::fill((int*)values[0] + scalarSize*2,	(int*)values[0] + scalarSize*3,		0);
623			fillRandomScalars(rnd, intRanges[precision].x(), intRanges[precision].y(), (int*)values[0] + scalarSize*3, (numValues-3)*scalarSize);
624		}
625	}
626
627	bool compare (const void* const* inputs, const void* const* outputs)
628	{
629		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
630		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
631		const int				scalarSize		= glu::getDataTypeScalarSize(type);
632
633		if (glu::isDataTypeFloatOrVec(type))
634		{
635			// Both highp and mediump should be able to represent -1, 0, and +1 exactly
636			const deUint32 maxUlpDiff = precision == glu::PRECISION_LOWP ? getMaxUlpDiffFromBits(getMinMantissaBits(precision)) : 0;
637
638			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
639			{
640				const float		in0			= ((const float*)inputs[0])[compNdx];
641				const float		out0		= ((const float*)outputs[0])[compNdx];
642				const float		ref0		= in0 < 0.0f ? -1.0f :
643											  in0 > 0.0f ? +1.0f : 0.0f;
644				const deUint32	ulpDiff0	= getUlpDiff(out0, ref0);
645
646				if (ulpDiff0 > maxUlpDiff)
647				{
648					m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref0) << " with ULP threshold " << maxUlpDiff << ", got ULP diff " << ulpDiff0;
649					return false;
650				}
651			}
652		}
653		else
654		{
655			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
656			{
657				const int	in0		= ((const int*)inputs[0])[compNdx];
658				const int	out0	= ((const int*)outputs[0])[compNdx];
659				const int	ref0	= in0 < 0 ? -1 :
660									  in0 > 0 ? +1 : 0;
661
662				if (out0 != ref0)
663				{
664					m_failMsg << "Expected [" << compNdx << "] = " << ref0;
665					return false;
666				}
667			}
668		}
669
670		return true;
671	}
672};
673
674static float roundEven (float v)
675{
676	const float		q			= deFloatFrac(v);
677	const int		truncated	= int(v-q);
678	const int		rounded		= (q > 0.5f)							? (truncated + 1) :	// Rounded up
679									(q == 0.5f && (truncated % 2 != 0))	? (truncated + 1) :	// Round to nearest even at 0.5
680									truncated;												// Rounded down
681
682	return float(rounded);
683}
684
685class RoundEvenCase : public CommonFunctionCase
686{
687public:
688	RoundEvenCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
689		: CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "roundEven", shaderType)
690	{
691		m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
692		m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision)));
693		m_spec.source = "out0 = roundEven(in0);";
694	}
695
696	void getInputValues (int numValues, void* const* values) const
697	{
698		const Vec2 ranges[] =
699		{
700			Vec2(-2.0f,		2.0f),	// lowp
701			Vec2(-1e3f,		1e3f),	// mediump
702			Vec2(-1e7f,		1e7f)	// highp
703		};
704
705		de::Random				rnd				(deStringHash(getName()) ^ 0xac23fu);
706		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
707		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
708		const int				scalarSize		= glu::getDataTypeScalarSize(type);
709		int						numSpecialCases	= 0;
710
711		// Special cases.
712		if (precision != glu::PRECISION_LOWP)
713		{
714			DE_ASSERT(numValues >= 20);
715			for (int ndx = 0; ndx < 20; ndx++)
716			{
717				const float v = de::clamp(float(ndx) - 10.5f, ranges[precision].x(), ranges[precision].y());
718				std::fill((float*)values[0], (float*)values[0] + scalarSize, v);
719				numSpecialCases += 1;
720			}
721		}
722
723		// Random cases.
724		fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), (float*)values[0] + numSpecialCases*scalarSize, (numValues-numSpecialCases)*scalarSize);
725
726		// If precision is mediump, make sure values can be represented in fp16 exactly
727		if (precision == glu::PRECISION_MEDIUMP)
728		{
729			for (int ndx = 0; ndx < numValues*scalarSize; ndx++)
730				((float*)values[0])[ndx] = tcu::Float16(((float*)values[0])[ndx]).asFloat();
731		}
732	}
733
734	bool compare (const void* const* inputs, const void* const* outputs)
735	{
736		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
737		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
738		const bool				hasSignedZero	= supportsSignedZero(precision);
739		const int				scalarSize		= glu::getDataTypeScalarSize(type);
740
741		if (precision == glu::PRECISION_HIGHP || precision == glu::PRECISION_MEDIUMP)
742		{
743			// Require exact rounding result.
744			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
745			{
746				const float		in0			= ((const float*)inputs[0])[compNdx];
747				const float		out0		= ((const float*)outputs[0])[compNdx];
748				const float		ref			= roundEven(in0);
749
750				const deUint32	ulpDiff		= hasSignedZero ? getUlpDiff(out0, ref) : getUlpDiffIgnoreZeroSign(out0, ref);
751
752				if (ulpDiff > 0)
753				{
754					m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref) << ", got ULP diff " << tcu::toHex(ulpDiff);
755					return false;
756				}
757			}
758		}
759		else
760		{
761			const int		mantissaBits	= getMinMantissaBits(precision);
762			const deUint32	maxUlpDiff		= getMaxUlpDiffFromBits(mantissaBits);	// ULP diff for rounded integer value.
763			const float		eps				= getEpsFromBits(1.0f, mantissaBits);	// epsilon for rounding bounds
764
765			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
766			{
767				const float		in0			= ((const float*)inputs[0])[compNdx];
768				const float		out0		= ((const float*)outputs[0])[compNdx];
769				const int		minRes		= int(roundEven(in0-eps));
770				const int		maxRes		= int(roundEven(in0+eps));
771				bool			anyOk		= false;
772
773				for (int roundedVal = minRes; roundedVal <= maxRes; roundedVal++)
774				{
775					const deUint32 ulpDiff = getUlpDiffIgnoreZeroSign(out0, float(roundedVal));
776
777					if (ulpDiff <= maxUlpDiff)
778					{
779						anyOk = true;
780						break;
781					}
782				}
783
784				if (!anyOk)
785				{
786					m_failMsg << "Expected [" << compNdx << "] = [" << minRes << ", " << maxRes << "] with ULP threshold " << tcu::toHex(maxUlpDiff);
787					return false;
788				}
789			}
790		}
791
792		return true;
793	}
794};
795
796class ModfCase : public CommonFunctionCase
797{
798public:
799	ModfCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
800		: CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "modf", shaderType)
801	{
802		m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
803		m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision)));
804		m_spec.outputs.push_back(Symbol("out1", glu::VarType(baseType, precision)));
805		m_spec.source = "out0 = modf(in0, out1);";
806	}
807
808	void getInputValues (int numValues, void* const* values) const
809	{
810		const Vec2 ranges[] =
811		{
812			Vec2(-2.0f,		2.0f),	// lowp
813			Vec2(-1e3f,		1e3f),	// mediump
814			Vec2(-1e7f,		1e7f)	// highp
815		};
816
817		de::Random				rnd			(deStringHash(getName()) ^ 0xac23fu);
818		const glu::DataType		type		= m_spec.inputs[0].varType.getBasicType();
819		const glu::Precision	precision	= m_spec.inputs[0].varType.getPrecision();
820		const int				scalarSize	= glu::getDataTypeScalarSize(type);
821
822		fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), values[0], numValues*scalarSize);
823	}
824
825	bool compare (const void* const* inputs, const void* const* outputs)
826	{
827		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
828		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
829		const bool				hasZeroSign		= supportsSignedZero(precision);
830		const int				scalarSize		= glu::getDataTypeScalarSize(type);
831
832		const int				mantissaBits	= getMinMantissaBits(precision);
833
834		for (int compNdx = 0; compNdx < scalarSize; compNdx++)
835		{
836			const float		in0			= ((const float*)inputs[0])[compNdx];
837			const float		out0		= ((const float*)outputs[0])[compNdx];
838			const float		out1		= ((const float*)outputs[1])[compNdx];
839
840			const float		refOut1		= float(int(in0));
841			const float		refOut0		= in0 - refOut1;
842
843			const int		bitsLost	= precision != glu::PRECISION_HIGHP ? numBitsLostInOp(in0, refOut0) : 0;
844			const deUint32	maxUlpDiff	= getMaxUlpDiffFromBits(de::max(mantissaBits - bitsLost, 0));
845
846			const float		resSum		= out0 + out1;
847
848			const deUint32	ulpDiff		= hasZeroSign ? getUlpDiff(resSum, in0) : getUlpDiffIgnoreZeroSign(resSum, in0);
849
850			if (ulpDiff > maxUlpDiff)
851			{
852				m_failMsg << "Expected [" << compNdx << "] = (" << HexFloat(refOut0) << ") + (" << HexFloat(refOut1) << ") = " << HexFloat(in0) << " with ULP threshold "
853							<< tcu::toHex(maxUlpDiff) << ", got ULP diff " << tcu::toHex(ulpDiff);
854				return false;
855			}
856		}
857
858		return true;
859	}
860};
861
862class IsnanCase : public CommonFunctionCase
863{
864public:
865	IsnanCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
866		: CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "isnan", shaderType)
867	{
868		DE_ASSERT(glu::isDataTypeFloatOrVec(baseType));
869
870		const int			vecSize		= glu::getDataTypeScalarSize(baseType);
871		const glu::DataType	boolType	= vecSize > 1 ? glu::getDataTypeBoolVec(vecSize) : glu::TYPE_BOOL;
872
873		m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
874		m_spec.outputs.push_back(Symbol("out0", glu::VarType(boolType, glu::PRECISION_LAST)));
875		m_spec.source = "out0 = isnan(in0);";
876	}
877
878	void getInputValues (int numValues, void* const* values) const
879	{
880		de::Random				rnd				(deStringHash(getName()) ^ 0xc2a39fu);
881		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
882		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
883		const int				scalarSize		= glu::getDataTypeScalarSize(type);
884		const int				mantissaBits	= getMinMantissaBits(precision);
885		const deUint32			mantissaMask	= ~getMaxUlpDiffFromBits(mantissaBits) & ((1u<<23)-1u);
886
887		for (int valNdx = 0; valNdx < numValues*scalarSize; valNdx++)
888		{
889			const bool		isNan		= rnd.getFloat() > 0.3f;
890			const bool		isInf		= !isNan && rnd.getFloat() > 0.4f;
891			const deUint32	mantissa	= !isInf ? ((1u<<22) | (rnd.getUint32() & mantissaMask)) : 0;
892			const deUint32	exp			= !isNan && !isInf ? (rnd.getUint32() & 0x7fu) : 0xffu;
893			const deUint32	sign		= rnd.getUint32() & 0x1u;
894			const deUint32	value		= (sign << 31) | (exp << 23) | mantissa;
895
896			DE_ASSERT(tcu::Float32(value).isInf() == isInf && tcu::Float32(value).isNaN() == isNan);
897
898			((deUint32*)values[0])[valNdx] = value;
899		}
900	}
901
902	bool compare (const void* const* inputs, const void* const* outputs)
903	{
904		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
905		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
906		const int				scalarSize		= glu::getDataTypeScalarSize(type);
907
908		if (precision == glu::PRECISION_HIGHP)
909		{
910			// Only highp is required to support inf/nan
911			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
912			{
913				const float		in0		= ((const float*)inputs[0])[compNdx];
914				const bool		out0	= ((const deUint32*)outputs[0])[compNdx] != 0;
915				const bool		ref		= tcu::Float32(in0).isNaN();
916
917				if (out0 != ref)
918				{
919					m_failMsg << "Expected [" << compNdx << "] = " << (ref ? "true" : "false");
920					return false;
921				}
922			}
923		}
924		else if (precision == glu::PRECISION_MEDIUMP || precision == glu::PRECISION_LOWP)
925		{
926			// NaN support is optional, check that inputs that are not NaN don't result in true.
927			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
928			{
929				const float		in0		= ((const float*)inputs[0])[compNdx];
930				const bool		out0	= ((const deUint32*)outputs[0])[compNdx] != 0;
931				const bool		ref		= tcu::Float32(in0).isNaN();
932
933				if (!ref && out0)
934				{
935					m_failMsg << "Expected [" << compNdx << "] = " << (ref ? "true" : "false");
936					return false;
937				}
938			}
939		}
940
941		return true;
942	}
943};
944
945class IsinfCase : public CommonFunctionCase
946{
947public:
948	IsinfCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
949		: CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "isinf", shaderType)
950	{
951		DE_ASSERT(glu::isDataTypeFloatOrVec(baseType));
952
953		const int			vecSize		= glu::getDataTypeScalarSize(baseType);
954		const glu::DataType	boolType	= vecSize > 1 ? glu::getDataTypeBoolVec(vecSize) : glu::TYPE_BOOL;
955
956		m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
957		m_spec.outputs.push_back(Symbol("out0", glu::VarType(boolType, glu::PRECISION_LAST)));
958		m_spec.source = "out0 = isinf(in0);";
959	}
960
961	void getInputValues (int numValues, void* const* values) const
962	{
963		de::Random				rnd				(deStringHash(getName()) ^ 0xc2a39fu);
964		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
965		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
966		const int				scalarSize		= glu::getDataTypeScalarSize(type);
967		const int				mantissaBits	= getMinMantissaBits(precision);
968		const deUint32			mantissaMask	= ~getMaxUlpDiffFromBits(mantissaBits) & ((1u<<23)-1u);
969
970		for (int valNdx = 0; valNdx < numValues*scalarSize; valNdx++)
971		{
972			const bool		isInf		= rnd.getFloat() > 0.3f;
973			const bool		isNan		= !isInf && rnd.getFloat() > 0.4f;
974			const deUint32	mantissa	= !isInf ? ((1u<<22) | (rnd.getUint32() & mantissaMask)) : 0;
975			const deUint32	exp			= !isNan && !isInf ? (rnd.getUint32() & 0x7fu) : 0xffu;
976			const deUint32	sign		= rnd.getUint32() & 0x1u;
977			const deUint32	value		= (sign << 31) | (exp << 23) | mantissa;
978
979			DE_ASSERT(tcu::Float32(value).isInf() == isInf && tcu::Float32(value).isNaN() == isNan);
980
981			((deUint32*)values[0])[valNdx] = value;
982		}
983	}
984
985	bool compare (const void* const* inputs, const void* const* outputs)
986	{
987		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
988		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
989		const int				scalarSize		= glu::getDataTypeScalarSize(type);
990
991		if (precision == glu::PRECISION_HIGHP)
992		{
993			// Only highp is required to support inf/nan
994			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
995			{
996				const float		in0		= ((const float*)inputs[0])[compNdx];
997				const bool		out0	= ((const deUint32*)outputs[0])[compNdx] != 0;
998				const bool		ref		= tcu::Float32(in0).isInf();
999
1000				if (out0 != ref)
1001				{
1002					m_failMsg << "Expected [" << compNdx << "] = " << HexBool(ref);
1003					return false;
1004				}
1005			}
1006		}
1007		else if (precision == glu::PRECISION_MEDIUMP)
1008		{
1009			// Inf support is optional, check that inputs that are not Inf in mediump don't result in true.
1010			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1011			{
1012				const float		in0		= ((const float*)inputs[0])[compNdx];
1013				const bool		out0	= ((const deUint32*)outputs[0])[compNdx] != 0;
1014				const bool		ref		= tcu::Float16(in0).isInf();
1015
1016				if (!ref && out0)
1017				{
1018					m_failMsg << "Expected [" << compNdx << "] = " << (ref ? "true" : "false");
1019					return false;
1020				}
1021			}
1022		}
1023		// else: no verification can be performed
1024
1025		return true;
1026	}
1027};
1028
1029class FloatBitsToUintIntCase : public CommonFunctionCase
1030{
1031public:
1032	FloatBitsToUintIntCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType, bool outIsSigned)
1033		: CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), outIsSigned ? "floatBitsToInt" : "floatBitsToUint", shaderType)
1034	{
1035		const int			vecSize		= glu::getDataTypeScalarSize(baseType);
1036		const glu::DataType	intType		= outIsSigned ? (vecSize > 1 ? glu::getDataTypeIntVec(vecSize) : glu::TYPE_INT)
1037													  : (vecSize > 1 ? glu::getDataTypeUintVec(vecSize) : glu::TYPE_UINT);
1038
1039		m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
1040		m_spec.outputs.push_back(Symbol("out0", glu::VarType(intType, glu::PRECISION_HIGHP)));
1041		m_spec.source = outIsSigned ? "out0 = floatBitsToInt(in0);" : "out0 = floatBitsToUint(in0);";
1042	}
1043
1044	void getInputValues (int numValues, void* const* values) const
1045	{
1046		const Vec2 ranges[] =
1047		{
1048			Vec2(-2.0f,		2.0f),	// lowp
1049			Vec2(-1e3f,		1e3f),	// mediump
1050			Vec2(-1e7f,		1e7f)	// highp
1051		};
1052
1053		de::Random				rnd			(deStringHash(getName()) ^ 0x2790au);
1054		const glu::DataType		type		= m_spec.inputs[0].varType.getBasicType();
1055		const glu::Precision	precision	= m_spec.inputs[0].varType.getPrecision();
1056		const int				scalarSize	= glu::getDataTypeScalarSize(type);
1057
1058		fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), values[0], numValues*scalarSize);
1059	}
1060
1061	bool compare (const void* const* inputs, const void* const* outputs)
1062	{
1063		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
1064		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
1065		const int				scalarSize		= glu::getDataTypeScalarSize(type);
1066
1067		const int				mantissaBits	= getMinMantissaBits(precision);
1068		const int				maxUlpDiff		= getMaxUlpDiffFromBits(mantissaBits);
1069
1070		for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1071		{
1072			const float		in0			= ((const float*)inputs[0])[compNdx];
1073			const deUint32	out0		= ((const deUint32*)outputs[0])[compNdx];
1074			const deUint32	refOut0		= tcu::Float32(in0).bits();
1075			const int		ulpDiff		= de::abs((int)out0 - (int)refOut0);
1076
1077			if (ulpDiff > maxUlpDiff)
1078			{
1079				m_failMsg << "Expected [" << compNdx << "] = " << tcu::toHex(refOut0) << " with threshold "
1080							<< tcu::toHex(maxUlpDiff) << ", got diff " << tcu::toHex(ulpDiff);
1081				return false;
1082			}
1083		}
1084
1085		return true;
1086	}
1087};
1088
1089class FloatBitsToIntCase : public FloatBitsToUintIntCase
1090{
1091public:
1092	FloatBitsToIntCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
1093		: FloatBitsToUintIntCase(context, baseType, precision, shaderType, true)
1094	{
1095	}
1096};
1097
1098class FloatBitsToUintCase : public FloatBitsToUintIntCase
1099{
1100public:
1101	FloatBitsToUintCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
1102		: FloatBitsToUintIntCase(context, baseType, precision, shaderType, false)
1103	{
1104	}
1105};
1106
1107class BitsToFloatCase : public CommonFunctionCase
1108{
1109public:
1110	BitsToFloatCase (Context& context, glu::DataType baseType, glu::ShaderType shaderType)
1111		: CommonFunctionCase(context, getCommonFuncCaseName(baseType, glu::PRECISION_HIGHP, shaderType).c_str(), glu::isDataTypeIntOrIVec(baseType) ? "intBitsToFloat" : "uintBitsToFloat", shaderType)
1112	{
1113		const bool			inIsSigned	= glu::isDataTypeIntOrIVec(baseType);
1114		const int			vecSize		= glu::getDataTypeScalarSize(baseType);
1115		const glu::DataType	floatType	= vecSize > 1 ? glu::getDataTypeFloatVec(vecSize) : glu::TYPE_FLOAT;
1116
1117		m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, glu::PRECISION_HIGHP)));
1118		m_spec.outputs.push_back(Symbol("out0", glu::VarType(floatType, glu::PRECISION_HIGHP)));
1119		m_spec.source = inIsSigned ? "out0 = intBitsToFloat(in0);" : "out0 = uintBitsToFloat(in0);";
1120	}
1121
1122	void getInputValues (int numValues, void* const* values) const
1123	{
1124		de::Random				rnd			(deStringHash(getName()) ^ 0xbbb225u);
1125		const glu::DataType		type		= m_spec.inputs[0].varType.getBasicType();
1126		const int				scalarSize	= glu::getDataTypeScalarSize(type);
1127		const Vec2				range		(-1e8f, +1e8f);
1128
1129		// \note Filled as floats.
1130		fillRandomScalars(rnd, range.x(), range.y(), values[0], numValues*scalarSize);
1131	}
1132
1133	bool compare (const void* const* inputs, const void* const* outputs)
1134	{
1135		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
1136		const int				scalarSize		= glu::getDataTypeScalarSize(type);
1137		const deUint32			maxUlpDiff		= 0;
1138
1139		for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1140		{
1141			const float		in0			= ((const float*)inputs[0])[compNdx];
1142			const float		out0		= ((const float*)outputs[0])[compNdx];
1143			const deUint32	ulpDiff		= getUlpDiff(in0, out0);
1144
1145			if (ulpDiff > maxUlpDiff)
1146			{
1147				m_failMsg << "Expected [" << compNdx << "] = " << tcu::toHex(tcu::Float32(in0).bits()) << " with ULP threshold "
1148							<< tcu::toHex(maxUlpDiff) << ", got ULP diff " << tcu::toHex(ulpDiff);
1149				return false;
1150			}
1151		}
1152
1153		return true;
1154	}
1155};
1156
1157class FloorCase : public CommonFunctionCase
1158{
1159public:
1160	FloorCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
1161		: CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "floor", shaderType)
1162	{
1163		m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
1164		m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision)));
1165		m_spec.source = "out0 = floor(in0);";
1166	}
1167
1168	void getInputValues (int numValues, void* const* values) const
1169	{
1170		const Vec2 ranges[] =
1171		{
1172			Vec2(-2.0f,		2.0f),	// lowp
1173			Vec2(-1e3f,		1e3f),	// mediump
1174			Vec2(-1e7f,		1e7f)	// highp
1175		};
1176
1177		de::Random				rnd			(deStringHash(getName()) ^ 0xac23fu);
1178		const glu::DataType		type		= m_spec.inputs[0].varType.getBasicType();
1179		const glu::Precision	precision	= m_spec.inputs[0].varType.getPrecision();
1180		const int				scalarSize	= glu::getDataTypeScalarSize(type);
1181		// Random cases.
1182		fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), (float*)values[0], numValues*scalarSize);
1183
1184		// If precision is mediump, make sure values can be represented in fp16 exactly
1185		if (precision == glu::PRECISION_MEDIUMP)
1186		{
1187			for (int ndx = 0; ndx < numValues*scalarSize; ndx++)
1188				((float*)values[0])[ndx] = tcu::Float16(((float*)values[0])[ndx]).asFloat();
1189		}
1190	}
1191
1192	bool compare (const void* const* inputs, const void* const* outputs)
1193	{
1194		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
1195		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
1196		const int				scalarSize		= glu::getDataTypeScalarSize(type);
1197
1198		if (precision == glu::PRECISION_HIGHP || precision == glu::PRECISION_MEDIUMP)
1199		{
1200			// Require exact result.
1201			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1202			{
1203				const float		in0			= ((const float*)inputs[0])[compNdx];
1204				const float		out0		= ((const float*)outputs[0])[compNdx];
1205				const float		ref			= deFloatFloor(in0);
1206
1207				const deUint32	ulpDiff		= getUlpDiff(out0, ref);
1208
1209				if (ulpDiff > 0)
1210				{
1211					m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref) << ", got ULP diff " << tcu::toHex(ulpDiff);
1212					return false;
1213				}
1214			}
1215		}
1216		else
1217		{
1218			const int		mantissaBits	= getMinMantissaBits(precision);
1219			const deUint32	maxUlpDiff		= getMaxUlpDiffFromBits(mantissaBits);	// ULP diff for rounded integer value.
1220			const float		eps				= getEpsFromBits(1.0f, mantissaBits);	// epsilon for rounding bounds
1221
1222			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1223			{
1224				const float		in0			= ((const float*)inputs[0])[compNdx];
1225				const float		out0		= ((const float*)outputs[0])[compNdx];
1226				const int		minRes		= int(deFloatFloor(in0-eps));
1227				const int		maxRes		= int(deFloatFloor(in0+eps));
1228				bool			anyOk		= false;
1229
1230				for (int roundedVal = minRes; roundedVal <= maxRes; roundedVal++)
1231				{
1232					const deUint32 ulpDiff = getUlpDiff(out0, float(roundedVal));
1233
1234					if (ulpDiff <= maxUlpDiff)
1235					{
1236						anyOk = true;
1237						break;
1238					}
1239				}
1240
1241				if (!anyOk)
1242				{
1243					m_failMsg << "Expected [" << compNdx << "] = [" << minRes << ", " << maxRes << "] with ULP threshold " << tcu::toHex(maxUlpDiff);
1244					return false;
1245				}
1246			}
1247		}
1248
1249		return true;
1250	}
1251};
1252
1253class TruncCase : public CommonFunctionCase
1254{
1255public:
1256	TruncCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
1257		: CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "trunc", shaderType)
1258	{
1259		m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
1260		m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision)));
1261		m_spec.source = "out0 = trunc(in0);";
1262	}
1263
1264	void getInputValues (int numValues, void* const* values) const
1265	{
1266		const Vec2 ranges[] =
1267		{
1268			Vec2(-2.0f,		2.0f),	// lowp
1269			Vec2(-1e3f,		1e3f),	// mediump
1270			Vec2(-1e7f,		1e7f)	// highp
1271		};
1272
1273		de::Random				rnd				(deStringHash(getName()) ^ 0xac23fu);
1274		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
1275		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
1276		const int				scalarSize		= glu::getDataTypeScalarSize(type);
1277		const float				specialCases[]	= { 0.0f, -0.0f, -0.9f, 0.9f, 1.0f, -1.0f };
1278		const int				numSpecialCases	= DE_LENGTH_OF_ARRAY(specialCases);
1279
1280		// Special cases
1281		for (int caseNdx = 0; caseNdx < numSpecialCases; caseNdx++)
1282		{
1283			for (int scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++)
1284				((float*)values[0])[caseNdx*scalarSize + scalarNdx] = specialCases[caseNdx];
1285		}
1286
1287		// Random cases.
1288		fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), (float*)values[0] + scalarSize*numSpecialCases, (numValues-numSpecialCases)*scalarSize);
1289
1290		// If precision is mediump, make sure values can be represented in fp16 exactly
1291		if (precision == glu::PRECISION_MEDIUMP)
1292		{
1293			for (int ndx = 0; ndx < numValues*scalarSize; ndx++)
1294				((float*)values[0])[ndx] = tcu::Float16(((float*)values[0])[ndx]).asFloat();
1295		}
1296	}
1297
1298	bool compare (const void* const* inputs, const void* const* outputs)
1299	{
1300		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
1301		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
1302		const int				scalarSize		= glu::getDataTypeScalarSize(type);
1303
1304		if (precision == glu::PRECISION_HIGHP || precision == glu::PRECISION_MEDIUMP)
1305		{
1306			// Require exact result.
1307			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1308			{
1309				const float		in0			= ((const float*)inputs[0])[compNdx];
1310				const float		out0		= ((const float*)outputs[0])[compNdx];
1311				const bool		isNeg		= tcu::Float32(in0).sign() < 0;
1312				const float		ref			= isNeg ? (-float(int(-in0))) : float(int(in0));
1313
1314				// \note: trunc() function definition is a bit broad on negative zeros. Ignore result sign if zero.
1315				const deUint32	ulpDiff		= getUlpDiffIgnoreZeroSign(out0, ref);
1316
1317				if (ulpDiff > 0)
1318				{
1319					m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref) << ", got ULP diff " << tcu::toHex(ulpDiff);
1320					return false;
1321				}
1322			}
1323		}
1324		else
1325		{
1326			const int		mantissaBits	= getMinMantissaBits(precision);
1327			const deUint32	maxUlpDiff		= getMaxUlpDiffFromBits(mantissaBits);	// ULP diff for rounded integer value.
1328			const float		eps				= getEpsFromBits(1.0f, mantissaBits);	// epsilon for rounding bounds
1329
1330			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1331			{
1332				const float		in0			= ((const float*)inputs[0])[compNdx];
1333				const float		out0		= ((const float*)outputs[0])[compNdx];
1334				const int		minRes		= int(in0-eps);
1335				const int		maxRes		= int(in0+eps);
1336				bool			anyOk		= false;
1337
1338				for (int roundedVal = minRes; roundedVal <= maxRes; roundedVal++)
1339				{
1340					const deUint32 ulpDiff = getUlpDiffIgnoreZeroSign(out0, float(roundedVal));
1341
1342					if (ulpDiff <= maxUlpDiff)
1343					{
1344						anyOk = true;
1345						break;
1346					}
1347				}
1348
1349				if (!anyOk)
1350				{
1351					m_failMsg << "Expected [" << compNdx << "] = [" << minRes << ", " << maxRes << "] with ULP threshold " << tcu::toHex(maxUlpDiff);
1352					return false;
1353				}
1354			}
1355		}
1356
1357		return true;
1358	}
1359};
1360
1361class RoundCase : public CommonFunctionCase
1362{
1363public:
1364	RoundCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
1365		: CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "round", shaderType)
1366	{
1367		m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
1368		m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision)));
1369		m_spec.source = "out0 = round(in0);";
1370	}
1371
1372	void getInputValues (int numValues, void* const* values) const
1373	{
1374		const Vec2 ranges[] =
1375		{
1376			Vec2(-2.0f,		2.0f),	// lowp
1377			Vec2(-1e3f,		1e3f),	// mediump
1378			Vec2(-1e7f,		1e7f)	// highp
1379		};
1380
1381		de::Random				rnd				(deStringHash(getName()) ^ 0xac23fu);
1382		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
1383		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
1384		const int				scalarSize		= glu::getDataTypeScalarSize(type);
1385		int						numSpecialCases	= 0;
1386
1387		// Special cases.
1388		if (precision != glu::PRECISION_LOWP)
1389		{
1390			DE_ASSERT(numValues >= 10);
1391			for (int ndx = 0; ndx < 10; ndx++)
1392			{
1393				const float v = de::clamp(float(ndx) - 5.5f, ranges[precision].x(), ranges[precision].y());
1394				std::fill((float*)values[0], (float*)values[0] + scalarSize, v);
1395				numSpecialCases += 1;
1396			}
1397		}
1398
1399		// Random cases.
1400		fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), (float*)values[0] + numSpecialCases*scalarSize, (numValues-numSpecialCases)*scalarSize);
1401
1402		// If precision is mediump, make sure values can be represented in fp16 exactly
1403		if (precision == glu::PRECISION_MEDIUMP)
1404		{
1405			for (int ndx = 0; ndx < numValues*scalarSize; ndx++)
1406				((float*)values[0])[ndx] = tcu::Float16(((float*)values[0])[ndx]).asFloat();
1407		}
1408	}
1409
1410	bool compare (const void* const* inputs, const void* const* outputs)
1411	{
1412		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
1413		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
1414		const bool				hasZeroSign		= supportsSignedZero(precision);
1415		const int				scalarSize		= glu::getDataTypeScalarSize(type);
1416
1417		if (precision == glu::PRECISION_HIGHP || precision == glu::PRECISION_MEDIUMP)
1418		{
1419			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1420			{
1421				const float		in0			= ((const float*)inputs[0])[compNdx];
1422				const float		out0		= ((const float*)outputs[0])[compNdx];
1423
1424				if (deFloatFrac(in0) == 0.5f)
1425				{
1426					// Allow both ceil(in) and floor(in)
1427					const float		ref0		= deFloatFloor(in0);
1428					const float		ref1		= deFloatCeil(in0);
1429					const deUint32	ulpDiff0	= hasZeroSign ? getUlpDiff(out0, ref0) : getUlpDiffIgnoreZeroSign(out0, ref0);
1430					const deUint32	ulpDiff1	= hasZeroSign ? getUlpDiff(out0, ref1) : getUlpDiffIgnoreZeroSign(out0, ref1);
1431
1432					if (ulpDiff0 > 0 && ulpDiff1 > 0)
1433					{
1434						m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref0) << " or " << HexFloat(ref1) << ", got ULP diff " << tcu::toHex(de::min(ulpDiff0, ulpDiff1));
1435						return false;
1436					}
1437				}
1438				else
1439				{
1440					// Require exact result
1441					const float		ref		= roundEven(in0);
1442					const deUint32	ulpDiff	= hasZeroSign ? getUlpDiff(out0, ref) : getUlpDiffIgnoreZeroSign(out0, ref);
1443
1444					if (ulpDiff > 0)
1445					{
1446						m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref) << ", got ULP diff " << tcu::toHex(ulpDiff);
1447						return false;
1448					}
1449				}
1450			}
1451		}
1452		else
1453		{
1454			const int		mantissaBits	= getMinMantissaBits(precision);
1455			const deUint32	maxUlpDiff		= getMaxUlpDiffFromBits(mantissaBits);	// ULP diff for rounded integer value.
1456			const float		eps				= getEpsFromBits(1.0f, mantissaBits);	// epsilon for rounding bounds
1457
1458			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1459			{
1460				const float		in0			= ((const float*)inputs[0])[compNdx];
1461				const float		out0		= ((const float*)outputs[0])[compNdx];
1462				const int		minRes		= int(roundEven(in0-eps));
1463				const int		maxRes		= int(roundEven(in0+eps));
1464				bool			anyOk		= false;
1465
1466				for (int roundedVal = minRes; roundedVal <= maxRes; roundedVal++)
1467				{
1468					const deUint32 ulpDiff = getUlpDiffIgnoreZeroSign(out0, float(roundedVal));
1469
1470					if (ulpDiff <= maxUlpDiff)
1471					{
1472						anyOk = true;
1473						break;
1474					}
1475				}
1476
1477				if (!anyOk)
1478				{
1479					m_failMsg << "Expected [" << compNdx << "] = [" << minRes << ", " << maxRes << "] with ULP threshold " << tcu::toHex(maxUlpDiff);
1480					return false;
1481				}
1482			}
1483		}
1484
1485		return true;
1486	}
1487};
1488
1489class CeilCase : public CommonFunctionCase
1490{
1491public:
1492	CeilCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
1493		: CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "ceil", shaderType)
1494	{
1495		m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
1496		m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision)));
1497		m_spec.source = "out0 = ceil(in0);";
1498	}
1499
1500	void getInputValues (int numValues, void* const* values) const
1501	{
1502		const Vec2 ranges[] =
1503		{
1504			Vec2(-2.0f,		2.0f),	// lowp
1505			Vec2(-1e3f,		1e3f),	// mediump
1506			Vec2(-1e7f,		1e7f)	// highp
1507		};
1508
1509		de::Random				rnd			(deStringHash(getName()) ^ 0xac23fu);
1510		const glu::DataType		type		= m_spec.inputs[0].varType.getBasicType();
1511		const glu::Precision	precision	= m_spec.inputs[0].varType.getPrecision();
1512		const int				scalarSize	= glu::getDataTypeScalarSize(type);
1513
1514		// Random cases.
1515		fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), (float*)values[0], numValues*scalarSize);
1516
1517		// If precision is mediump, make sure values can be represented in fp16 exactly
1518		if (precision == glu::PRECISION_MEDIUMP)
1519		{
1520			for (int ndx = 0; ndx < numValues*scalarSize; ndx++)
1521				((float*)values[0])[ndx] = tcu::Float16(((float*)values[0])[ndx]).asFloat();
1522		}
1523	}
1524
1525	bool compare (const void* const* inputs, const void* const* outputs)
1526	{
1527		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
1528		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
1529		const bool				hasZeroSign		= supportsSignedZero(precision);
1530		const int				scalarSize		= glu::getDataTypeScalarSize(type);
1531
1532		if (precision == glu::PRECISION_HIGHP || precision == glu::PRECISION_MEDIUMP)
1533		{
1534			// Require exact result.
1535			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1536			{
1537				const float		in0			= ((const float*)inputs[0])[compNdx];
1538				const float		out0		= ((const float*)outputs[0])[compNdx];
1539				const float		ref			= deFloatCeil(in0);
1540
1541				const deUint32	ulpDiff		= hasZeroSign ? getUlpDiff(out0, ref) : getUlpDiffIgnoreZeroSign(out0, ref);
1542
1543				if (ulpDiff > 0)
1544				{
1545					m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref) << ", got ULP diff " << tcu::toHex(ulpDiff);
1546					return false;
1547				}
1548			}
1549		}
1550		else
1551		{
1552			const int		mantissaBits	= getMinMantissaBits(precision);
1553			const deUint32	maxUlpDiff		= getMaxUlpDiffFromBits(mantissaBits);	// ULP diff for rounded integer value.
1554			const float		eps				= getEpsFromBits(1.0f, mantissaBits);	// epsilon for rounding bounds
1555
1556			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1557			{
1558				const float		in0			= ((const float*)inputs[0])[compNdx];
1559				const float		out0		= ((const float*)outputs[0])[compNdx];
1560				const int		minRes		= int(deFloatCeil(in0-eps));
1561				const int		maxRes		= int(deFloatCeil(in0+eps));
1562				bool			anyOk		= false;
1563
1564				for (int roundedVal = minRes; roundedVal <= maxRes; roundedVal++)
1565				{
1566					const deUint32 ulpDiff = getUlpDiffIgnoreZeroSign(out0, float(roundedVal));
1567
1568					if (ulpDiff <= maxUlpDiff)
1569					{
1570						anyOk = true;
1571						break;
1572					}
1573				}
1574
1575				if (!anyOk && de::inRange(0, minRes, maxRes))
1576				{
1577					// Allow -0 as well.
1578					const int ulpDiff = de::abs((int)tcu::Float32(out0).bits() - (int)0x80000000u);
1579					anyOk = ((deUint32)ulpDiff <= maxUlpDiff);
1580				}
1581
1582				if (!anyOk)
1583				{
1584					m_failMsg << "Expected [" << compNdx << "] = [" << minRes << ", " << maxRes << "] with ULP threshold " << tcu::toHex(maxUlpDiff);
1585					return false;
1586				}
1587			}
1588		}
1589
1590		return true;
1591	}
1592};
1593
1594class FractCase : public CommonFunctionCase
1595{
1596public:
1597	FractCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
1598		: CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "fract", shaderType)
1599	{
1600		m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
1601		m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision)));
1602		m_spec.source = "out0 = fract(in0);";
1603	}
1604
1605	void getInputValues (int numValues, void* const* values) const
1606	{
1607		const Vec2 ranges[] =
1608		{
1609			Vec2(-2.0f,		2.0f),	// lowp
1610			Vec2(-1e3f,		1e3f),	// mediump
1611			Vec2(-1e7f,		1e7f)	// highp
1612		};
1613
1614		de::Random				rnd				(deStringHash(getName()) ^ 0xac23fu);
1615		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
1616		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
1617		const int				scalarSize		= glu::getDataTypeScalarSize(type);
1618		int						numSpecialCases	= 0;
1619
1620		// Special cases.
1621		if (precision != glu::PRECISION_LOWP)
1622		{
1623			DE_ASSERT(numValues >= 10);
1624			for (int ndx = 0; ndx < 10; ndx++)
1625			{
1626				const float v = de::clamp(float(ndx) - 5.5f, ranges[precision].x(), ranges[precision].y());
1627				std::fill((float*)values[0], (float*)values[0] + scalarSize, v);
1628				numSpecialCases += 1;
1629			}
1630		}
1631
1632		// Random cases.
1633		fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), (float*)values[0] + numSpecialCases*scalarSize, (numValues-numSpecialCases)*scalarSize);
1634
1635		// If precision is mediump, make sure values can be represented in fp16 exactly
1636		if (precision == glu::PRECISION_MEDIUMP)
1637		{
1638			for (int ndx = 0; ndx < numValues*scalarSize; ndx++)
1639				((float*)values[0])[ndx] = tcu::Float16(((float*)values[0])[ndx]).asFloat();
1640		}
1641	}
1642
1643	bool compare (const void* const* inputs, const void* const* outputs)
1644	{
1645		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
1646		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
1647		const bool				hasZeroSign		= supportsSignedZero(precision);
1648		const int				scalarSize		= glu::getDataTypeScalarSize(type);
1649
1650		if (precision == glu::PRECISION_HIGHP || precision == glu::PRECISION_MEDIUMP)
1651		{
1652			// Require exact result.
1653			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1654			{
1655				const float		in0			= ((const float*)inputs[0])[compNdx];
1656				const float		out0		= ((const float*)outputs[0])[compNdx];
1657				const float		ref			= deFloatFrac(in0);
1658
1659				const deUint32	ulpDiff		= hasZeroSign ? getUlpDiff(out0, ref) : getUlpDiffIgnoreZeroSign(out0, ref);
1660
1661				if (ulpDiff > 0)
1662				{
1663					m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref) << ", got ULP diff " << tcu::toHex(ulpDiff);
1664					return false;
1665				}
1666			}
1667		}
1668		else
1669		{
1670			const int		mantissaBits	= getMinMantissaBits(precision);
1671			const float		eps				= getEpsFromBits(1.0f, mantissaBits);	// epsilon for rounding bounds
1672
1673			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1674			{
1675				const float		in0			= ((const float*)inputs[0])[compNdx];
1676				const float		out0		= ((const float*)outputs[0])[compNdx];
1677
1678				if (int(deFloatFloor(in0-eps)) == int(deFloatFloor(in0+eps)))
1679				{
1680					const float		ref			= deFloatFrac(in0);
1681					const int		bitsLost	= numBitsLostInOp(in0, ref);
1682					const deUint32	maxUlpDiff	= getMaxUlpDiffFromBits(de::max(0, mantissaBits-bitsLost));	// ULP diff for rounded integer value.
1683					const deUint32	ulpDiff		= getUlpDiffIgnoreZeroSign(out0, ref);
1684
1685					if (ulpDiff > maxUlpDiff)
1686					{
1687						m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref) << " with ULP threshold " << tcu::toHex(maxUlpDiff) << ", got diff " << tcu::toHex(ulpDiff);
1688						return false;
1689					}
1690				}
1691				else
1692				{
1693					if (out0 >= 1.0f)
1694					{
1695						m_failMsg << "Expected [" << compNdx << "] < 1.0";
1696						return false;
1697					}
1698				}
1699			}
1700		}
1701
1702		return true;
1703	}
1704};
1705
1706static inline void frexp (float in, float* significand, int* exponent)
1707{
1708	const tcu::Float32 fpValue(in);
1709
1710	if (!fpValue.isZero())
1711	{
1712		// Construct float that has exactly the mantissa, and exponent of -1.
1713		*significand	= tcu::Float32::construct(fpValue.sign(), -1, fpValue.mantissa()).asFloat();
1714		*exponent		= fpValue.exponent()+1;
1715	}
1716	else
1717	{
1718		*significand	= fpValue.sign() < 0 ? -0.0f : 0.0f;
1719		*exponent		= 0;
1720	}
1721}
1722
1723static inline float ldexp (float significand, int exponent)
1724{
1725	const tcu::Float32 mant(significand);
1726
1727	if (exponent == 0 && mant.isZero())
1728	{
1729		return mant.sign() < 0 ? -0.0f : 0.0f;
1730	}
1731	else
1732	{
1733		return tcu::Float32::construct(mant.sign(), exponent+mant.exponent(), mant.mantissa()).asFloat();
1734	}
1735}
1736
1737class FrexpCase : public CommonFunctionCase
1738{
1739public:
1740	FrexpCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
1741		: CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "frexp", shaderType)
1742	{
1743		const int			vecSize		= glu::getDataTypeScalarSize(baseType);
1744		const glu::DataType	intType		= vecSize > 1 ? glu::getDataTypeIntVec(vecSize) : glu::TYPE_INT;
1745
1746		m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
1747		m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, glu::PRECISION_HIGHP)));
1748		m_spec.outputs.push_back(Symbol("out1", glu::VarType(intType, glu::PRECISION_HIGHP)));
1749		m_spec.source = "out0 = frexp(in0, out1);";
1750	}
1751
1752	void getInputValues (int numValues, void* const* values) const
1753	{
1754		const Vec2 ranges[] =
1755		{
1756			Vec2(-2.0f,		2.0f),	// lowp
1757			Vec2(-1e3f,		1e3f),	// mediump
1758			Vec2(-1e7f,		1e7f)	// highp
1759		};
1760
1761		de::Random				rnd			(deStringHash(getName()) ^ 0x2790au);
1762		const glu::DataType		type		= m_spec.inputs[0].varType.getBasicType();
1763		const glu::Precision	precision	= m_spec.inputs[0].varType.getPrecision();
1764		const int				scalarSize	= glu::getDataTypeScalarSize(type);
1765
1766		// Special cases
1767		for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1768		{
1769			((float*)values[0])[scalarSize*0 + compNdx] = 0.0f;
1770			((float*)values[0])[scalarSize*1 + compNdx] = -0.0f;
1771			((float*)values[0])[scalarSize*2 + compNdx] = 0.5f;
1772			((float*)values[0])[scalarSize*3 + compNdx] = -0.5f;
1773			((float*)values[0])[scalarSize*4 + compNdx] = 1.0f;
1774			((float*)values[0])[scalarSize*5 + compNdx] = -1.0f;
1775			((float*)values[0])[scalarSize*6 + compNdx] = 2.0f;
1776			((float*)values[0])[scalarSize*7 + compNdx] = -2.0f;
1777		}
1778
1779		fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), (float*)values[0] + 8*scalarSize, (numValues-8)*scalarSize);
1780
1781		// Make sure the values are representable in the target format
1782		for (int caseNdx = 0; caseNdx < numValues; ++caseNdx)
1783		{
1784			for (int scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++)
1785			{
1786				float* const valuePtr = &((float*)values[0])[caseNdx * scalarSize + scalarNdx];
1787
1788				*valuePtr = makeFloatRepresentable(*valuePtr, precision);
1789			}
1790		}
1791	}
1792
1793	bool compare (const void* const* inputs, const void* const* outputs)
1794	{
1795		const glu::DataType		type						= m_spec.inputs[0].varType.getBasicType();
1796		const glu::Precision	precision					= m_spec.inputs[0].varType.getPrecision();
1797		const int				scalarSize					= glu::getDataTypeScalarSize(type);
1798		const bool				signedZero					= false;
1799
1800		const int				mantissaBits				= getMinMantissaBits(precision);
1801		const deUint32			maxUlpDiff					= getMaxUlpDiffFromBits(mantissaBits);
1802
1803		for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1804		{
1805			const float		in0			= ((const float*)inputs[0])[compNdx];
1806			const float		out0		= ((const float*)outputs[0])[compNdx];
1807			const int		out1		= ((const int*)outputs[1])[compNdx];
1808
1809			float			refOut0;
1810			int				refOut1;
1811
1812			frexp(in0, &refOut0, &refOut1);
1813
1814			const deUint32	ulpDiff0	= signedZero ? getUlpDiff(out0, refOut0) : getUlpDiffIgnoreZeroSign(out0, refOut0);
1815
1816			if (ulpDiff0 > maxUlpDiff || out1 != refOut1)
1817			{
1818				m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(refOut0) << ", " << refOut1 << " with ULP threshold "
1819						  << tcu::toHex(maxUlpDiff) << ", got ULP diff " << tcu::toHex(ulpDiff0);
1820				return false;
1821			}
1822		}
1823
1824		return true;
1825	}
1826};
1827
1828class LdexpCase : public CommonFunctionCase
1829{
1830public:
1831	LdexpCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
1832		: CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "ldexp", shaderType)
1833	{
1834		const int			vecSize		= glu::getDataTypeScalarSize(baseType);
1835		const glu::DataType	intType		= vecSize > 1 ? glu::getDataTypeIntVec(vecSize) : glu::TYPE_INT;
1836
1837		m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
1838		m_spec.inputs.push_back(Symbol("in1", glu::VarType(intType, glu::PRECISION_HIGHP)));
1839		m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, glu::PRECISION_HIGHP)));
1840		m_spec.source = "out0 = ldexp(in0, in1);";
1841	}
1842
1843	void getInputValues (int numValues, void* const* values) const
1844	{
1845		const Vec2 ranges[] =
1846		{
1847			Vec2(-2.0f,		2.0f),	// lowp
1848			Vec2(-1e3f,		1e3f),	// mediump
1849			Vec2(-1e7f,		1e7f)	// highp
1850		};
1851
1852		de::Random				rnd					(deStringHash(getName()) ^ 0x2790au);
1853		const glu::DataType		type				= m_spec.inputs[0].varType.getBasicType();
1854		const glu::Precision	precision			= m_spec.inputs[0].varType.getPrecision();
1855		const int				scalarSize			= glu::getDataTypeScalarSize(type);
1856		int						valueNdx			= 0;
1857
1858		{
1859			const float easySpecialCases[] = { 0.0f, -0.0f, 0.5f, -0.5f, 1.0f, -1.0f, 2.0f, -2.0f };
1860
1861			DE_ASSERT(valueNdx + DE_LENGTH_OF_ARRAY(easySpecialCases) <= numValues);
1862			for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(easySpecialCases); caseNdx++)
1863			{
1864				float	in0;
1865				int		in1;
1866
1867				frexp(easySpecialCases[caseNdx], &in0, &in1);
1868
1869				for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1870				{
1871					((float*)values[0])[valueNdx*scalarSize + compNdx] = in0;
1872					((int*)values[1])[valueNdx*scalarSize + compNdx] = in1;
1873				}
1874
1875				valueNdx += 1;
1876			}
1877		}
1878
1879		{
1880			// \note lowp and mediump can not necessarily fit the values in hard cases, so we'll use only easy ones.
1881			const int numEasyRandomCases = precision == glu::PRECISION_HIGHP ? 50 : (numValues-valueNdx);
1882
1883			DE_ASSERT(valueNdx + numEasyRandomCases <= numValues);
1884			for (int caseNdx = 0; caseNdx < numEasyRandomCases; caseNdx++)
1885			{
1886				for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1887				{
1888					const float	in	= rnd.getFloat(ranges[precision].x(), ranges[precision].y());
1889					float		in0;
1890					int			in1;
1891
1892					frexp(in, &in0, &in1);
1893
1894					((float*)values[0])[valueNdx*scalarSize + compNdx] = in0;
1895					((int*)values[1])[valueNdx*scalarSize + compNdx] = in1;
1896				}
1897
1898				valueNdx += 1;
1899			}
1900		}
1901
1902		{
1903			const int numHardRandomCases = numValues-valueNdx;
1904			DE_ASSERT(numHardRandomCases >= 0 && valueNdx + numHardRandomCases <= numValues);
1905
1906			for (int caseNdx = 0; caseNdx < numHardRandomCases; caseNdx++)
1907			{
1908				for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1909				{
1910					const int		fpExp		= rnd.getInt(-126, 127);
1911					const int		sign		= rnd.getBool() ? -1 : +1;
1912					const deUint32	mantissa	= (1u<<23) | (rnd.getUint32() & ((1u<<23)-1));
1913					const int		in1			= rnd.getInt(de::max(-126, -126-fpExp), de::min(127, 127-fpExp));
1914					const float		in0			= tcu::Float32::construct(sign, fpExp, mantissa).asFloat();
1915
1916					DE_ASSERT(de::inRange(in1, -126, 127)); // See Khronos bug 11180
1917					DE_ASSERT(de::inRange(in1+fpExp, -126, 127));
1918
1919					const float		out			= ldexp(in0, in1);
1920
1921					DE_ASSERT(!tcu::Float32(out).isInf() && !tcu::Float32(out).isDenorm());
1922					DE_UNREF(out);
1923
1924					((float*)values[0])[valueNdx*scalarSize + compNdx] = in0;
1925					((int*)values[1])[valueNdx*scalarSize + compNdx] = in1;
1926				}
1927
1928				valueNdx += 1;
1929			}
1930		}
1931	}
1932
1933	bool compare (const void* const* inputs, const void* const* outputs)
1934	{
1935		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
1936		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
1937		const int				scalarSize		= glu::getDataTypeScalarSize(type);
1938
1939		const int				mantissaBits	= getMinMantissaBits(precision);
1940		const deUint32			maxUlpDiff		= getMaxUlpDiffFromBits(mantissaBits);
1941
1942		for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1943		{
1944			const float		in0			= ((const float*)inputs[0])[compNdx];
1945			const int		in1			= ((const int*)inputs[1])[compNdx];
1946			const float		out0		= ((const float*)outputs[0])[compNdx];
1947			const float		refOut0		= ldexp(in0, in1);
1948			const deUint32	ulpDiff		= getUlpDiffIgnoreZeroSign(out0, refOut0);
1949
1950			const int		inExp		= tcu::Float32(in0).exponent();
1951
1952			if (ulpDiff > maxUlpDiff)
1953			{
1954				m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(refOut0) << ", (exp = " << inExp << ") with ULP threshold "
1955						  << tcu::toHex(maxUlpDiff) << ", got ULP diff " << tcu::toHex(ulpDiff);
1956				return false;
1957			}
1958		}
1959
1960		return true;
1961	}
1962};
1963
1964class FmaCase : public CommonFunctionCase
1965{
1966public:
1967	FmaCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
1968		: CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "fma", shaderType)
1969	{
1970		m_spec.inputs.push_back(Symbol("a", glu::VarType(baseType, precision)));
1971		m_spec.inputs.push_back(Symbol("b", glu::VarType(baseType, precision)));
1972		m_spec.inputs.push_back(Symbol("c", glu::VarType(baseType, precision)));
1973		m_spec.outputs.push_back(Symbol("res", glu::VarType(baseType, precision)));
1974		m_spec.source = "res = fma(a, b, c);";
1975
1976		if (!glu::contextSupports(context.getRenderContext().getType(), glu::ApiType::es(3, 2)))
1977			m_spec.globalDeclarations = "#extension GL_EXT_gpu_shader5 : require\n";
1978	}
1979
1980	void init (void)
1981	{
1982		if (!glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2))
1983				&& !m_context.getContextInfo().isExtensionSupported("GL_EXT_gpu_shader5"))
1984			throw tcu::NotSupportedError("GL_EXT_gpu_shader5 not supported");
1985
1986		CommonFunctionCase::init();
1987	}
1988
1989	void getInputValues (int numValues, void* const* values) const
1990	{
1991		const Vec2 ranges[] =
1992		{
1993			Vec2(-2.0f,		2.0f),	// lowp
1994			Vec2(-127.f,	127.f),	// mediump
1995			Vec2(-1e7f,		1e7f)	// highp
1996		};
1997
1998		de::Random				rnd							(deStringHash(getName()) ^ 0xac23fu);
1999		const glu::DataType		type						= m_spec.inputs[0].varType.getBasicType();
2000		const glu::Precision	precision					= m_spec.inputs[0].varType.getPrecision();
2001		const int				scalarSize					= glu::getDataTypeScalarSize(type);
2002		const float				specialCases[][3]			=
2003		{
2004			// a		b		c
2005			{ 0.0f,		0.0f,	0.0f },
2006			{ 0.0f,		1.0f,	0.0f },
2007			{ 0.0f,		0.0f,	-1.0f },
2008			{ 1.0f,		1.0f,	0.0f },
2009			{ 1.0f,		1.0f,	1.0f },
2010			{ -1.0f,	1.0f,	0.0f },
2011			{ 1.0f,		-1.0f,	0.0f },
2012			{ -1.0f,	-1.0f,	0.0f },
2013			{ -0.0f,	1.0f,	0.0f },
2014			{ 1.0f,		-0.0f,	0.0f }
2015		};
2016		const int				numSpecialCases				= DE_LENGTH_OF_ARRAY(specialCases);
2017
2018		// Special cases
2019		for (int caseNdx = 0; caseNdx < numSpecialCases; caseNdx++)
2020		{
2021			for (int inputNdx = 0; inputNdx < 3; inputNdx++)
2022			{
2023				for (int scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++)
2024					((float*)values[inputNdx])[caseNdx*scalarSize + scalarNdx] = specialCases[caseNdx][inputNdx];
2025			}
2026		}
2027
2028		// Random cases.
2029		{
2030			const int	numScalars	= (numValues-numSpecialCases)*scalarSize;
2031			const int	offs		= scalarSize*numSpecialCases;
2032
2033			for (int inputNdx = 0; inputNdx < 3; inputNdx++)
2034				fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), (float*)values[inputNdx] + offs, numScalars);
2035		}
2036
2037		// Make sure the values are representable in the target format
2038		for (int inputNdx = 0; inputNdx < 3; inputNdx++)
2039		{
2040			for (int caseNdx = 0; caseNdx < numValues; ++caseNdx)
2041			{
2042				for (int scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++)
2043				{
2044					float* const valuePtr = &((float*)values[inputNdx])[caseNdx * scalarSize + scalarNdx];
2045
2046					*valuePtr = makeFloatRepresentable(*valuePtr, precision);
2047				}
2048			}
2049		}
2050	}
2051
2052	static tcu::Interval fma (glu::Precision precision, float a, float b, float c)
2053	{
2054		const tcu::FloatFormat formats[] =
2055		{
2056			//				 minExp		maxExp		mantissa	exact,		subnormals	infinities	NaN
2057			tcu::FloatFormat(0,			0,			7,			false,		tcu::YES,	tcu::MAYBE,	tcu::MAYBE),
2058			tcu::FloatFormat(-13,		13,			9,			false,		tcu::MAYBE,	tcu::MAYBE,	tcu::MAYBE),
2059			tcu::FloatFormat(-126,		127,		23,			true,		tcu::MAYBE, tcu::YES,	tcu::MAYBE)
2060		};
2061		const tcu::FloatFormat&	format	= de::getSizedArrayElement<glu::PRECISION_LAST>(formats, precision);
2062		const tcu::Interval		ia		= format.convert(a);
2063		const tcu::Interval		ib		= format.convert(b);
2064		const tcu::Interval		ic		= format.convert(c);
2065		tcu::Interval			prod0;
2066		tcu::Interval			prod1;
2067		tcu::Interval			prod2;
2068		tcu::Interval			prod3;
2069		tcu::Interval			prod;
2070		tcu::Interval			res;
2071
2072		TCU_SET_INTERVAL(prod0, tmp, tmp = ia.lo() * ib.lo());
2073		TCU_SET_INTERVAL(prod1, tmp, tmp = ia.lo() * ib.hi());
2074		TCU_SET_INTERVAL(prod2, tmp, tmp = ia.hi() * ib.lo());
2075		TCU_SET_INTERVAL(prod3, tmp, tmp = ia.hi() * ib.hi());
2076
2077		prod = format.convert(format.roundOut(prod0 | prod1 | prod2 | prod3, ia.isFinite() && ib.isFinite()));
2078
2079		TCU_SET_INTERVAL_BOUNDS(res, tmp,
2080								tmp = prod.lo() + ic.lo(),
2081								tmp = prod.hi() + ic.hi());
2082
2083		return format.convert(format.roundOut(res, prod.isFinite() && ic.isFinite()));
2084	}
2085
2086	bool compare (const void* const* inputs, const void* const* outputs)
2087	{
2088		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
2089		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
2090		const int				scalarSize		= glu::getDataTypeScalarSize(type);
2091
2092		for (int compNdx = 0; compNdx < scalarSize; compNdx++)
2093		{
2094			const float			a			= ((const float*)inputs[0])[compNdx];
2095			const float			b			= ((const float*)inputs[1])[compNdx];
2096			const float			c			= ((const float*)inputs[2])[compNdx];
2097			const float			res			= ((const float*)outputs[0])[compNdx];
2098			const tcu::Interval	ref			= fma(precision, a, b, c);
2099
2100			if (!ref.contains(res))
2101			{
2102				m_failMsg << "Expected [" << compNdx << "] = " << ref;
2103				return false;
2104			}
2105		}
2106
2107		return true;
2108	}
2109};
2110
2111ShaderCommonFunctionTests::ShaderCommonFunctionTests (Context& context)
2112	: TestCaseGroup(context, "common", "Common function tests")
2113{
2114}
2115
2116ShaderCommonFunctionTests::~ShaderCommonFunctionTests (void)
2117{
2118}
2119
2120template<class TestClass>
2121static void addFunctionCases (TestCaseGroup* parent, const char* functionName, bool floatTypes, bool intTypes, bool uintTypes, deUint32 shaderBits)
2122{
2123	tcu::TestCaseGroup* group = new tcu::TestCaseGroup(parent->getTestContext(), functionName, functionName);
2124	parent->addChild(group);
2125
2126	const glu::DataType scalarTypes[] =
2127	{
2128		glu::TYPE_FLOAT,
2129		glu::TYPE_INT,
2130		glu::TYPE_UINT
2131	};
2132
2133	for (int scalarTypeNdx = 0; scalarTypeNdx < DE_LENGTH_OF_ARRAY(scalarTypes); scalarTypeNdx++)
2134	{
2135		const glu::DataType scalarType = scalarTypes[scalarTypeNdx];
2136
2137		if ((!floatTypes && scalarType == glu::TYPE_FLOAT)	||
2138			(!intTypes && scalarType == glu::TYPE_INT)		||
2139			(!uintTypes && scalarType == glu::TYPE_UINT))
2140			continue;
2141
2142		for (int vecSize = 1; vecSize <= 4; vecSize++)
2143		{
2144			for (int prec = glu::PRECISION_LOWP; prec <= glu::PRECISION_HIGHP; prec++)
2145			{
2146				for (int shaderTypeNdx = 0; shaderTypeNdx < glu::SHADERTYPE_LAST; shaderTypeNdx++)
2147				{
2148					if (shaderBits & (1<<shaderTypeNdx))
2149						group->addChild(new TestClass(parent->getContext(), glu::DataType(scalarType + vecSize - 1), glu::Precision(prec), glu::ShaderType(shaderTypeNdx)));
2150				}
2151			}
2152		}
2153	}
2154}
2155
2156void ShaderCommonFunctionTests::init (void)
2157{
2158	enum
2159	{
2160		VS = (1<<glu::SHADERTYPE_VERTEX),
2161		TC = (1<<glu::SHADERTYPE_TESSELLATION_CONTROL),
2162		TE = (1<<glu::SHADERTYPE_TESSELLATION_EVALUATION),
2163		GS = (1<<glu::SHADERTYPE_GEOMETRY),
2164		FS = (1<<glu::SHADERTYPE_FRAGMENT),
2165		CS = (1<<glu::SHADERTYPE_COMPUTE),
2166
2167		ALL_SHADERS = VS|TC|TE|GS|FS|CS,
2168		NEW_SHADERS = TC|TE|GS|CS,
2169	};
2170
2171	//																	Float?	Int?	Uint?	Shaders
2172	addFunctionCases<AbsCase>				(this,	"abs",				true,	true,	false,	NEW_SHADERS);
2173	addFunctionCases<SignCase>				(this,	"sign",				true,	true,	false,	NEW_SHADERS);
2174	addFunctionCases<FloorCase>				(this,	"floor",			true,	false,	false,	NEW_SHADERS);
2175	addFunctionCases<TruncCase>				(this,	"trunc",			true,	false,	false,	NEW_SHADERS);
2176	addFunctionCases<RoundCase>				(this,	"round",			true,	false,	false,	NEW_SHADERS);
2177	addFunctionCases<RoundEvenCase>			(this,	"roundeven",		true,	false,	false,	NEW_SHADERS);
2178	addFunctionCases<CeilCase>				(this,	"ceil",				true,	false,	false,	NEW_SHADERS);
2179	addFunctionCases<FractCase>				(this,	"fract",			true,	false,	false,	NEW_SHADERS);
2180	// mod
2181	addFunctionCases<ModfCase>				(this,	"modf",				true,	false,	false,	NEW_SHADERS);
2182	// min
2183	// max
2184	// clamp
2185	// mix
2186	// step
2187	// smoothstep
2188	addFunctionCases<IsnanCase>				(this,	"isnan",			true,	false,	false,	NEW_SHADERS);
2189	addFunctionCases<IsinfCase>				(this,	"isinf",			true,	false,	false,	NEW_SHADERS);
2190	addFunctionCases<FloatBitsToIntCase>	(this,	"floatbitstoint",	true,	false,	false,	NEW_SHADERS);
2191	addFunctionCases<FloatBitsToUintCase>	(this,	"floatbitstouint",	true,	false,	false,	NEW_SHADERS);
2192
2193	addFunctionCases<FrexpCase>				(this,	"frexp",			true,	false,	false,	ALL_SHADERS);
2194	addFunctionCases<LdexpCase>				(this,	"ldexp",			true,	false,	false,	ALL_SHADERS);
2195	addFunctionCases<FmaCase>				(this,	"fma",				true,	false,	false,	ALL_SHADERS);
2196
2197	// (u)intBitsToFloat()
2198	{
2199		const deUint32		shaderBits	= NEW_SHADERS;
2200		tcu::TestCaseGroup* intGroup	= new tcu::TestCaseGroup(m_testCtx, "intbitstofloat",	"intBitsToFloat() Tests");
2201		tcu::TestCaseGroup* uintGroup	= new tcu::TestCaseGroup(m_testCtx, "uintbitstofloat",	"uintBitsToFloat() Tests");
2202
2203		addChild(intGroup);
2204		addChild(uintGroup);
2205
2206		for (int vecSize = 1; vecSize < 4; vecSize++)
2207		{
2208			const glu::DataType		intType		= vecSize > 1 ? glu::getDataTypeIntVec(vecSize) : glu::TYPE_INT;
2209			const glu::DataType		uintType	= vecSize > 1 ? glu::getDataTypeUintVec(vecSize) : glu::TYPE_UINT;
2210
2211			for (int shaderType = 0; shaderType < glu::SHADERTYPE_LAST; shaderType++)
2212			{
2213				if (shaderBits & (1<<shaderType))
2214				{
2215					intGroup->addChild(new BitsToFloatCase(m_context, intType, glu::ShaderType(shaderType)));
2216					uintGroup->addChild(new BitsToFloatCase(m_context, uintType, glu::ShaderType(shaderType)));
2217				}
2218			}
2219		}
2220	}
2221}
2222
2223} // Functional
2224} // gles31
2225} // deqp
2226