13c827367444ee418f129b2c238299f49d3264554Jarkko Poyry/*-------------------------------------------------------------------------
23c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * drawElements Quality Program OpenGL ES 3.1 Module
33c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * -------------------------------------------------
43c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *
53c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * Copyright 2014 The Android Open Source Project
63c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *
73c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * Licensed under the Apache License, Version 2.0 (the "License");
83c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * you may not use this file except in compliance with the License.
93c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * You may obtain a copy of the License at
103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *
113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *      http://www.apache.org/licenses/LICENSE-2.0
123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *
133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * Unless required by applicable law or agreed to in writing, software
143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * distributed under the License is distributed on an "AS IS" BASIS,
153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * See the License for the specific language governing permissions and
173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * limitations under the License.
183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *
193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *//*!
203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * \file
213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * \brief Common built-in function tests.
223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *//*--------------------------------------------------------------------*/
233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "es31fShaderCommonFunctionTests.hpp"
253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "gluContextInfo.hpp"
263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "glsShaderExecUtil.hpp"
273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "tcuTestLog.hpp"
283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "tcuFormatUtil.hpp"
293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "tcuFloat.hpp"
30e5fc2a804322422a6d50270e9e00fb1c193b6f90Pyry Haulos#include "tcuInterval.hpp"
31e5fc2a804322422a6d50270e9e00fb1c193b6f90Pyry Haulos#include "tcuFloatFormat.hpp"
323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "deRandom.hpp"
333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "deMath.h"
343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "deString.h"
35d6148171f88da1301f053e2e0236afc69416137cJarkko Pöyry#include "deArrayUtil.hpp"
363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
373c827367444ee418f129b2c238299f49d3264554Jarkko Poyrynamespace deqp
383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
393c827367444ee418f129b2c238299f49d3264554Jarkko Poyrynamespace gles31
403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
413c827367444ee418f129b2c238299f49d3264554Jarkko Poyrynamespace Functional
423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
443c827367444ee418f129b2c238299f49d3264554Jarkko Poyryusing std::vector;
453c827367444ee418f129b2c238299f49d3264554Jarkko Poyryusing std::string;
463c827367444ee418f129b2c238299f49d3264554Jarkko Poyryusing tcu::TestLog;
473c827367444ee418f129b2c238299f49d3264554Jarkko Poyryusing namespace gls::ShaderExecUtil;
483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
493c827367444ee418f129b2c238299f49d3264554Jarkko Poyryusing tcu::Vec2;
503c827367444ee418f129b2c238299f49d3264554Jarkko Poyryusing tcu::Vec3;
513c827367444ee418f129b2c238299f49d3264554Jarkko Poyryusing tcu::Vec4;
523c827367444ee418f129b2c238299f49d3264554Jarkko Poyryusing tcu::IVec2;
533c827367444ee418f129b2c238299f49d3264554Jarkko Poyryusing tcu::IVec3;
543c827367444ee418f129b2c238299f49d3264554Jarkko Poyryusing tcu::IVec4;
553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry// Utilities
573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
583c827367444ee418f129b2c238299f49d3264554Jarkko Poyrytemplate<typename T, int Size>
593c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystruct VecArrayAccess
603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
613c827367444ee418f129b2c238299f49d3264554Jarkko Poyrypublic:
623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry									VecArrayAccess	(const void* ptr) : m_array((tcu::Vector<T, Size>*)ptr) {}
633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry									~VecArrayAccess	(void) {}
643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const tcu::Vector<T, Size>&		operator[]		(size_t offset) const	{ return m_array[offset];	}
663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	tcu::Vector<T, Size>&			operator[]		(size_t offset)			{ return m_array[offset];	}
673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
683c827367444ee418f129b2c238299f49d3264554Jarkko Poyryprivate:
693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	tcu::Vector<T, Size>*			m_array;
703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
723c827367444ee418f129b2c238299f49d3264554Jarkko Poyrytemplate<typename T>	T			randomScalar	(de::Random& rnd, T minValue, T maxValue);
733c827367444ee418f129b2c238299f49d3264554Jarkko Poyrytemplate<> inline		float		randomScalar	(de::Random& rnd, float minValue, float maxValue)		{ return rnd.getFloat(minValue, maxValue);	}
743c827367444ee418f129b2c238299f49d3264554Jarkko Poyrytemplate<> inline		deInt32		randomScalar	(de::Random& rnd, deInt32 minValue, deInt32 maxValue)	{ return rnd.getInt(minValue, maxValue);	}
753c827367444ee418f129b2c238299f49d3264554Jarkko Poyrytemplate<> inline		deUint32	randomScalar	(de::Random& rnd, deUint32 minValue, deUint32 maxValue)	{ return minValue + rnd.getUint32() % (maxValue - minValue + 1); }
763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
773c827367444ee418f129b2c238299f49d3264554Jarkko Poyrytemplate<typename T, int Size>
783c827367444ee418f129b2c238299f49d3264554Jarkko Poyryinline tcu::Vector<T, Size> randomVector (de::Random& rnd, const tcu::Vector<T, Size>& minValue, const tcu::Vector<T, Size>& maxValue)
793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	tcu::Vector<T, Size> res;
813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	for (int ndx = 0; ndx < Size; ndx++)
823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		res[ndx] = randomScalar<T>(rnd, minValue[ndx], maxValue[ndx]);
833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return res;
843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
863c827367444ee418f129b2c238299f49d3264554Jarkko Poyrytemplate<typename T, int Size>
873c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic void fillRandomVectors (de::Random& rnd, const tcu::Vector<T, Size>& minValue, const tcu::Vector<T, Size>& maxValue, void* dst, int numValues, int offset = 0)
883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	VecArrayAccess<T, Size> access(dst);
903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	for (int ndx = 0; ndx < numValues; ndx++)
913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		access[offset + ndx] = randomVector<T, Size>(rnd, minValue, maxValue);
923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
943c827367444ee418f129b2c238299f49d3264554Jarkko Poyrytemplate<typename T>
953c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic void fillRandomScalars (de::Random& rnd, T minValue, T maxValue, void* dst, int numValues, int offset = 0)
963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	T* typedPtr = (T*)dst;
983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	for (int ndx = 0; ndx < numValues; ndx++)
993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		typedPtr[offset + ndx] = randomScalar<T>(rnd, minValue, maxValue);
1003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
1013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1023c827367444ee418f129b2c238299f49d3264554Jarkko Poyryinline int numBitsLostInOp (float input, float output)
1033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
1043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const int	inExp		= tcu::Float32(input).exponent();
1053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const int	outExp		= tcu::Float32(output).exponent();
1063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return de::max(0, inExp-outExp); // Lost due to mantissa shift.
1083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
1093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1103c827367444ee418f129b2c238299f49d3264554Jarkko Poyryinline deUint32 getUlpDiff (float a, float b)
1113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
1123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deUint32	aBits	= tcu::Float32(a).bits();
1133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deUint32	bBits	= tcu::Float32(b).bits();
1143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return aBits > bBits ? aBits - bBits : bBits - aBits;
1153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
1163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1173c827367444ee418f129b2c238299f49d3264554Jarkko Poyryinline deUint32 getUlpDiffIgnoreZeroSign (float a, float b)
1183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
1193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (tcu::Float32(a).isZero())
1203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return getUlpDiff(tcu::Float32::construct(tcu::Float32(b).sign(), 0, 0).asFloat(), b);
1213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	else if (tcu::Float32(b).isZero())
1223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return getUlpDiff(a, tcu::Float32::construct(tcu::Float32(a).sign(), 0, 0).asFloat());
1233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	else
1243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return getUlpDiff(a, b);
1253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
1263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1273c827367444ee418f129b2c238299f49d3264554Jarkko Poyryinline bool supportsSignedZero (glu::Precision precision)
1283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
1293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// \note GLSL ES 3.1 doesn't really require support for -0, but we require it for highp
1303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	//		 as it is very widely supported.
1313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return precision == glu::PRECISION_HIGHP;
1323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
1333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1343c827367444ee418f129b2c238299f49d3264554Jarkko Poyryinline float getEpsFromMaxUlpDiff (float value, deUint32 ulpDiff)
1353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
1363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const int exp = tcu::Float32(value).exponent();
1373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return tcu::Float32::construct(+1, exp, (1u<<23) | ulpDiff).asFloat() - tcu::Float32::construct(+1, exp, 1u<<23).asFloat();
1383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
1393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1403c827367444ee418f129b2c238299f49d3264554Jarkko Poyryinline deUint32 getMaxUlpDiffFromBits (int numAccurateBits)
1413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
1423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const int		numGarbageBits	= 23-numAccurateBits;
1433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deUint32	mask			= (1u<<numGarbageBits)-1u;
1443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return mask;
1463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
1473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1483c827367444ee418f129b2c238299f49d3264554Jarkko Poyryinline float getEpsFromBits (float value, int numAccurateBits)
1493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
1503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return getEpsFromMaxUlpDiff(value, getMaxUlpDiffFromBits(numAccurateBits));
1513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
1523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1533c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic int getMinMantissaBits (glu::Precision precision)
1543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
1553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const int bits[] =
1563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
1573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		7,		// lowp
1583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		10,		// mediump
1593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		23		// highp
1603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	};
1613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(bits) == glu::PRECISION_LAST);
1623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(de::inBounds<int>(precision, 0, DE_LENGTH_OF_ARRAY(bits)));
1633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return bits[precision];
1643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
1653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
166ade588f3b2b1b6d007b9681e95434dc4a4bd46caJarkko Pöyrystatic int getMaxNormalizedValueExponent (glu::Precision precision)
167ade588f3b2b1b6d007b9681e95434dc4a4bd46caJarkko Pöyry{
168ade588f3b2b1b6d007b9681e95434dc4a4bd46caJarkko Pöyry	const int exponent[] =
169ade588f3b2b1b6d007b9681e95434dc4a4bd46caJarkko Pöyry	{
170ade588f3b2b1b6d007b9681e95434dc4a4bd46caJarkko Pöyry		0,		// lowp
171ade588f3b2b1b6d007b9681e95434dc4a4bd46caJarkko Pöyry		13,		// mediump
172ade588f3b2b1b6d007b9681e95434dc4a4bd46caJarkko Pöyry		127		// highp
173ade588f3b2b1b6d007b9681e95434dc4a4bd46caJarkko Pöyry	};
174ade588f3b2b1b6d007b9681e95434dc4a4bd46caJarkko Pöyry	DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(exponent) == glu::PRECISION_LAST);
175ade588f3b2b1b6d007b9681e95434dc4a4bd46caJarkko Pöyry	DE_ASSERT(de::inBounds<int>(precision, 0, DE_LENGTH_OF_ARRAY(exponent)));
176ade588f3b2b1b6d007b9681e95434dc4a4bd46caJarkko Pöyry	return exponent[precision];
177ade588f3b2b1b6d007b9681e95434dc4a4bd46caJarkko Pöyry}
178ade588f3b2b1b6d007b9681e95434dc4a4bd46caJarkko Pöyry
179ade588f3b2b1b6d007b9681e95434dc4a4bd46caJarkko Pöyrystatic int getMinNormalizedValueExponent (glu::Precision precision)
180ade588f3b2b1b6d007b9681e95434dc4a4bd46caJarkko Pöyry{
181ade588f3b2b1b6d007b9681e95434dc4a4bd46caJarkko Pöyry	const int exponent[] =
182ade588f3b2b1b6d007b9681e95434dc4a4bd46caJarkko Pöyry	{
183ade588f3b2b1b6d007b9681e95434dc4a4bd46caJarkko Pöyry		-7,		// lowp
184ade588f3b2b1b6d007b9681e95434dc4a4bd46caJarkko Pöyry		-13,	// mediump
185ade588f3b2b1b6d007b9681e95434dc4a4bd46caJarkko Pöyry		-126	// highp
186ade588f3b2b1b6d007b9681e95434dc4a4bd46caJarkko Pöyry	};
187ade588f3b2b1b6d007b9681e95434dc4a4bd46caJarkko Pöyry	DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(exponent) == glu::PRECISION_LAST);
188ade588f3b2b1b6d007b9681e95434dc4a4bd46caJarkko Pöyry	DE_ASSERT(de::inBounds<int>(precision, 0, DE_LENGTH_OF_ARRAY(exponent)));
189ade588f3b2b1b6d007b9681e95434dc4a4bd46caJarkko Pöyry	return exponent[precision];
190ade588f3b2b1b6d007b9681e95434dc4a4bd46caJarkko Pöyry}
191ade588f3b2b1b6d007b9681e95434dc4a4bd46caJarkko Pöyry
1926c9ec4d03a5a9eb4e7cc7e665181c216fefe49f9Jarkko Pöyrystatic float makeFloatRepresentable (float f, glu::Precision precision)
1936c9ec4d03a5a9eb4e7cc7e665181c216fefe49f9Jarkko Pöyry{
1946c9ec4d03a5a9eb4e7cc7e665181c216fefe49f9Jarkko Pöyry	if (precision == glu::PRECISION_HIGHP)
1956c9ec4d03a5a9eb4e7cc7e665181c216fefe49f9Jarkko Pöyry	{
1966c9ec4d03a5a9eb4e7cc7e665181c216fefe49f9Jarkko Pöyry		// \note: assuming f is not extended-precision
1976c9ec4d03a5a9eb4e7cc7e665181c216fefe49f9Jarkko Pöyry		return f;
1986c9ec4d03a5a9eb4e7cc7e665181c216fefe49f9Jarkko Pöyry	}
1996c9ec4d03a5a9eb4e7cc7e665181c216fefe49f9Jarkko Pöyry	else
2006c9ec4d03a5a9eb4e7cc7e665181c216fefe49f9Jarkko Pöyry	{
2016c9ec4d03a5a9eb4e7cc7e665181c216fefe49f9Jarkko Pöyry		const int			numMantissaBits				= getMinMantissaBits(precision);
2026c9ec4d03a5a9eb4e7cc7e665181c216fefe49f9Jarkko Pöyry		const int			maxNormalizedValueExponent	= getMaxNormalizedValueExponent(precision);
2036c9ec4d03a5a9eb4e7cc7e665181c216fefe49f9Jarkko Pöyry		const int			minNormalizedValueExponent	= getMinNormalizedValueExponent(precision);
2046c9ec4d03a5a9eb4e7cc7e665181c216fefe49f9Jarkko Pöyry		const deUint32		representableMantissaMask	= ((deUint32(1) << numMantissaBits) - 1) << (23 - (deUint32)numMantissaBits);
2056c9ec4d03a5a9eb4e7cc7e665181c216fefe49f9Jarkko Pöyry		const float			largestRepresentableValue	= tcu::Float32::constructBits(+1, maxNormalizedValueExponent, ((1u << numMantissaBits) - 1u) << (23u - (deUint32)numMantissaBits)).asFloat();
2066c9ec4d03a5a9eb4e7cc7e665181c216fefe49f9Jarkko Pöyry		const bool			zeroNotRepresentable		= (precision == glu::PRECISION_LOWP);
2076c9ec4d03a5a9eb4e7cc7e665181c216fefe49f9Jarkko Pöyry
2086c9ec4d03a5a9eb4e7cc7e665181c216fefe49f9Jarkko Pöyry		// if zero is not required to be representable, use smallest positive non-subnormal value
2096c9ec4d03a5a9eb4e7cc7e665181c216fefe49f9Jarkko Pöyry		const float			zeroValue					= (zeroNotRepresentable) ? (tcu::Float32::constructBits(+1, minNormalizedValueExponent, 1).asFloat()) : (0.0f);
2106c9ec4d03a5a9eb4e7cc7e665181c216fefe49f9Jarkko Pöyry
2116c9ec4d03a5a9eb4e7cc7e665181c216fefe49f9Jarkko Pöyry		const tcu::Float32	float32Representation		(f);
2126c9ec4d03a5a9eb4e7cc7e665181c216fefe49f9Jarkko Pöyry
2136c9ec4d03a5a9eb4e7cc7e665181c216fefe49f9Jarkko Pöyry		if (float32Representation.exponent() < minNormalizedValueExponent)
2146c9ec4d03a5a9eb4e7cc7e665181c216fefe49f9Jarkko Pöyry		{
2156c9ec4d03a5a9eb4e7cc7e665181c216fefe49f9Jarkko Pöyry			// flush too small values to zero
2166c9ec4d03a5a9eb4e7cc7e665181c216fefe49f9Jarkko Pöyry			return zeroValue;
2176c9ec4d03a5a9eb4e7cc7e665181c216fefe49f9Jarkko Pöyry		}
2186c9ec4d03a5a9eb4e7cc7e665181c216fefe49f9Jarkko Pöyry		else if (float32Representation.exponent() > maxNormalizedValueExponent)
2196c9ec4d03a5a9eb4e7cc7e665181c216fefe49f9Jarkko Pöyry		{
2206c9ec4d03a5a9eb4e7cc7e665181c216fefe49f9Jarkko Pöyry			// clamp too large values
2216c9ec4d03a5a9eb4e7cc7e665181c216fefe49f9Jarkko Pöyry			return (float32Representation.sign() == +1) ? (largestRepresentableValue) : (-largestRepresentableValue);
2226c9ec4d03a5a9eb4e7cc7e665181c216fefe49f9Jarkko Pöyry		}
2236c9ec4d03a5a9eb4e7cc7e665181c216fefe49f9Jarkko Pöyry		else
2246c9ec4d03a5a9eb4e7cc7e665181c216fefe49f9Jarkko Pöyry		{
2256c9ec4d03a5a9eb4e7cc7e665181c216fefe49f9Jarkko Pöyry			// remove unrepresentable mantissa bits
2266c9ec4d03a5a9eb4e7cc7e665181c216fefe49f9Jarkko Pöyry			const tcu::Float32 targetRepresentation(tcu::Float32::constructBits(float32Representation.sign(),
2276c9ec4d03a5a9eb4e7cc7e665181c216fefe49f9Jarkko Pöyry													float32Representation.exponent(),
2286c9ec4d03a5a9eb4e7cc7e665181c216fefe49f9Jarkko Pöyry													float32Representation.mantissaBits() & representableMantissaMask));
2296c9ec4d03a5a9eb4e7cc7e665181c216fefe49f9Jarkko Pöyry
2306c9ec4d03a5a9eb4e7cc7e665181c216fefe49f9Jarkko Pöyry			return targetRepresentation.asFloat();
2316c9ec4d03a5a9eb4e7cc7e665181c216fefe49f9Jarkko Pöyry		}
2326c9ec4d03a5a9eb4e7cc7e665181c216fefe49f9Jarkko Pöyry	}
2336c9ec4d03a5a9eb4e7cc7e665181c216fefe49f9Jarkko Pöyry}
2346c9ec4d03a5a9eb4e7cc7e665181c216fefe49f9Jarkko Pöyry
2353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry// CommonFunctionCase
2363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2373c827367444ee418f129b2c238299f49d3264554Jarkko Poyryclass CommonFunctionCase : public TestCase
2383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
2393c827367444ee418f129b2c238299f49d3264554Jarkko Poyrypublic:
2403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry							CommonFunctionCase		(Context& context, const char* name, const char* description, glu::ShaderType shaderType);
2413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry							~CommonFunctionCase		(void);
2423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	void					init					(void);
2443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	void					deinit					(void);
2453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	IterateResult			iterate					(void);
2463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2473c827367444ee418f129b2c238299f49d3264554Jarkko Poyryprotected:
2483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry							CommonFunctionCase		(const CommonFunctionCase& other);
2493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	CommonFunctionCase&		operator=				(const CommonFunctionCase& other);
2503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	virtual void			getInputValues			(int numValues, void* const* values) const = 0;
2523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	virtual bool			compare					(const void* const* inputs, const void* const* outputs) = 0;
2533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	glu::ShaderType			m_shaderType;
2553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	ShaderSpec				m_spec;
2563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	int						m_numValues;
2573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	std::ostringstream		m_failMsg;				//!< Comparison failure help message.
2593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2603c827367444ee418f129b2c238299f49d3264554Jarkko Poyryprivate:
2613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	ShaderExecutor*			m_executor;
2623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
2633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2643c827367444ee418f129b2c238299f49d3264554Jarkko PoyryCommonFunctionCase::CommonFunctionCase (Context& context, const char* name, const char* description, glu::ShaderType shaderType)
2653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	: TestCase		(context, name, description)
2663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	, m_shaderType	(shaderType)
2673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	, m_numValues	(100)
2683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	, m_executor	(DE_NULL)
2693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
2703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
2713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2723c827367444ee418f129b2c238299f49d3264554Jarkko PoyryCommonFunctionCase::~CommonFunctionCase (void)
2733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
2743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	CommonFunctionCase::deinit();
2753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
2763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2773c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid CommonFunctionCase::init (void)
2783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
2793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(!m_executor);
2803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
281c7dc8067b55f15b156b0add2e22be468ddf5ad20Daniel Andrade Groppe	m_spec.version = contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)) ? glu::GLSL_VERSION_320_ES : glu::GLSL_VERSION_310_ES;
282c7dc8067b55f15b156b0add2e22be468ddf5ad20Daniel Andrade Groppe
2833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	m_executor = createExecutor(m_context.getRenderContext(), m_shaderType, m_spec);
2843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	m_testCtx.getLog() << m_executor;
2853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (!m_executor->isOk())
2873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		throw tcu::TestError("Compile failed");
2883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
2893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2903c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid CommonFunctionCase::deinit (void)
2913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
2923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	delete m_executor;
2933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	m_executor = DE_NULL;
2943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
2953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2963c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic vector<int> getScalarSizes (const vector<Symbol>& symbols)
2973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
2983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	vector<int> sizes(symbols.size());
2993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	for (int ndx = 0; ndx < (int)symbols.size(); ++ndx)
3003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		sizes[ndx] = symbols[ndx].varType.getScalarSize();
3013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return sizes;
3023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
3033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3043c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic int computeTotalScalarSize (const vector<Symbol>& symbols)
3053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
3063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	int totalSize = 0;
3073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	for (vector<Symbol>::const_iterator sym = symbols.begin(); sym != symbols.end(); ++sym)
3083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		totalSize += sym->varType.getScalarSize();
3093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return totalSize;
3103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
3113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3123c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic vector<void*> getInputOutputPointers (const vector<Symbol>& symbols, vector<deUint32>& data, const int numValues)
3133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
3143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	vector<void*>	pointers		(symbols.size());
3153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	int				curScalarOffset	= 0;
3163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	for (int varNdx = 0; varNdx < (int)symbols.size(); ++varNdx)
3183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
3193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const Symbol&	var				= symbols[varNdx];
3203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int		scalarSize		= var.varType.getScalarSize();
3213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Uses planar layout as input/output specs do not support strides.
3233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		pointers[varNdx] = &data[curScalarOffset];
3243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		curScalarOffset += scalarSize*numValues;
3253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
3263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(curScalarOffset == (int)data.size());
3283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return pointers;
3303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
3313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry// \todo [2013-08-08 pyry] Make generic utility and move to glu?
3333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3343c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystruct HexFloat
3353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
3363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const float value;
3373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	HexFloat (const float value_) : value(value_) {}
3383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
3393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3403c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystd::ostream& operator<< (std::ostream& str, const HexFloat& v)
3413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
3423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return str << v.value << " / " << tcu::toHex(tcu::Float32(v.value).bits());
3433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
3443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3453c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystruct HexBool
3463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
3473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const deUint32 value;
3483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	HexBool (const deUint32 value_) : value(value_) {}
3493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
3503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3513c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystd::ostream& operator<< (std::ostream& str, const HexBool& v)
3523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
3533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return str << (v.value ? "true" : "false") << " / " << tcu::toHex(v.value);
3543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
3553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3563c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystruct VarValue
3573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
3583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const glu::VarType&	type;
3593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const void*			value;
3603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	VarValue (const glu::VarType& type_, const void* value_) : type(type_), value(value_) {}
3623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
3633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3643c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystd::ostream& operator<< (std::ostream& str, const VarValue& varValue)
3653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
3663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(varValue.type.isBasicType());
3673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const glu::DataType		basicType		= varValue.type.getBasicType();
3693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const glu::DataType		scalarType		= glu::getDataTypeScalarType(basicType);
3703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const int				numComponents	= glu::getDataTypeScalarSize(basicType);
3713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (numComponents > 1)
3733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		str << glu::getDataTypeName(basicType) << "(";
3743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	for (int compNdx = 0; compNdx < numComponents; compNdx++)
3763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
3773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (compNdx != 0)
3783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			str << ", ";
3793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		switch (scalarType)
3813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
3823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			case glu::TYPE_FLOAT:	str << HexFloat(((const float*)varValue.value)[compNdx]);			break;
3833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			case glu::TYPE_INT:		str << ((const deInt32*)varValue.value)[compNdx];					break;
3843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			case glu::TYPE_UINT:	str << tcu::toHex(((const deUint32*)varValue.value)[compNdx]);		break;
3853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			case glu::TYPE_BOOL:	str << HexBool(((const deUint32*)varValue.value)[compNdx]);			break;
3863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			default:
3883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				DE_ASSERT(false);
3893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
3903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
3913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (numComponents > 1)
3933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		str << ")";
3943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return str;
3963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
3973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
3983c827367444ee418f129b2c238299f49d3264554Jarkko PoyryCommonFunctionCase::IterateResult CommonFunctionCase::iterate (void)
3993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
4003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const int				numInputScalars			= computeTotalScalarSize(m_spec.inputs);
4013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const int				numOutputScalars		= computeTotalScalarSize(m_spec.outputs);
4023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	vector<deUint32>		inputData				(numInputScalars * m_numValues);
4033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	vector<deUint32>		outputData				(numOutputScalars * m_numValues);
4043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const vector<void*>		inputPointers			= getInputOutputPointers(m_spec.inputs, inputData, m_numValues);
4053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const vector<void*>		outputPointers			= getInputOutputPointers(m_spec.outputs, outputData, m_numValues);
4063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Initialize input data.
4083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	getInputValues(m_numValues, &inputPointers[0]);
4093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Execute shader.
4113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	m_executor->useProgram();
4123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	m_executor->execute(m_numValues, &inputPointers[0], &outputPointers[0]);
4133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// Compare results.
4153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
4163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const vector<int>		inScalarSizes		= getScalarSizes(m_spec.inputs);
4173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const vector<int>		outScalarSizes		= getScalarSizes(m_spec.outputs);
4183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		vector<void*>			curInputPtr			(inputPointers.size());
4193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		vector<void*>			curOutputPtr		(outputPointers.size());
4203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		int						numFailed			= 0;
4213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int valNdx = 0; valNdx < m_numValues; valNdx++)
4233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
4243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			// Set up pointers for comparison.
4253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int inNdx = 0; inNdx < (int)curInputPtr.size(); ++inNdx)
4263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				curInputPtr[inNdx] = (deUint32*)inputPointers[inNdx] + inScalarSizes[inNdx]*valNdx;
4273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int outNdx = 0; outNdx < (int)curOutputPtr.size(); ++outNdx)
4293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				curOutputPtr[outNdx] = (deUint32*)outputPointers[outNdx] + outScalarSizes[outNdx]*valNdx;
4303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			if (!compare(&curInputPtr[0], &curOutputPtr[0]))
4323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
4333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				// \todo [2013-08-08 pyry] We probably want to log reference value as well?
4343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				m_testCtx.getLog() << TestLog::Message << "ERROR: comparison failed for value " << valNdx << ":\n  " << m_failMsg.str() << TestLog::EndMessage;
4363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				m_testCtx.getLog() << TestLog::Message << "  inputs:" << TestLog::EndMessage;
4383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				for (int inNdx = 0; inNdx < (int)curInputPtr.size(); inNdx++)
4393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					m_testCtx.getLog() << TestLog::Message << "    " << m_spec.inputs[inNdx].name << " = "
4403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														   << VarValue(m_spec.inputs[inNdx].varType, curInputPtr[inNdx])
4413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry									   << TestLog::EndMessage;
4423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				m_testCtx.getLog() << TestLog::Message << "  outputs:" << TestLog::EndMessage;
4443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				for (int outNdx = 0; outNdx < (int)curOutputPtr.size(); outNdx++)
4453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					m_testCtx.getLog() << TestLog::Message << "    " << m_spec.outputs[outNdx].name << " = "
4463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry														   << VarValue(m_spec.outputs[outNdx].varType, curOutputPtr[outNdx])
4473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry									   << TestLog::EndMessage;
4483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				m_failMsg.str("");
4503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				m_failMsg.clear();
4513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				numFailed += 1;
4523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
4533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
4543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_testCtx.getLog() << TestLog::Message << (m_numValues - numFailed) << " / " << m_numValues << " values passed" << TestLog::EndMessage;
4563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS	: QP_TEST_RESULT_FAIL,
4583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry								numFailed == 0 ? "Pass"					: "Result comparison failed");
4593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
4603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return STOP;
4623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
4633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4643c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic const char* getPrecisionPostfix (glu::Precision precision)
4653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
4663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	static const char* s_postfix[] =
4673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
4683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		"_lowp",
4693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		"_mediump",
4703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		"_highp"
4713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	};
4723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_postfix) == glu::PRECISION_LAST);
4733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(de::inBounds<int>(precision, 0, DE_LENGTH_OF_ARRAY(s_postfix)));
4743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return s_postfix[precision];
4753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
4763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4773c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic const char* getShaderTypePostfix (glu::ShaderType shaderType)
4783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
4793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	static const char* s_postfix[] =
4803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
4813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		"_vertex",
4823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		"_fragment",
4833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		"_geometry",
4843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		"_tess_control",
4853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		"_tess_eval",
4863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		"_compute"
4873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	};
4883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	DE_ASSERT(de::inBounds<int>(shaderType, 0, DE_LENGTH_OF_ARRAY(s_postfix)));
4893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return s_postfix[shaderType];
4903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
4913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4923c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic std::string getCommonFuncCaseName (glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
4933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
4943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return string(glu::getDataTypeName(baseType)) + getPrecisionPostfix(precision) + getShaderTypePostfix(shaderType);
4953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
4963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
4973c827367444ee418f129b2c238299f49d3264554Jarkko Poyryclass AbsCase : public CommonFunctionCase
4983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
4993c827367444ee418f129b2c238299f49d3264554Jarkko Poyrypublic:
5003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	AbsCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
5013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		: CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "abs", shaderType)
5023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
5033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
5043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision)));
5053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_spec.source = "out0 = abs(in0);";
5063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
5073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	void getInputValues (int numValues, void* const* values) const
5093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
5103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const Vec2 floatRanges[] =
5113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
5123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			Vec2(-2.0f,		2.0f),	// lowp
5133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			Vec2(-1e3f,		1e3f),	// mediump
5143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			Vec2(-1e7f,		1e7f)	// highp
5153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		};
5163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const IVec2 intRanges[] =
5173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
5183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			IVec2(-(1<<7)+1,	(1<<7)-1),
5193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			IVec2(-(1<<15)+1,	(1<<15)-1),
5203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			IVec2(0x80000001,	0x7fffffff)
5213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		};
5223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		de::Random				rnd			(deStringHash(getName()) ^ 0x235facu);
5243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::DataType		type		= m_spec.inputs[0].varType.getBasicType();
5253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::Precision	precision	= m_spec.inputs[0].varType.getPrecision();
5263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int				scalarSize	= glu::getDataTypeScalarSize(type);
5273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (glu::isDataTypeFloatOrVec(type))
5293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			fillRandomScalars(rnd, floatRanges[precision].x(), floatRanges[precision].y(), values[0], numValues*scalarSize);
5303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		else
5313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			fillRandomScalars(rnd, intRanges[precision].x(), intRanges[precision].y(), values[0], numValues*scalarSize);
5323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
5333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	bool compare (const void* const* inputs, const void* const* outputs)
5353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
5363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
5373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
5383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int				scalarSize		= glu::getDataTypeScalarSize(type);
5393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (glu::isDataTypeFloatOrVec(type))
5413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
5423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const int		mantissaBits	= getMinMantissaBits(precision);
5433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const deUint32	maxUlpDiff		= (1u<<(23-mantissaBits))-1u;
5443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
5463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
5473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const float		in0			= ((const float*)inputs[0])[compNdx];
5483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const float		out0		= ((const float*)outputs[0])[compNdx];
5493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const float		ref0		= de::abs(in0);
5503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const deUint32	ulpDiff0	= getUlpDiff(out0, ref0);
5513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				if (ulpDiff0 > maxUlpDiff)
5533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
5543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref0) << " with ULP threshold " << maxUlpDiff << ", got ULP diff " << ulpDiff0;
5553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					return false;
5563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
5573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
5583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
5593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		else
5603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
5613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
5623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
5633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const int	in0		= ((const int*)inputs[0])[compNdx];
5643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const int	out0	= ((const int*)outputs[0])[compNdx];
5653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const int	ref0	= de::abs(in0);
5663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				if (out0 != ref0)
5683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
5693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					m_failMsg << "Expected [" << compNdx << "] = " << ref0;
5703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					return false;
5713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
5723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
5733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
5743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return true;
5763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
5773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
5783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5793c827367444ee418f129b2c238299f49d3264554Jarkko Poyryclass SignCase : public CommonFunctionCase
5803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
5813c827367444ee418f129b2c238299f49d3264554Jarkko Poyrypublic:
5823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	SignCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
5833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		: CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "sign", shaderType)
5843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
5853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
5863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision)));
5873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_spec.source = "out0 = sign(in0);";
5883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
5893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
5903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	void getInputValues (int numValues, void* const* values) const
5913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
5923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const Vec2 floatRanges[] =
5933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
5943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			Vec2(-2.0f,		2.0f),	// lowp
5953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			Vec2(-1e4f,		1e4f),	// mediump	- note: may end up as inf
5963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			Vec2(-1e8f,		1e8f)	// highp	- note: may end up as inf
5973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		};
5983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const IVec2 intRanges[] =
5993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
6003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			IVec2(-(1<<7),		(1<<7)-1),
6013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			IVec2(-(1<<15),		(1<<15)-1),
6023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			IVec2(0x80000000,	0x7fffffff)
6033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		};
6043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		de::Random				rnd			(deStringHash(getName()) ^ 0x324u);
6063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::DataType		type		= m_spec.inputs[0].varType.getBasicType();
6073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::Precision	precision	= m_spec.inputs[0].varType.getPrecision();
6083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int				scalarSize	= glu::getDataTypeScalarSize(type);
6093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (glu::isDataTypeFloatOrVec(type))
6113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
6123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			// Special cases.
613b55a172c47932197abc5e18950a70c938ef302c0Pyry Haulos			std::fill((float*)values[0],				(float*)values[0] + scalarSize,		+1.0f);
614b55a172c47932197abc5e18950a70c938ef302c0Pyry Haulos			std::fill((float*)values[0] + scalarSize*1,	(float*)values[0] + scalarSize*2,	-1.0f);
615b55a172c47932197abc5e18950a70c938ef302c0Pyry Haulos			std::fill((float*)values[0] + scalarSize*2,	(float*)values[0] + scalarSize*3,	0.0f);
6163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			fillRandomScalars(rnd, floatRanges[precision].x(), floatRanges[precision].y(), (float*)values[0] + scalarSize*3, (numValues-3)*scalarSize);
6173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
6183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		else
6193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
620b55a172c47932197abc5e18950a70c938ef302c0Pyry Haulos			std::fill((int*)values[0],					(int*)values[0] + scalarSize,		+1);
621b55a172c47932197abc5e18950a70c938ef302c0Pyry Haulos			std::fill((int*)values[0] + scalarSize*1,	(int*)values[0] + scalarSize*2,		-1);
622b55a172c47932197abc5e18950a70c938ef302c0Pyry Haulos			std::fill((int*)values[0] + scalarSize*2,	(int*)values[0] + scalarSize*3,		0);
6233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			fillRandomScalars(rnd, intRanges[precision].x(), intRanges[precision].y(), (int*)values[0] + scalarSize*3, (numValues-3)*scalarSize);
6243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
6253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
6263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	bool compare (const void* const* inputs, const void* const* outputs)
6283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
6293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
6303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
6313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int				scalarSize		= glu::getDataTypeScalarSize(type);
6323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (glu::isDataTypeFloatOrVec(type))
6343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
6353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			// Both highp and mediump should be able to represent -1, 0, and +1 exactly
6363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const deUint32 maxUlpDiff = precision == glu::PRECISION_LOWP ? getMaxUlpDiffFromBits(getMinMantissaBits(precision)) : 0;
6373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
6393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
6403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const float		in0			= ((const float*)inputs[0])[compNdx];
6413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const float		out0		= ((const float*)outputs[0])[compNdx];
6423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const float		ref0		= in0 < 0.0f ? -1.0f :
6433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry											  in0 > 0.0f ? +1.0f : 0.0f;
6443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const deUint32	ulpDiff0	= getUlpDiff(out0, ref0);
6453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				if (ulpDiff0 > maxUlpDiff)
6473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
6483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref0) << " with ULP threshold " << maxUlpDiff << ", got ULP diff " << ulpDiff0;
6493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					return false;
6503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
6513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
6523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
6533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		else
6543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
6553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
6563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
6573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const int	in0		= ((const int*)inputs[0])[compNdx];
6583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const int	out0	= ((const int*)outputs[0])[compNdx];
6593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const int	ref0	= in0 < 0 ? -1 :
6603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry									  in0 > 0 ? +1 : 0;
6613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				if (out0 != ref0)
6633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
6643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					m_failMsg << "Expected [" << compNdx << "] = " << ref0;
6653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					return false;
6663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
6673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
6683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
6693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return true;
6713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
6723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
6733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6743c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic float roundEven (float v)
6753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
6763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const float		q			= deFloatFrac(v);
6773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const int		truncated	= int(v-q);
6783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const int		rounded		= (q > 0.5f)							? (truncated + 1) :	// Rounded up
6793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry									(q == 0.5f && (truncated % 2 != 0))	? (truncated + 1) :	// Round to nearest even at 0.5
6803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry									truncated;												// Rounded down
6813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	return float(rounded);
6833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
6843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6853c827367444ee418f129b2c238299f49d3264554Jarkko Poyryclass RoundEvenCase : public CommonFunctionCase
6863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
6873c827367444ee418f129b2c238299f49d3264554Jarkko Poyrypublic:
6883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	RoundEvenCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
6893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		: CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "roundEven", shaderType)
6903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
6913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
6923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision)));
6933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_spec.source = "out0 = roundEven(in0);";
6943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
6953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
6963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	void getInputValues (int numValues, void* const* values) const
6973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
6983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const Vec2 ranges[] =
6993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
7003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			Vec2(-2.0f,		2.0f),	// lowp
7013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			Vec2(-1e3f,		1e3f),	// mediump
7023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			Vec2(-1e7f,		1e7f)	// highp
7033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		};
7043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		de::Random				rnd				(deStringHash(getName()) ^ 0xac23fu);
7063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
7073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
7083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int				scalarSize		= glu::getDataTypeScalarSize(type);
7093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		int						numSpecialCases	= 0;
7103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Special cases.
7123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (precision != glu::PRECISION_LOWP)
7133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
7143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			DE_ASSERT(numValues >= 20);
7153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int ndx = 0; ndx < 20; ndx++)
7163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
7173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const float v = de::clamp(float(ndx) - 10.5f, ranges[precision].x(), ranges[precision].y());
7183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				std::fill((float*)values[0], (float*)values[0] + scalarSize, v);
7193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				numSpecialCases += 1;
7203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
7213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
7223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Random cases.
7243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), (float*)values[0] + numSpecialCases*scalarSize, (numValues-numSpecialCases)*scalarSize);
7253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// If precision is mediump, make sure values can be represented in fp16 exactly
7273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (precision == glu::PRECISION_MEDIUMP)
7283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
7293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int ndx = 0; ndx < numValues*scalarSize; ndx++)
7303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				((float*)values[0])[ndx] = tcu::Float16(((float*)values[0])[ndx]).asFloat();
7313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
7323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
7333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	bool compare (const void* const* inputs, const void* const* outputs)
7353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
7363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
7373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
7383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const bool				hasSignedZero	= supportsSignedZero(precision);
7393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int				scalarSize		= glu::getDataTypeScalarSize(type);
7403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (precision == glu::PRECISION_HIGHP || precision == glu::PRECISION_MEDIUMP)
7423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
7433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			// Require exact rounding result.
7443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
7453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
7463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const float		in0			= ((const float*)inputs[0])[compNdx];
7473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const float		out0		= ((const float*)outputs[0])[compNdx];
7483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const float		ref			= roundEven(in0);
7493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const deUint32	ulpDiff		= hasSignedZero ? getUlpDiff(out0, ref) : getUlpDiffIgnoreZeroSign(out0, ref);
7513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				if (ulpDiff > 0)
7533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
7543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref) << ", got ULP diff " << tcu::toHex(ulpDiff);
7553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					return false;
7563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
7573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
7583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
7593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		else
7603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
7613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const int		mantissaBits	= getMinMantissaBits(precision);
7623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const deUint32	maxUlpDiff		= getMaxUlpDiffFromBits(mantissaBits);	// ULP diff for rounded integer value.
7633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const float		eps				= getEpsFromBits(1.0f, mantissaBits);	// epsilon for rounding bounds
7643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
7663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
7673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const float		in0			= ((const float*)inputs[0])[compNdx];
7683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const float		out0		= ((const float*)outputs[0])[compNdx];
7693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const int		minRes		= int(roundEven(in0-eps));
7703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const int		maxRes		= int(roundEven(in0+eps));
7713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				bool			anyOk		= false;
7723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				for (int roundedVal = minRes; roundedVal <= maxRes; roundedVal++)
7743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
7753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					const deUint32 ulpDiff = getUlpDiffIgnoreZeroSign(out0, float(roundedVal));
7763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					if (ulpDiff <= maxUlpDiff)
7783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					{
7793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						anyOk = true;
7803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						break;
7813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					}
7823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
7833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				if (!anyOk)
7853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
7863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					m_failMsg << "Expected [" << compNdx << "] = [" << minRes << ", " << maxRes << "] with ULP threshold " << tcu::toHex(maxUlpDiff);
7873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					return false;
7883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
7893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
7903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
7913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return true;
7933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
7943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
7953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
7963c827367444ee418f129b2c238299f49d3264554Jarkko Poyryclass ModfCase : public CommonFunctionCase
7973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
7983c827367444ee418f129b2c238299f49d3264554Jarkko Poyrypublic:
7993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	ModfCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
8003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		: CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "modf", shaderType)
8013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
8023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
8033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision)));
8043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_spec.outputs.push_back(Symbol("out1", glu::VarType(baseType, precision)));
8053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_spec.source = "out0 = modf(in0, out1);";
8063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
8073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	void getInputValues (int numValues, void* const* values) const
8093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
8103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const Vec2 ranges[] =
8113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
8123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			Vec2(-2.0f,		2.0f),	// lowp
8133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			Vec2(-1e3f,		1e3f),	// mediump
8143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			Vec2(-1e7f,		1e7f)	// highp
8153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		};
8163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		de::Random				rnd			(deStringHash(getName()) ^ 0xac23fu);
8183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::DataType		type		= m_spec.inputs[0].varType.getBasicType();
8193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::Precision	precision	= m_spec.inputs[0].varType.getPrecision();
8203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int				scalarSize	= glu::getDataTypeScalarSize(type);
8213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), values[0], numValues*scalarSize);
8233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
8243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	bool compare (const void* const* inputs, const void* const* outputs)
8263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
8273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
8283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
8293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const bool				hasZeroSign		= supportsSignedZero(precision);
8303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int				scalarSize		= glu::getDataTypeScalarSize(type);
8313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int				mantissaBits	= getMinMantissaBits(precision);
8333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int compNdx = 0; compNdx < scalarSize; compNdx++)
8353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
8363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const float		in0			= ((const float*)inputs[0])[compNdx];
8373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const float		out0		= ((const float*)outputs[0])[compNdx];
8383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const float		out1		= ((const float*)outputs[1])[compNdx];
8393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const float		refOut1		= float(int(in0));
8413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const float		refOut0		= in0 - refOut1;
8423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const int		bitsLost	= precision != glu::PRECISION_HIGHP ? numBitsLostInOp(in0, refOut0) : 0;
8443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const deUint32	maxUlpDiff	= getMaxUlpDiffFromBits(de::max(mantissaBits - bitsLost, 0));
8453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const float		resSum		= out0 + out1;
8473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const deUint32	ulpDiff		= hasZeroSign ? getUlpDiff(resSum, in0) : getUlpDiffIgnoreZeroSign(resSum, in0);
8493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			if (ulpDiff > maxUlpDiff)
8513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
8523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				m_failMsg << "Expected [" << compNdx << "] = (" << HexFloat(refOut0) << ") + (" << HexFloat(refOut1) << ") = " << HexFloat(in0) << " with ULP threshold "
8533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry							<< tcu::toHex(maxUlpDiff) << ", got ULP diff " << tcu::toHex(ulpDiff);
8543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				return false;
8553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
8563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
8573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return true;
8593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
8603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
8613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8623c827367444ee418f129b2c238299f49d3264554Jarkko Poyryclass IsnanCase : public CommonFunctionCase
8633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
8643c827367444ee418f129b2c238299f49d3264554Jarkko Poyrypublic:
8653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	IsnanCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
8663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		: CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "isnan", shaderType)
8673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
8683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		DE_ASSERT(glu::isDataTypeFloatOrVec(baseType));
8693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int			vecSize		= glu::getDataTypeScalarSize(baseType);
8713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::DataType	boolType	= vecSize > 1 ? glu::getDataTypeBoolVec(vecSize) : glu::TYPE_BOOL;
8723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
8743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_spec.outputs.push_back(Symbol("out0", glu::VarType(boolType, glu::PRECISION_LAST)));
8753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_spec.source = "out0 = isnan(in0);";
8763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
8773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	void getInputValues (int numValues, void* const* values) const
8793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
8803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		de::Random				rnd				(deStringHash(getName()) ^ 0xc2a39fu);
8813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
8823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
8833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int				scalarSize		= glu::getDataTypeScalarSize(type);
8843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int				mantissaBits	= getMinMantissaBits(precision);
8853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const deUint32			mantissaMask	= ~getMaxUlpDiffFromBits(mantissaBits) & ((1u<<23)-1u);
8863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int valNdx = 0; valNdx < numValues*scalarSize; valNdx++)
8883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
8893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const bool		isNan		= rnd.getFloat() > 0.3f;
8903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const bool		isInf		= !isNan && rnd.getFloat() > 0.4f;
8913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const deUint32	mantissa	= !isInf ? ((1u<<22) | (rnd.getUint32() & mantissaMask)) : 0;
8923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const deUint32	exp			= !isNan && !isInf ? (rnd.getUint32() & 0x7fu) : 0xffu;
8933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const deUint32	sign		= rnd.getUint32() & 0x1u;
8943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const deUint32	value		= (sign << 31) | (exp << 23) | mantissa;
8953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			DE_ASSERT(tcu::Float32(value).isInf() == isInf && tcu::Float32(value).isNaN() == isNan);
8973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
8983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			((deUint32*)values[0])[valNdx] = value;
8993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
9003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
9013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	bool compare (const void* const* inputs, const void* const* outputs)
9033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
9043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
9053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
9063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int				scalarSize		= glu::getDataTypeScalarSize(type);
9073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (precision == glu::PRECISION_HIGHP)
9093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
9103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			// Only highp is required to support inf/nan
9113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
9123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
9133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const float		in0		= ((const float*)inputs[0])[compNdx];
9148852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry				const bool		out0	= ((const deUint32*)outputs[0])[compNdx] != 0;
9158852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry				const bool		ref		= tcu::Float32(in0).isNaN();
9163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				if (out0 != ref)
9183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
9198852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry					m_failMsg << "Expected [" << compNdx << "] = " << (ref ? "true" : "false");
9203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					return false;
9213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
9223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
9233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
9248852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry		else if (precision == glu::PRECISION_MEDIUMP || precision == glu::PRECISION_LOWP)
9253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
9268852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry			// NaN support is optional, check that inputs that are not NaN don't result in true.
9273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
9283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
9298852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry				const float		in0		= ((const float*)inputs[0])[compNdx];
9308852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry				const bool		out0	= ((const deUint32*)outputs[0])[compNdx] != 0;
9318852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry				const bool		ref		= tcu::Float32(in0).isNaN();
9323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9338852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry				if (!ref && out0)
9343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
9358852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry					m_failMsg << "Expected [" << compNdx << "] = " << (ref ? "true" : "false");
9363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					return false;
9373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
9383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
9393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
9403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return true;
9423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
9433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
9443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9453c827367444ee418f129b2c238299f49d3264554Jarkko Poyryclass IsinfCase : public CommonFunctionCase
9463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
9473c827367444ee418f129b2c238299f49d3264554Jarkko Poyrypublic:
9483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	IsinfCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
9493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		: CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "isinf", shaderType)
9503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
9513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		DE_ASSERT(glu::isDataTypeFloatOrVec(baseType));
9523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int			vecSize		= glu::getDataTypeScalarSize(baseType);
9543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::DataType	boolType	= vecSize > 1 ? glu::getDataTypeBoolVec(vecSize) : glu::TYPE_BOOL;
9553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
9573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_spec.outputs.push_back(Symbol("out0", glu::VarType(boolType, glu::PRECISION_LAST)));
9583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_spec.source = "out0 = isinf(in0);";
9593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
9603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	void getInputValues (int numValues, void* const* values) const
9623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
9633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		de::Random				rnd				(deStringHash(getName()) ^ 0xc2a39fu);
9643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
9653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
9663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int				scalarSize		= glu::getDataTypeScalarSize(type);
9673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int				mantissaBits	= getMinMantissaBits(precision);
9683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const deUint32			mantissaMask	= ~getMaxUlpDiffFromBits(mantissaBits) & ((1u<<23)-1u);
9693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int valNdx = 0; valNdx < numValues*scalarSize; valNdx++)
9713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
9723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const bool		isInf		= rnd.getFloat() > 0.3f;
9733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const bool		isNan		= !isInf && rnd.getFloat() > 0.4f;
9743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const deUint32	mantissa	= !isInf ? ((1u<<22) | (rnd.getUint32() & mantissaMask)) : 0;
9753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const deUint32	exp			= !isNan && !isInf ? (rnd.getUint32() & 0x7fu) : 0xffu;
9763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const deUint32	sign		= rnd.getUint32() & 0x1u;
9773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const deUint32	value		= (sign << 31) | (exp << 23) | mantissa;
9783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			DE_ASSERT(tcu::Float32(value).isInf() == isInf && tcu::Float32(value).isNaN() == isNan);
9803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			((deUint32*)values[0])[valNdx] = value;
9823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
9833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
9843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	bool compare (const void* const* inputs, const void* const* outputs)
9863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
9873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
9883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
9893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int				scalarSize		= glu::getDataTypeScalarSize(type);
9903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
9913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (precision == glu::PRECISION_HIGHP)
9923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
9933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			// Only highp is required to support inf/nan
9943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
9953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
9963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const float		in0		= ((const float*)inputs[0])[compNdx];
9978852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry				const bool		out0	= ((const deUint32*)outputs[0])[compNdx] != 0;
9988852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry				const bool		ref		= tcu::Float32(in0).isInf();
9993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				if (out0 != ref)
10013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
10023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					m_failMsg << "Expected [" << compNdx << "] = " << HexBool(ref);
10033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					return false;
10043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
10053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
10063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
10078852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry		else if (precision == glu::PRECISION_MEDIUMP)
10083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
10098852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry			// Inf support is optional, check that inputs that are not Inf in mediump don't result in true.
10103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
10113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
10128852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry				const float		in0		= ((const float*)inputs[0])[compNdx];
10138852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry				const bool		out0	= ((const deUint32*)outputs[0])[compNdx] != 0;
10148852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry				const bool		ref		= tcu::Float16(in0).isInf();
10153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10168852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry				if (!ref && out0)
10173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
10188852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry					m_failMsg << "Expected [" << compNdx << "] = " << (ref ? "true" : "false");
10193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					return false;
10203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
10213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
10223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
10238852c82a1ffa4760985c17cc6875d5d521daf343Jarkko Poyry		// else: no verification can be performed
10243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return true;
10263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
10273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
10283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10293c827367444ee418f129b2c238299f49d3264554Jarkko Poyryclass FloatBitsToUintIntCase : public CommonFunctionCase
10303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
10313c827367444ee418f129b2c238299f49d3264554Jarkko Poyrypublic:
10323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	FloatBitsToUintIntCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType, bool outIsSigned)
10333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		: CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), outIsSigned ? "floatBitsToInt" : "floatBitsToUint", shaderType)
10343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
10353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int			vecSize		= glu::getDataTypeScalarSize(baseType);
10363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::DataType	intType		= outIsSigned ? (vecSize > 1 ? glu::getDataTypeIntVec(vecSize) : glu::TYPE_INT)
10373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry													  : (vecSize > 1 ? glu::getDataTypeUintVec(vecSize) : glu::TYPE_UINT);
10383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
10403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_spec.outputs.push_back(Symbol("out0", glu::VarType(intType, glu::PRECISION_HIGHP)));
10413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_spec.source = outIsSigned ? "out0 = floatBitsToInt(in0);" : "out0 = floatBitsToUint(in0);";
10423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
10433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	void getInputValues (int numValues, void* const* values) const
10453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
10463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const Vec2 ranges[] =
10473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
10483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			Vec2(-2.0f,		2.0f),	// lowp
10493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			Vec2(-1e3f,		1e3f),	// mediump
10503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			Vec2(-1e7f,		1e7f)	// highp
10513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		};
10523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		de::Random				rnd			(deStringHash(getName()) ^ 0x2790au);
10543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::DataType		type		= m_spec.inputs[0].varType.getBasicType();
10553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::Precision	precision	= m_spec.inputs[0].varType.getPrecision();
10563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int				scalarSize	= glu::getDataTypeScalarSize(type);
10573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), values[0], numValues*scalarSize);
10593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
10603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	bool compare (const void* const* inputs, const void* const* outputs)
10623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
10633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
10643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
10653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int				scalarSize		= glu::getDataTypeScalarSize(type);
10663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int				mantissaBits	= getMinMantissaBits(precision);
10683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int				maxUlpDiff		= getMaxUlpDiffFromBits(mantissaBits);
10693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int compNdx = 0; compNdx < scalarSize; compNdx++)
10713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
10723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const float		in0			= ((const float*)inputs[0])[compNdx];
10733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const deUint32	out0		= ((const deUint32*)outputs[0])[compNdx];
10743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const deUint32	refOut0		= tcu::Float32(in0).bits();
10753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const int		ulpDiff		= de::abs((int)out0 - (int)refOut0);
10763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			if (ulpDiff > maxUlpDiff)
10783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
10793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				m_failMsg << "Expected [" << compNdx << "] = " << tcu::toHex(refOut0) << " with threshold "
10803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry							<< tcu::toHex(maxUlpDiff) << ", got diff " << tcu::toHex(ulpDiff);
10813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				return false;
10823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
10833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
10843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return true;
10863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
10873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
10883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10893c827367444ee418f129b2c238299f49d3264554Jarkko Poyryclass FloatBitsToIntCase : public FloatBitsToUintIntCase
10903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
10913c827367444ee418f129b2c238299f49d3264554Jarkko Poyrypublic:
10923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	FloatBitsToIntCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
10933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		: FloatBitsToUintIntCase(context, baseType, precision, shaderType, true)
10943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
10953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
10963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
10973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
10983c827367444ee418f129b2c238299f49d3264554Jarkko Poyryclass FloatBitsToUintCase : public FloatBitsToUintIntCase
10993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
11003c827367444ee418f129b2c238299f49d3264554Jarkko Poyrypublic:
11013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	FloatBitsToUintCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
11023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		: FloatBitsToUintIntCase(context, baseType, precision, shaderType, false)
11033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
11043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
11053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
11063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
11073c827367444ee418f129b2c238299f49d3264554Jarkko Poyryclass BitsToFloatCase : public CommonFunctionCase
11083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
11093c827367444ee418f129b2c238299f49d3264554Jarkko Poyrypublic:
11103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	BitsToFloatCase (Context& context, glu::DataType baseType, glu::ShaderType shaderType)
11113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		: CommonFunctionCase(context, getCommonFuncCaseName(baseType, glu::PRECISION_HIGHP, shaderType).c_str(), glu::isDataTypeIntOrIVec(baseType) ? "intBitsToFloat" : "uintBitsToFloat", shaderType)
11123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
11133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const bool			inIsSigned	= glu::isDataTypeIntOrIVec(baseType);
11143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int			vecSize		= glu::getDataTypeScalarSize(baseType);
11153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::DataType	floatType	= vecSize > 1 ? glu::getDataTypeFloatVec(vecSize) : glu::TYPE_FLOAT;
11163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
11173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, glu::PRECISION_HIGHP)));
11183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_spec.outputs.push_back(Symbol("out0", glu::VarType(floatType, glu::PRECISION_HIGHP)));
11193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_spec.source = inIsSigned ? "out0 = intBitsToFloat(in0);" : "out0 = uintBitsToFloat(in0);";
11203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
11213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
11223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	void getInputValues (int numValues, void* const* values) const
11233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
11243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		de::Random				rnd			(deStringHash(getName()) ^ 0xbbb225u);
11253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::DataType		type		= m_spec.inputs[0].varType.getBasicType();
11263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int				scalarSize	= glu::getDataTypeScalarSize(type);
11273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const Vec2				range		(-1e8f, +1e8f);
11283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
11293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// \note Filled as floats.
11303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		fillRandomScalars(rnd, range.x(), range.y(), values[0], numValues*scalarSize);
11313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
11323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
11333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	bool compare (const void* const* inputs, const void* const* outputs)
11343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
11353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
11363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int				scalarSize		= glu::getDataTypeScalarSize(type);
11378a14bbb74876a4a318d6277a3afeb8d35d682aafPyry Haulos		const deUint32			maxUlpDiff		= 0;
11383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
11393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int compNdx = 0; compNdx < scalarSize; compNdx++)
11403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
11413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const float		in0			= ((const float*)inputs[0])[compNdx];
11423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const float		out0		= ((const float*)outputs[0])[compNdx];
11438a14bbb74876a4a318d6277a3afeb8d35d682aafPyry Haulos			const deUint32	ulpDiff		= getUlpDiff(in0, out0);
11443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
11453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			if (ulpDiff > maxUlpDiff)
11463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
11478a14bbb74876a4a318d6277a3afeb8d35d682aafPyry Haulos				m_failMsg << "Expected [" << compNdx << "] = " << tcu::toHex(tcu::Float32(in0).bits()) << " with ULP threshold "
11483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry							<< tcu::toHex(maxUlpDiff) << ", got ULP diff " << tcu::toHex(ulpDiff);
11493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				return false;
11503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
11513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
11523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
11533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return true;
11543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
11553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
11563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
11573c827367444ee418f129b2c238299f49d3264554Jarkko Poyryclass FloorCase : public CommonFunctionCase
11583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
11593c827367444ee418f129b2c238299f49d3264554Jarkko Poyrypublic:
11603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	FloorCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
11613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		: CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "floor", shaderType)
11623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
11633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
11643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision)));
11653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_spec.source = "out0 = floor(in0);";
11663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
11673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
11683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	void getInputValues (int numValues, void* const* values) const
11693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
11703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const Vec2 ranges[] =
11713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
11723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			Vec2(-2.0f,		2.0f),	// lowp
11733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			Vec2(-1e3f,		1e3f),	// mediump
11743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			Vec2(-1e7f,		1e7f)	// highp
11753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		};
11763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
11773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		de::Random				rnd			(deStringHash(getName()) ^ 0xac23fu);
11783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::DataType		type		= m_spec.inputs[0].varType.getBasicType();
11793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::Precision	precision	= m_spec.inputs[0].varType.getPrecision();
11803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int				scalarSize	= glu::getDataTypeScalarSize(type);
11813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Random cases.
11823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), (float*)values[0], numValues*scalarSize);
11833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
11843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// If precision is mediump, make sure values can be represented in fp16 exactly
11853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (precision == glu::PRECISION_MEDIUMP)
11863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
11873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int ndx = 0; ndx < numValues*scalarSize; ndx++)
11883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				((float*)values[0])[ndx] = tcu::Float16(((float*)values[0])[ndx]).asFloat();
11893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
11903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
11913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
11923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	bool compare (const void* const* inputs, const void* const* outputs)
11933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
11943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
11953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
11963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int				scalarSize		= glu::getDataTypeScalarSize(type);
11973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
11983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (precision == glu::PRECISION_HIGHP || precision == glu::PRECISION_MEDIUMP)
11993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
12003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			// Require exact result.
12013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
12023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
12033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const float		in0			= ((const float*)inputs[0])[compNdx];
12043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const float		out0		= ((const float*)outputs[0])[compNdx];
12053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const float		ref			= deFloatFloor(in0);
12063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
12073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const deUint32	ulpDiff		= getUlpDiff(out0, ref);
12083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
12093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				if (ulpDiff > 0)
12103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
12113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref) << ", got ULP diff " << tcu::toHex(ulpDiff);
12123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					return false;
12133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
12143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
12153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
12163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		else
12173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
12183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const int		mantissaBits	= getMinMantissaBits(precision);
12193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const deUint32	maxUlpDiff		= getMaxUlpDiffFromBits(mantissaBits);	// ULP diff for rounded integer value.
12203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const float		eps				= getEpsFromBits(1.0f, mantissaBits);	// epsilon for rounding bounds
12213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
12223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
12233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
12243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const float		in0			= ((const float*)inputs[0])[compNdx];
12253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const float		out0		= ((const float*)outputs[0])[compNdx];
12263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const int		minRes		= int(deFloatFloor(in0-eps));
12273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const int		maxRes		= int(deFloatFloor(in0+eps));
12283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				bool			anyOk		= false;
12293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
12303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				for (int roundedVal = minRes; roundedVal <= maxRes; roundedVal++)
12313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
12323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					const deUint32 ulpDiff = getUlpDiff(out0, float(roundedVal));
12333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
12343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					if (ulpDiff <= maxUlpDiff)
12353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					{
12363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						anyOk = true;
12373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						break;
12383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					}
12393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
12403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
12413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				if (!anyOk)
12423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
12433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					m_failMsg << "Expected [" << compNdx << "] = [" << minRes << ", " << maxRes << "] with ULP threshold " << tcu::toHex(maxUlpDiff);
12443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					return false;
12453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
12463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
12473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
12483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
12493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return true;
12503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
12513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
12523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
12533c827367444ee418f129b2c238299f49d3264554Jarkko Poyryclass TruncCase : public CommonFunctionCase
12543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
12553c827367444ee418f129b2c238299f49d3264554Jarkko Poyrypublic:
12563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	TruncCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
12573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		: CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "trunc", shaderType)
12583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
12593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
12603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision)));
12613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_spec.source = "out0 = trunc(in0);";
12623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
12633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
12643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	void getInputValues (int numValues, void* const* values) const
12653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
12663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const Vec2 ranges[] =
12673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
12683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			Vec2(-2.0f,		2.0f),	// lowp
12693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			Vec2(-1e3f,		1e3f),	// mediump
12703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			Vec2(-1e7f,		1e7f)	// highp
12713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		};
12723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
12733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		de::Random				rnd				(deStringHash(getName()) ^ 0xac23fu);
12743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
12753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
12763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int				scalarSize		= glu::getDataTypeScalarSize(type);
12773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const float				specialCases[]	= { 0.0f, -0.0f, -0.9f, 0.9f, 1.0f, -1.0f };
12783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int				numSpecialCases	= DE_LENGTH_OF_ARRAY(specialCases);
12793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
12803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Special cases
12813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int caseNdx = 0; caseNdx < numSpecialCases; caseNdx++)
12823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
12833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++)
12843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				((float*)values[0])[caseNdx*scalarSize + scalarNdx] = specialCases[caseNdx];
12853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
12863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
12873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Random cases.
12883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), (float*)values[0] + scalarSize*numSpecialCases, (numValues-numSpecialCases)*scalarSize);
12893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
12903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// If precision is mediump, make sure values can be represented in fp16 exactly
12913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (precision == glu::PRECISION_MEDIUMP)
12923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
12933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int ndx = 0; ndx < numValues*scalarSize; ndx++)
12943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				((float*)values[0])[ndx] = tcu::Float16(((float*)values[0])[ndx]).asFloat();
12953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
12963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
12973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
12983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	bool compare (const void* const* inputs, const void* const* outputs)
12993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
13003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
13013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
13023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int				scalarSize		= glu::getDataTypeScalarSize(type);
13033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
13043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (precision == glu::PRECISION_HIGHP || precision == glu::PRECISION_MEDIUMP)
13053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
13063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			// Require exact result.
13073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
13083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
13093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const float		in0			= ((const float*)inputs[0])[compNdx];
13103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const float		out0		= ((const float*)outputs[0])[compNdx];
13113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const bool		isNeg		= tcu::Float32(in0).sign() < 0;
13123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const float		ref			= isNeg ? (-float(int(-in0))) : float(int(in0));
13133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1314ade588f3b2b1b6d007b9681e95434dc4a4bd46caJarkko Pöyry				// \note: trunc() function definition is a bit broad on negative zeros. Ignore result sign if zero.
1315ade588f3b2b1b6d007b9681e95434dc4a4bd46caJarkko Pöyry				const deUint32	ulpDiff		= getUlpDiffIgnoreZeroSign(out0, ref);
13163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
13173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				if (ulpDiff > 0)
13183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
13193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref) << ", got ULP diff " << tcu::toHex(ulpDiff);
13203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					return false;
13213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
13223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
13233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
13243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		else
13253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
13263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const int		mantissaBits	= getMinMantissaBits(precision);
13273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const deUint32	maxUlpDiff		= getMaxUlpDiffFromBits(mantissaBits);	// ULP diff for rounded integer value.
13283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const float		eps				= getEpsFromBits(1.0f, mantissaBits);	// epsilon for rounding bounds
13293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
13303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
13313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
13323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const float		in0			= ((const float*)inputs[0])[compNdx];
13333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const float		out0		= ((const float*)outputs[0])[compNdx];
13343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const int		minRes		= int(in0-eps);
13353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const int		maxRes		= int(in0+eps);
13363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				bool			anyOk		= false;
13373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
13383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				for (int roundedVal = minRes; roundedVal <= maxRes; roundedVal++)
13393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
13403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					const deUint32 ulpDiff = getUlpDiffIgnoreZeroSign(out0, float(roundedVal));
13413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
13423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					if (ulpDiff <= maxUlpDiff)
13433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					{
13443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						anyOk = true;
13453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						break;
13463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					}
13473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
13483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
13493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				if (!anyOk)
13503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
13513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					m_failMsg << "Expected [" << compNdx << "] = [" << minRes << ", " << maxRes << "] with ULP threshold " << tcu::toHex(maxUlpDiff);
13523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					return false;
13533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
13543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
13553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
13563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
13573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return true;
13583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
13593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
13603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
13613c827367444ee418f129b2c238299f49d3264554Jarkko Poyryclass RoundCase : public CommonFunctionCase
13623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
13633c827367444ee418f129b2c238299f49d3264554Jarkko Poyrypublic:
13643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	RoundCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
13653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		: CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "round", shaderType)
13663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
13673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
13683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision)));
13693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_spec.source = "out0 = round(in0);";
13703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
13713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
13723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	void getInputValues (int numValues, void* const* values) const
13733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
13743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const Vec2 ranges[] =
13753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
13763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			Vec2(-2.0f,		2.0f),	// lowp
13773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			Vec2(-1e3f,		1e3f),	// mediump
13783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			Vec2(-1e7f,		1e7f)	// highp
13793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		};
13803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
13813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		de::Random				rnd				(deStringHash(getName()) ^ 0xac23fu);
13823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
13833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
13843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int				scalarSize		= glu::getDataTypeScalarSize(type);
13853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		int						numSpecialCases	= 0;
13863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
13873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Special cases.
13883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (precision != glu::PRECISION_LOWP)
13893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
13903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			DE_ASSERT(numValues >= 10);
13913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int ndx = 0; ndx < 10; ndx++)
13923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
13933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const float v = de::clamp(float(ndx) - 5.5f, ranges[precision].x(), ranges[precision].y());
13943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				std::fill((float*)values[0], (float*)values[0] + scalarSize, v);
13953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				numSpecialCases += 1;
13963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
13973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
13983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
13993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Random cases.
14003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), (float*)values[0] + numSpecialCases*scalarSize, (numValues-numSpecialCases)*scalarSize);
14013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// If precision is mediump, make sure values can be represented in fp16 exactly
14033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (precision == glu::PRECISION_MEDIUMP)
14043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
14053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int ndx = 0; ndx < numValues*scalarSize; ndx++)
14063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				((float*)values[0])[ndx] = tcu::Float16(((float*)values[0])[ndx]).asFloat();
14073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
14083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
14093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	bool compare (const void* const* inputs, const void* const* outputs)
14113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
14123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
14133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
14143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const bool				hasZeroSign		= supportsSignedZero(precision);
14153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int				scalarSize		= glu::getDataTypeScalarSize(type);
14163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (precision == glu::PRECISION_HIGHP || precision == glu::PRECISION_MEDIUMP)
14183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
14193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
14203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
14213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const float		in0			= ((const float*)inputs[0])[compNdx];
14223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const float		out0		= ((const float*)outputs[0])[compNdx];
14233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				if (deFloatFrac(in0) == 0.5f)
14253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
14263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					// Allow both ceil(in) and floor(in)
14273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					const float		ref0		= deFloatFloor(in0);
14283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					const float		ref1		= deFloatCeil(in0);
14293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					const deUint32	ulpDiff0	= hasZeroSign ? getUlpDiff(out0, ref0) : getUlpDiffIgnoreZeroSign(out0, ref0);
14303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					const deUint32	ulpDiff1	= hasZeroSign ? getUlpDiff(out0, ref1) : getUlpDiffIgnoreZeroSign(out0, ref1);
14313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					if (ulpDiff0 > 0 && ulpDiff1 > 0)
14333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					{
14343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref0) << " or " << HexFloat(ref1) << ", got ULP diff " << tcu::toHex(de::min(ulpDiff0, ulpDiff1));
14353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						return false;
14363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					}
14373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
14383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				else
14393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
14403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					// Require exact result
14413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					const float		ref		= roundEven(in0);
14423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					const deUint32	ulpDiff	= hasZeroSign ? getUlpDiff(out0, ref) : getUlpDiffIgnoreZeroSign(out0, ref);
14433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					if (ulpDiff > 0)
14453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					{
14463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref) << ", got ULP diff " << tcu::toHex(ulpDiff);
14473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						return false;
14483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					}
14493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
14503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
14513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
14523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		else
14533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
14543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const int		mantissaBits	= getMinMantissaBits(precision);
14553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const deUint32	maxUlpDiff		= getMaxUlpDiffFromBits(mantissaBits);	// ULP diff for rounded integer value.
14563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const float		eps				= getEpsFromBits(1.0f, mantissaBits);	// epsilon for rounding bounds
14573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
14593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
14603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const float		in0			= ((const float*)inputs[0])[compNdx];
14613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const float		out0		= ((const float*)outputs[0])[compNdx];
14623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const int		minRes		= int(roundEven(in0-eps));
14633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const int		maxRes		= int(roundEven(in0+eps));
14643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				bool			anyOk		= false;
14653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				for (int roundedVal = minRes; roundedVal <= maxRes; roundedVal++)
14673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
14683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					const deUint32 ulpDiff = getUlpDiffIgnoreZeroSign(out0, float(roundedVal));
14693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					if (ulpDiff <= maxUlpDiff)
14713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					{
14723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						anyOk = true;
14733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						break;
14743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					}
14753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
14763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				if (!anyOk)
14783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
14793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					m_failMsg << "Expected [" << compNdx << "] = [" << minRes << ", " << maxRes << "] with ULP threshold " << tcu::toHex(maxUlpDiff);
14803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					return false;
14813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
14823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
14833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
14843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return true;
14863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
14873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
14883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
14893c827367444ee418f129b2c238299f49d3264554Jarkko Poyryclass CeilCase : public CommonFunctionCase
14903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
14913c827367444ee418f129b2c238299f49d3264554Jarkko Poyrypublic:
14923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	CeilCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
14933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		: CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "ceil", shaderType)
14943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
14953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
14963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision)));
14973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_spec.source = "out0 = ceil(in0);";
14983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
14993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
15003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	void getInputValues (int numValues, void* const* values) const
15013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
15023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const Vec2 ranges[] =
15033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
15043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			Vec2(-2.0f,		2.0f),	// lowp
15053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			Vec2(-1e3f,		1e3f),	// mediump
15063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			Vec2(-1e7f,		1e7f)	// highp
15073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		};
15083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
15093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		de::Random				rnd			(deStringHash(getName()) ^ 0xac23fu);
15103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::DataType		type		= m_spec.inputs[0].varType.getBasicType();
15113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::Precision	precision	= m_spec.inputs[0].varType.getPrecision();
15123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int				scalarSize	= glu::getDataTypeScalarSize(type);
15133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
15143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Random cases.
15153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), (float*)values[0], numValues*scalarSize);
15163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
15173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// If precision is mediump, make sure values can be represented in fp16 exactly
15183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (precision == glu::PRECISION_MEDIUMP)
15193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
15203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int ndx = 0; ndx < numValues*scalarSize; ndx++)
15213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				((float*)values[0])[ndx] = tcu::Float16(((float*)values[0])[ndx]).asFloat();
15223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
15233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
15243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
15253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	bool compare (const void* const* inputs, const void* const* outputs)
15263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
15273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
15283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
15293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const bool				hasZeroSign		= supportsSignedZero(precision);
15303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int				scalarSize		= glu::getDataTypeScalarSize(type);
15313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
15323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (precision == glu::PRECISION_HIGHP || precision == glu::PRECISION_MEDIUMP)
15333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
15343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			// Require exact result.
15353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
15363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
15373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const float		in0			= ((const float*)inputs[0])[compNdx];
15383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const float		out0		= ((const float*)outputs[0])[compNdx];
15393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const float		ref			= deFloatCeil(in0);
15403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
15413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const deUint32	ulpDiff		= hasZeroSign ? getUlpDiff(out0, ref) : getUlpDiffIgnoreZeroSign(out0, ref);
15423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
15433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				if (ulpDiff > 0)
15443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
15453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref) << ", got ULP diff " << tcu::toHex(ulpDiff);
15463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					return false;
15473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
15483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
15493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
15503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		else
15513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
15523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const int		mantissaBits	= getMinMantissaBits(precision);
15533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const deUint32	maxUlpDiff		= getMaxUlpDiffFromBits(mantissaBits);	// ULP diff for rounded integer value.
15543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const float		eps				= getEpsFromBits(1.0f, mantissaBits);	// epsilon for rounding bounds
15553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
15563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
15573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
15583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const float		in0			= ((const float*)inputs[0])[compNdx];
15593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const float		out0		= ((const float*)outputs[0])[compNdx];
15603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const int		minRes		= int(deFloatCeil(in0-eps));
15613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const int		maxRes		= int(deFloatCeil(in0+eps));
15623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				bool			anyOk		= false;
15633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
15643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				for (int roundedVal = minRes; roundedVal <= maxRes; roundedVal++)
15653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
15663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					const deUint32 ulpDiff = getUlpDiffIgnoreZeroSign(out0, float(roundedVal));
15673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
15683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					if (ulpDiff <= maxUlpDiff)
15693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					{
15703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						anyOk = true;
15713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						break;
15723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					}
15733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
15743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
15753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				if (!anyOk && de::inRange(0, minRes, maxRes))
15763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
15773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					// Allow -0 as well.
15783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					const int ulpDiff = de::abs((int)tcu::Float32(out0).bits() - (int)0x80000000u);
15793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					anyOk = ((deUint32)ulpDiff <= maxUlpDiff);
15803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
15813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
15823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				if (!anyOk)
15833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
15843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					m_failMsg << "Expected [" << compNdx << "] = [" << minRes << ", " << maxRes << "] with ULP threshold " << tcu::toHex(maxUlpDiff);
15853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					return false;
15863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
15873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
15883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
15893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
15903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return true;
15913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
15923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
15933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
15943c827367444ee418f129b2c238299f49d3264554Jarkko Poyryclass FractCase : public CommonFunctionCase
15953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
15963c827367444ee418f129b2c238299f49d3264554Jarkko Poyrypublic:
15973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	FractCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
15983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		: CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "fract", shaderType)
15993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
16003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
16013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision)));
16023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_spec.source = "out0 = fract(in0);";
16033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
16043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
16053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	void getInputValues (int numValues, void* const* values) const
16063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
16073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const Vec2 ranges[] =
16083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
16093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			Vec2(-2.0f,		2.0f),	// lowp
16103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			Vec2(-1e3f,		1e3f),	// mediump
16113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			Vec2(-1e7f,		1e7f)	// highp
16123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		};
16133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
16143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		de::Random				rnd				(deStringHash(getName()) ^ 0xac23fu);
16153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
16163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
16173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int				scalarSize		= glu::getDataTypeScalarSize(type);
16183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		int						numSpecialCases	= 0;
16193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
16203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Special cases.
16213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (precision != glu::PRECISION_LOWP)
16223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
16233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			DE_ASSERT(numValues >= 10);
16243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int ndx = 0; ndx < 10; ndx++)
16253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
16263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const float v = de::clamp(float(ndx) - 5.5f, ranges[precision].x(), ranges[precision].y());
16273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				std::fill((float*)values[0], (float*)values[0] + scalarSize, v);
16283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				numSpecialCases += 1;
16293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
16303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
16313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
16323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Random cases.
16333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), (float*)values[0] + numSpecialCases*scalarSize, (numValues-numSpecialCases)*scalarSize);
16343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
16353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// If precision is mediump, make sure values can be represented in fp16 exactly
16363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (precision == glu::PRECISION_MEDIUMP)
16373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
16383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int ndx = 0; ndx < numValues*scalarSize; ndx++)
16393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				((float*)values[0])[ndx] = tcu::Float16(((float*)values[0])[ndx]).asFloat();
16403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
16413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
16423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
16433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	bool compare (const void* const* inputs, const void* const* outputs)
16443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
16453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
16463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
16473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const bool				hasZeroSign		= supportsSignedZero(precision);
16483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int				scalarSize		= glu::getDataTypeScalarSize(type);
16493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
16503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (precision == glu::PRECISION_HIGHP || precision == glu::PRECISION_MEDIUMP)
16513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
16523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			// Require exact result.
16533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
16543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
16553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const float		in0			= ((const float*)inputs[0])[compNdx];
16563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const float		out0		= ((const float*)outputs[0])[compNdx];
16573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const float		ref			= deFloatFrac(in0);
16583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
16593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const deUint32	ulpDiff		= hasZeroSign ? getUlpDiff(out0, ref) : getUlpDiffIgnoreZeroSign(out0, ref);
16603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
16613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				if (ulpDiff > 0)
16623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
16633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref) << ", got ULP diff " << tcu::toHex(ulpDiff);
16643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					return false;
16653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
16663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
16673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
16683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		else
16693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
16703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const int		mantissaBits	= getMinMantissaBits(precision);
16713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const float		eps				= getEpsFromBits(1.0f, mantissaBits);	// epsilon for rounding bounds
16723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
16733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
16743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
16753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const float		in0			= ((const float*)inputs[0])[compNdx];
16763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				const float		out0		= ((const float*)outputs[0])[compNdx];
16773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
16783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				if (int(deFloatFloor(in0-eps)) == int(deFloatFloor(in0+eps)))
16793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
16803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					const float		ref			= deFloatFrac(in0);
16813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					const int		bitsLost	= numBitsLostInOp(in0, ref);
16823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					const deUint32	maxUlpDiff	= getMaxUlpDiffFromBits(de::max(0, mantissaBits-bitsLost));	// ULP diff for rounded integer value.
16833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					const deUint32	ulpDiff		= getUlpDiffIgnoreZeroSign(out0, ref);
16843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
16853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					if (ulpDiff > maxUlpDiff)
16863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					{
16873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref) << " with ULP threshold " << tcu::toHex(maxUlpDiff) << ", got diff " << tcu::toHex(ulpDiff);
16883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						return false;
16893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					}
16903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
16913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				else
16923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
16933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					if (out0 >= 1.0f)
16943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					{
16953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						m_failMsg << "Expected [" << compNdx << "] < 1.0";
16963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						return false;
16973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					}
16983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
16993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
17003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
17013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
17023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return true;
17033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
17043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
17053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
17063c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic inline void frexp (float in, float* significand, int* exponent)
17073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
17083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const tcu::Float32 fpValue(in);
17093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
17103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (!fpValue.isZero())
17113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
17123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Construct float that has exactly the mantissa, and exponent of -1.
17133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		*significand	= tcu::Float32::construct(fpValue.sign(), -1, fpValue.mantissa()).asFloat();
17143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		*exponent		= fpValue.exponent()+1;
17153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
17163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	else
17173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
17183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		*significand	= fpValue.sign() < 0 ? -0.0f : 0.0f;
17193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		*exponent		= 0;
17203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
17213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
17223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
17233c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic inline float ldexp (float significand, int exponent)
17243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
17253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const tcu::Float32 mant(significand);
17263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
17273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	if (exponent == 0 && mant.isZero())
17283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
17293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return mant.sign() < 0 ? -0.0f : 0.0f;
17303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
17313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	else
17323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
17333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return tcu::Float32::construct(mant.sign(), exponent+mant.exponent(), mant.mantissa()).asFloat();
17343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
17353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
17363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
17373c827367444ee418f129b2c238299f49d3264554Jarkko Poyryclass FrexpCase : public CommonFunctionCase
17383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
17393c827367444ee418f129b2c238299f49d3264554Jarkko Poyrypublic:
17403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	FrexpCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
17413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		: CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "frexp", shaderType)
17423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
17433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int			vecSize		= glu::getDataTypeScalarSize(baseType);
17443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::DataType	intType		= vecSize > 1 ? glu::getDataTypeIntVec(vecSize) : glu::TYPE_INT;
17453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
17463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
17473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, glu::PRECISION_HIGHP)));
17483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_spec.outputs.push_back(Symbol("out1", glu::VarType(intType, glu::PRECISION_HIGHP)));
17493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_spec.source = "out0 = frexp(in0, out1);";
17503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
17513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
17523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	void getInputValues (int numValues, void* const* values) const
17533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
17543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const Vec2 ranges[] =
17553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
17563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			Vec2(-2.0f,		2.0f),	// lowp
17573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			Vec2(-1e3f,		1e3f),	// mediump
17583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			Vec2(-1e7f,		1e7f)	// highp
17593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		};
17603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
17613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		de::Random				rnd			(deStringHash(getName()) ^ 0x2790au);
17623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::DataType		type		= m_spec.inputs[0].varType.getBasicType();
17633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::Precision	precision	= m_spec.inputs[0].varType.getPrecision();
17643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int				scalarSize	= glu::getDataTypeScalarSize(type);
17653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
17663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Special cases
17673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int compNdx = 0; compNdx < scalarSize; compNdx++)
17683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
17693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			((float*)values[0])[scalarSize*0 + compNdx] = 0.0f;
17703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			((float*)values[0])[scalarSize*1 + compNdx] = -0.0f;
17713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			((float*)values[0])[scalarSize*2 + compNdx] = 0.5f;
17723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			((float*)values[0])[scalarSize*3 + compNdx] = -0.5f;
17733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			((float*)values[0])[scalarSize*4 + compNdx] = 1.0f;
17743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			((float*)values[0])[scalarSize*5 + compNdx] = -1.0f;
17753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			((float*)values[0])[scalarSize*6 + compNdx] = 2.0f;
17763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			((float*)values[0])[scalarSize*7 + compNdx] = -2.0f;
17773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
17783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
17793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), (float*)values[0] + 8*scalarSize, (numValues-8)*scalarSize);
17806c9ec4d03a5a9eb4e7cc7e665181c216fefe49f9Jarkko Pöyry
17816c9ec4d03a5a9eb4e7cc7e665181c216fefe49f9Jarkko Pöyry		// Make sure the values are representable in the target format
17826c9ec4d03a5a9eb4e7cc7e665181c216fefe49f9Jarkko Pöyry		for (int caseNdx = 0; caseNdx < numValues; ++caseNdx)
17836c9ec4d03a5a9eb4e7cc7e665181c216fefe49f9Jarkko Pöyry		{
17846c9ec4d03a5a9eb4e7cc7e665181c216fefe49f9Jarkko Pöyry			for (int scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++)
17856c9ec4d03a5a9eb4e7cc7e665181c216fefe49f9Jarkko Pöyry			{
17866c9ec4d03a5a9eb4e7cc7e665181c216fefe49f9Jarkko Pöyry				float* const valuePtr = &((float*)values[0])[caseNdx * scalarSize + scalarNdx];
17876c9ec4d03a5a9eb4e7cc7e665181c216fefe49f9Jarkko Pöyry
17886c9ec4d03a5a9eb4e7cc7e665181c216fefe49f9Jarkko Pöyry				*valuePtr = makeFloatRepresentable(*valuePtr, precision);
17896c9ec4d03a5a9eb4e7cc7e665181c216fefe49f9Jarkko Pöyry			}
17906c9ec4d03a5a9eb4e7cc7e665181c216fefe49f9Jarkko Pöyry		}
17913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
17923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
17933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	bool compare (const void* const* inputs, const void* const* outputs)
17943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
17957b3d2d144661c38a8e609d4633f1585b7c5d3c43Jarkko Pöyry		const glu::DataType		type						= m_spec.inputs[0].varType.getBasicType();
17967b3d2d144661c38a8e609d4633f1585b7c5d3c43Jarkko Pöyry		const glu::Precision	precision					= m_spec.inputs[0].varType.getPrecision();
17977b3d2d144661c38a8e609d4633f1585b7c5d3c43Jarkko Pöyry		const int				scalarSize					= glu::getDataTypeScalarSize(type);
17989af2a7364f8f35d008d63c5df45fce6f33cc5a82Pyry Haulos		const bool				signedZero					= false;
17997b3d2d144661c38a8e609d4633f1585b7c5d3c43Jarkko Pöyry
18007b3d2d144661c38a8e609d4633f1585b7c5d3c43Jarkko Pöyry		const int				mantissaBits				= getMinMantissaBits(precision);
18017b3d2d144661c38a8e609d4633f1585b7c5d3c43Jarkko Pöyry		const deUint32			maxUlpDiff					= getMaxUlpDiffFromBits(mantissaBits);
18023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
18033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int compNdx = 0; compNdx < scalarSize; compNdx++)
18043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
18053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const float		in0			= ((const float*)inputs[0])[compNdx];
18063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const float		out0		= ((const float*)outputs[0])[compNdx];
18073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const int		out1		= ((const int*)outputs[1])[compNdx];
18083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
18093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			float			refOut0;
18103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			int				refOut1;
18113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
18123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			frexp(in0, &refOut0, &refOut1);
18133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
18143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const deUint32	ulpDiff0	= signedZero ? getUlpDiff(out0, refOut0) : getUlpDiffIgnoreZeroSign(out0, refOut0);
18153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
18163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			if (ulpDiff0 > maxUlpDiff || out1 != refOut1)
18173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
18183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(refOut0) << ", " << refOut1 << " with ULP threshold "
18193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						  << tcu::toHex(maxUlpDiff) << ", got ULP diff " << tcu::toHex(ulpDiff0);
18203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				return false;
18213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
18223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
18233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
18243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return true;
18253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
18263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
18273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
18283c827367444ee418f129b2c238299f49d3264554Jarkko Poyryclass LdexpCase : public CommonFunctionCase
18293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
18303c827367444ee418f129b2c238299f49d3264554Jarkko Poyrypublic:
18313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	LdexpCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
18323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		: CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "ldexp", shaderType)
18333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
18343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int			vecSize		= glu::getDataTypeScalarSize(baseType);
18353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::DataType	intType		= vecSize > 1 ? glu::getDataTypeIntVec(vecSize) : glu::TYPE_INT;
18363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
18373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
18383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_spec.inputs.push_back(Symbol("in1", glu::VarType(intType, glu::PRECISION_HIGHP)));
18393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, glu::PRECISION_HIGHP)));
18403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_spec.source = "out0 = ldexp(in0, in1);";
18413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
18423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
18433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	void getInputValues (int numValues, void* const* values) const
18443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
18453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const Vec2 ranges[] =
18463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
18473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			Vec2(-2.0f,		2.0f),	// lowp
18483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			Vec2(-1e3f,		1e3f),	// mediump
18493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			Vec2(-1e7f,		1e7f)	// highp
18503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		};
18513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
18523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		de::Random				rnd					(deStringHash(getName()) ^ 0x2790au);
18533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::DataType		type				= m_spec.inputs[0].varType.getBasicType();
18543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::Precision	precision			= m_spec.inputs[0].varType.getPrecision();
18553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int				scalarSize			= glu::getDataTypeScalarSize(type);
18563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		int						valueNdx			= 0;
18573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
18583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
18593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const float easySpecialCases[] = { 0.0f, -0.0f, 0.5f, -0.5f, 1.0f, -1.0f, 2.0f, -2.0f };
18603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
18613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			DE_ASSERT(valueNdx + DE_LENGTH_OF_ARRAY(easySpecialCases) <= numValues);
18623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(easySpecialCases); caseNdx++)
18633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
18643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				float	in0;
18653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				int		in1;
18663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
18673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				frexp(easySpecialCases[caseNdx], &in0, &in1);
18683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
18693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				for (int compNdx = 0; compNdx < scalarSize; compNdx++)
18703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
18713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					((float*)values[0])[valueNdx*scalarSize + compNdx] = in0;
18723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					((int*)values[1])[valueNdx*scalarSize + compNdx] = in1;
18733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
18743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
18753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				valueNdx += 1;
18763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
18773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
18783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
18793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
18803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			// \note lowp and mediump can not necessarily fit the values in hard cases, so we'll use only easy ones.
18813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const int numEasyRandomCases = precision == glu::PRECISION_HIGHP ? 50 : (numValues-valueNdx);
18823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
18833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			DE_ASSERT(valueNdx + numEasyRandomCases <= numValues);
18843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int caseNdx = 0; caseNdx < numEasyRandomCases; caseNdx++)
18853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
18863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				for (int compNdx = 0; compNdx < scalarSize; compNdx++)
18873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
18883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					const float	in	= rnd.getFloat(ranges[precision].x(), ranges[precision].y());
18893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					float		in0;
18903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					int			in1;
18913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
18923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					frexp(in, &in0, &in1);
18933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
18943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					((float*)values[0])[valueNdx*scalarSize + compNdx] = in0;
18953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					((int*)values[1])[valueNdx*scalarSize + compNdx] = in1;
18963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
18973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
18983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				valueNdx += 1;
18993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
19003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
19013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
19023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
19033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const int numHardRandomCases = numValues-valueNdx;
19043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			DE_ASSERT(numHardRandomCases >= 0 && valueNdx + numHardRandomCases <= numValues);
19053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
19063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int caseNdx = 0; caseNdx < numHardRandomCases; caseNdx++)
19073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
19083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				for (int compNdx = 0; compNdx < scalarSize; compNdx++)
19093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
19103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					const int		fpExp		= rnd.getInt(-126, 127);
19113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					const int		sign		= rnd.getBool() ? -1 : +1;
19123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					const deUint32	mantissa	= (1u<<23) | (rnd.getUint32() & ((1u<<23)-1));
19133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					const int		in1			= rnd.getInt(de::max(-126, -126-fpExp), de::min(127, 127-fpExp));
19143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					const float		in0			= tcu::Float32::construct(sign, fpExp, mantissa).asFloat();
19153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
19163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					DE_ASSERT(de::inRange(in1, -126, 127)); // See Khronos bug 11180
19173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					DE_ASSERT(de::inRange(in1+fpExp, -126, 127));
19183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
19193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					const float		out			= ldexp(in0, in1);
19203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
19213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					DE_ASSERT(!tcu::Float32(out).isInf() && !tcu::Float32(out).isDenorm());
19223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					DE_UNREF(out);
19233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
19243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					((float*)values[0])[valueNdx*scalarSize + compNdx] = in0;
19253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					((int*)values[1])[valueNdx*scalarSize + compNdx] = in1;
19263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
19273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
19283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				valueNdx += 1;
19293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
19303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
19313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
19323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
19333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	bool compare (const void* const* inputs, const void* const* outputs)
19343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
19353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
19363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
19373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int				scalarSize		= glu::getDataTypeScalarSize(type);
19383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
19393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int				mantissaBits	= getMinMantissaBits(precision);
19403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const deUint32			maxUlpDiff		= getMaxUlpDiffFromBits(mantissaBits);
19413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
19423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int compNdx = 0; compNdx < scalarSize; compNdx++)
19433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
19443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const float		in0			= ((const float*)inputs[0])[compNdx];
19453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const int		in1			= ((const int*)inputs[1])[compNdx];
19463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const float		out0		= ((const float*)outputs[0])[compNdx];
19473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const float		refOut0		= ldexp(in0, in1);
19481e44f197ded674677381f65c840820728cf36efbPyry Haulos			const deUint32	ulpDiff		= getUlpDiffIgnoreZeroSign(out0, refOut0);
19493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
19503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const int		inExp		= tcu::Float32(in0).exponent();
19513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
19523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			if (ulpDiff > maxUlpDiff)
19533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
19543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(refOut0) << ", (exp = " << inExp << ") with ULP threshold "
19553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						  << tcu::toHex(maxUlpDiff) << ", got ULP diff " << tcu::toHex(ulpDiff);
19563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				return false;
19573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
19583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
19593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
19603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return true;
19613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
19623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
19633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
19643c827367444ee418f129b2c238299f49d3264554Jarkko Poyryclass FmaCase : public CommonFunctionCase
19653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
19663c827367444ee418f129b2c238299f49d3264554Jarkko Poyrypublic:
19673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	FmaCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
19683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		: CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "fma", shaderType)
19693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
19703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_spec.inputs.push_back(Symbol("a", glu::VarType(baseType, precision)));
19713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_spec.inputs.push_back(Symbol("b", glu::VarType(baseType, precision)));
19723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_spec.inputs.push_back(Symbol("c", glu::VarType(baseType, precision)));
19733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_spec.outputs.push_back(Symbol("res", glu::VarType(baseType, precision)));
19743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_spec.source = "res = fma(a, b, c);";
19753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		m_spec.globalDeclarations = "#extension GL_EXT_gpu_shader5 : require\n";
19763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
19773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
19783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	void init (void)
19793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
19803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_gpu_shader5"))
19813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			throw tcu::NotSupportedError("GL_EXT_gpu_shader5 not supported");
19823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
19833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		CommonFunctionCase::init();
19843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
19853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
19863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	void getInputValues (int numValues, void* const* values) const
19873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
19883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const Vec2 ranges[] =
19893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
19903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			Vec2(-2.0f,		2.0f),	// lowp
199124f9049882d302a83a4788f829863f123f2aeae1Pyry Haulos			Vec2(-127.f,	127.f),	// mediump
19923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			Vec2(-1e7f,		1e7f)	// highp
19933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		};
19943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
1995ade588f3b2b1b6d007b9681e95434dc4a4bd46caJarkko Pöyry		de::Random				rnd							(deStringHash(getName()) ^ 0xac23fu);
1996ade588f3b2b1b6d007b9681e95434dc4a4bd46caJarkko Pöyry		const glu::DataType		type						= m_spec.inputs[0].varType.getBasicType();
1997ade588f3b2b1b6d007b9681e95434dc4a4bd46caJarkko Pöyry		const glu::Precision	precision					= m_spec.inputs[0].varType.getPrecision();
1998ade588f3b2b1b6d007b9681e95434dc4a4bd46caJarkko Pöyry		const int				scalarSize					= glu::getDataTypeScalarSize(type);
1999ade588f3b2b1b6d007b9681e95434dc4a4bd46caJarkko Pöyry		const float				specialCases[][3]			=
20003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
20013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			// a		b		c
20023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{ 0.0f,		0.0f,	0.0f },
20033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{ 0.0f,		1.0f,	0.0f },
20043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{ 0.0f,		0.0f,	-1.0f },
20053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{ 1.0f,		1.0f,	0.0f },
20063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{ 1.0f,		1.0f,	1.0f },
20073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{ -1.0f,	1.0f,	0.0f },
20083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{ 1.0f,		-1.0f,	0.0f },
20093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{ -1.0f,	-1.0f,	0.0f },
20103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{ -0.0f,	1.0f,	0.0f },
20113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{ 1.0f,		-0.0f,	0.0f }
20123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		};
2013ade588f3b2b1b6d007b9681e95434dc4a4bd46caJarkko Pöyry		const int				numSpecialCases				= DE_LENGTH_OF_ARRAY(specialCases);
20143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
20153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Special cases
20163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int caseNdx = 0; caseNdx < numSpecialCases; caseNdx++)
20173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
20183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int inputNdx = 0; inputNdx < 3; inputNdx++)
20193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
20203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				for (int scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++)
20213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					((float*)values[inputNdx])[caseNdx*scalarSize + scalarNdx] = specialCases[caseNdx][inputNdx];
20223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
20233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
20243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
20253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		// Random cases.
20263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
20273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const int	numScalars	= (numValues-numSpecialCases)*scalarSize;
20283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const int	offs		= scalarSize*numSpecialCases;
20293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
20303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int inputNdx = 0; inputNdx < 3; inputNdx++)
20313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), (float*)values[inputNdx] + offs, numScalars);
20323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
2033ade588f3b2b1b6d007b9681e95434dc4a4bd46caJarkko Pöyry
2034ade588f3b2b1b6d007b9681e95434dc4a4bd46caJarkko Pöyry		// Make sure the values are representable in the target format
20356c9ec4d03a5a9eb4e7cc7e665181c216fefe49f9Jarkko Pöyry		for (int inputNdx = 0; inputNdx < 3; inputNdx++)
2036ade588f3b2b1b6d007b9681e95434dc4a4bd46caJarkko Pöyry		{
20376c9ec4d03a5a9eb4e7cc7e665181c216fefe49f9Jarkko Pöyry			for (int caseNdx = 0; caseNdx < numValues; ++caseNdx)
2038ade588f3b2b1b6d007b9681e95434dc4a4bd46caJarkko Pöyry			{
20396c9ec4d03a5a9eb4e7cc7e665181c216fefe49f9Jarkko Pöyry				for (int scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++)
2040ade588f3b2b1b6d007b9681e95434dc4a4bd46caJarkko Pöyry				{
20416c9ec4d03a5a9eb4e7cc7e665181c216fefe49f9Jarkko Pöyry					float* const valuePtr = &((float*)values[inputNdx])[caseNdx * scalarSize + scalarNdx];
20426c9ec4d03a5a9eb4e7cc7e665181c216fefe49f9Jarkko Pöyry
20436c9ec4d03a5a9eb4e7cc7e665181c216fefe49f9Jarkko Pöyry					*valuePtr = makeFloatRepresentable(*valuePtr, precision);
2044ade588f3b2b1b6d007b9681e95434dc4a4bd46caJarkko Pöyry				}
2045ade588f3b2b1b6d007b9681e95434dc4a4bd46caJarkko Pöyry			}
2046ade588f3b2b1b6d007b9681e95434dc4a4bd46caJarkko Pöyry		}
20473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
20483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2049e5fc2a804322422a6d50270e9e00fb1c193b6f90Pyry Haulos	static tcu::Interval fma (glu::Precision precision, float a, float b, float c)
2050e5fc2a804322422a6d50270e9e00fb1c193b6f90Pyry Haulos	{
2051e5fc2a804322422a6d50270e9e00fb1c193b6f90Pyry Haulos		const tcu::FloatFormat formats[] =
2052e5fc2a804322422a6d50270e9e00fb1c193b6f90Pyry Haulos		{
2053e5fc2a804322422a6d50270e9e00fb1c193b6f90Pyry Haulos			//				 minExp		maxExp		mantissa	exact,		subnormals	infinities	NaN
2054e5fc2a804322422a6d50270e9e00fb1c193b6f90Pyry Haulos			tcu::FloatFormat(0,			0,			7,			false,		tcu::YES,	tcu::MAYBE,	tcu::MAYBE),
2055e5fc2a804322422a6d50270e9e00fb1c193b6f90Pyry Haulos			tcu::FloatFormat(-13,		13,			9,			false,		tcu::MAYBE,	tcu::MAYBE,	tcu::MAYBE),
2056e5fc2a804322422a6d50270e9e00fb1c193b6f90Pyry Haulos			tcu::FloatFormat(-126,		127,		23,			true,		tcu::MAYBE, tcu::YES,	tcu::MAYBE)
2057e5fc2a804322422a6d50270e9e00fb1c193b6f90Pyry Haulos		};
2058e5fc2a804322422a6d50270e9e00fb1c193b6f90Pyry Haulos		const tcu::FloatFormat&	format	= de::getSizedArrayElement<glu::PRECISION_LAST>(formats, precision);
2059e5fc2a804322422a6d50270e9e00fb1c193b6f90Pyry Haulos		const tcu::Interval		ia		= format.convert(a);
2060e5fc2a804322422a6d50270e9e00fb1c193b6f90Pyry Haulos		const tcu::Interval		ib		= format.convert(b);
2061e5fc2a804322422a6d50270e9e00fb1c193b6f90Pyry Haulos		const tcu::Interval		ic		= format.convert(c);
2062e5fc2a804322422a6d50270e9e00fb1c193b6f90Pyry Haulos		tcu::Interval			prod0;
2063e5fc2a804322422a6d50270e9e00fb1c193b6f90Pyry Haulos		tcu::Interval			prod1;
2064e5fc2a804322422a6d50270e9e00fb1c193b6f90Pyry Haulos		tcu::Interval			prod2;
2065e5fc2a804322422a6d50270e9e00fb1c193b6f90Pyry Haulos		tcu::Interval			prod3;
2066e5fc2a804322422a6d50270e9e00fb1c193b6f90Pyry Haulos		tcu::Interval			prod;
2067e5fc2a804322422a6d50270e9e00fb1c193b6f90Pyry Haulos		tcu::Interval			res;
2068e5fc2a804322422a6d50270e9e00fb1c193b6f90Pyry Haulos
2069e5fc2a804322422a6d50270e9e00fb1c193b6f90Pyry Haulos		TCU_SET_INTERVAL(prod0, tmp, tmp = ia.lo() * ib.lo());
2070e5fc2a804322422a6d50270e9e00fb1c193b6f90Pyry Haulos		TCU_SET_INTERVAL(prod1, tmp, tmp = ia.lo() * ib.hi());
2071e5fc2a804322422a6d50270e9e00fb1c193b6f90Pyry Haulos		TCU_SET_INTERVAL(prod2, tmp, tmp = ia.hi() * ib.lo());
2072e5fc2a804322422a6d50270e9e00fb1c193b6f90Pyry Haulos		TCU_SET_INTERVAL(prod3, tmp, tmp = ia.hi() * ib.hi());
2073e5fc2a804322422a6d50270e9e00fb1c193b6f90Pyry Haulos
2074e5fc2a804322422a6d50270e9e00fb1c193b6f90Pyry Haulos		prod = format.convert(format.roundOut(prod0 | prod1 | prod2 | prod3, ia.isFinite() && ib.isFinite()));
2075e5fc2a804322422a6d50270e9e00fb1c193b6f90Pyry Haulos
2076e5fc2a804322422a6d50270e9e00fb1c193b6f90Pyry Haulos		TCU_SET_INTERVAL_BOUNDS(res, tmp,
2077e5fc2a804322422a6d50270e9e00fb1c193b6f90Pyry Haulos								tmp = prod.lo() + ic.lo(),
2078e5fc2a804322422a6d50270e9e00fb1c193b6f90Pyry Haulos								tmp = prod.hi() + ic.hi());
2079e5fc2a804322422a6d50270e9e00fb1c193b6f90Pyry Haulos
2080e5fc2a804322422a6d50270e9e00fb1c193b6f90Pyry Haulos		return format.convert(format.roundOut(res, prod.isFinite() && ic.isFinite()));
2081e5fc2a804322422a6d50270e9e00fb1c193b6f90Pyry Haulos	}
2082e5fc2a804322422a6d50270e9e00fb1c193b6f90Pyry Haulos
20833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	bool compare (const void* const* inputs, const void* const* outputs)
20843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
20853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
20863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
20873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const int				scalarSize		= glu::getDataTypeScalarSize(type);
20883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
20893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int compNdx = 0; compNdx < scalarSize; compNdx++)
20903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
2091e5fc2a804322422a6d50270e9e00fb1c193b6f90Pyry Haulos			const float			a			= ((const float*)inputs[0])[compNdx];
2092e5fc2a804322422a6d50270e9e00fb1c193b6f90Pyry Haulos			const float			b			= ((const float*)inputs[1])[compNdx];
2093e5fc2a804322422a6d50270e9e00fb1c193b6f90Pyry Haulos			const float			c			= ((const float*)inputs[2])[compNdx];
2094e5fc2a804322422a6d50270e9e00fb1c193b6f90Pyry Haulos			const float			res			= ((const float*)outputs[0])[compNdx];
2095e5fc2a804322422a6d50270e9e00fb1c193b6f90Pyry Haulos			const tcu::Interval	ref			= fma(precision, a, b, c);
20963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
2097e5fc2a804322422a6d50270e9e00fb1c193b6f90Pyry Haulos			if (!ref.contains(res))
20983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
2099e5fc2a804322422a6d50270e9e00fb1c193b6f90Pyry Haulos				m_failMsg << "Expected [" << compNdx << "] = " << ref;
21003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				return false;
21013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
21023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
21033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
21043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		return true;
21053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
21063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry};
21073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
21083c827367444ee418f129b2c238299f49d3264554Jarkko PoyryShaderCommonFunctionTests::ShaderCommonFunctionTests (Context& context)
21093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	: TestCaseGroup(context, "common", "Common function tests")
21103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
21113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
21123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
21133c827367444ee418f129b2c238299f49d3264554Jarkko PoyryShaderCommonFunctionTests::~ShaderCommonFunctionTests (void)
21143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
21153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
21163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
21173c827367444ee418f129b2c238299f49d3264554Jarkko Poyrytemplate<class TestClass>
21183c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic void addFunctionCases (TestCaseGroup* parent, const char* functionName, bool floatTypes, bool intTypes, bool uintTypes, deUint32 shaderBits)
21193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
21203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	tcu::TestCaseGroup* group = new tcu::TestCaseGroup(parent->getTestContext(), functionName, functionName);
21213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	parent->addChild(group);
21223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
21233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	const glu::DataType scalarTypes[] =
21243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
21253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		glu::TYPE_FLOAT,
21263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		glu::TYPE_INT,
21273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		glu::TYPE_UINT
21283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	};
21293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
21303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	for (int scalarTypeNdx = 0; scalarTypeNdx < DE_LENGTH_OF_ARRAY(scalarTypes); scalarTypeNdx++)
21313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
21323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const glu::DataType scalarType = scalarTypes[scalarTypeNdx];
21333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
21343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		if ((!floatTypes && scalarType == glu::TYPE_FLOAT)	||
21353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			(!intTypes && scalarType == glu::TYPE_INT)		||
21363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			(!uintTypes && scalarType == glu::TYPE_UINT))
21373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			continue;
21383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
21393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int vecSize = 1; vecSize <= 4; vecSize++)
21403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
21413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int prec = glu::PRECISION_LOWP; prec <= glu::PRECISION_HIGHP; prec++)
21423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
21433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				for (int shaderTypeNdx = 0; shaderTypeNdx < glu::SHADERTYPE_LAST; shaderTypeNdx++)
21443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
21453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					if (shaderBits & (1<<shaderTypeNdx))
21463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry						group->addChild(new TestClass(parent->getContext(), glu::DataType(scalarType + vecSize - 1), glu::Precision(prec), glu::ShaderType(shaderTypeNdx)));
21473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
21483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
21493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
21503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
21513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
21523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
21533c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid ShaderCommonFunctionTests::init (void)
21543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{
21553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	enum
21563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
21573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		VS = (1<<glu::SHADERTYPE_VERTEX),
21583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		TC = (1<<glu::SHADERTYPE_TESSELLATION_CONTROL),
21593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		TE = (1<<glu::SHADERTYPE_TESSELLATION_EVALUATION),
21603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		GS = (1<<glu::SHADERTYPE_GEOMETRY),
21613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		FS = (1<<glu::SHADERTYPE_FRAGMENT),
21623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		CS = (1<<glu::SHADERTYPE_COMPUTE),
21633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
21643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		ALL_SHADERS = VS|TC|TE|GS|FS|CS,
21653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		NEW_SHADERS = TC|TE|GS|CS,
21663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	};
21673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
21683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	//																	Float?	Int?	Uint?	Shaders
21693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	addFunctionCases<AbsCase>				(this,	"abs",				true,	true,	false,	NEW_SHADERS);
21703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	addFunctionCases<SignCase>				(this,	"sign",				true,	true,	false,	NEW_SHADERS);
21713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	addFunctionCases<FloorCase>				(this,	"floor",			true,	false,	false,	NEW_SHADERS);
21723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	addFunctionCases<TruncCase>				(this,	"trunc",			true,	false,	false,	NEW_SHADERS);
21733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	addFunctionCases<RoundCase>				(this,	"round",			true,	false,	false,	NEW_SHADERS);
21743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	addFunctionCases<RoundEvenCase>			(this,	"roundeven",		true,	false,	false,	NEW_SHADERS);
21753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	addFunctionCases<CeilCase>				(this,	"ceil",				true,	false,	false,	NEW_SHADERS);
21763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	addFunctionCases<FractCase>				(this,	"fract",			true,	false,	false,	NEW_SHADERS);
21773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// mod
21783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	addFunctionCases<ModfCase>				(this,	"modf",				true,	false,	false,	NEW_SHADERS);
21793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// min
21803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// max
21813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// clamp
21823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// mix
21833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// step
21843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// smoothstep
21853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	addFunctionCases<IsnanCase>				(this,	"isnan",			true,	false,	false,	NEW_SHADERS);
21863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	addFunctionCases<IsinfCase>				(this,	"isinf",			true,	false,	false,	NEW_SHADERS);
21873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	addFunctionCases<FloatBitsToIntCase>	(this,	"floatbitstoint",	true,	false,	false,	NEW_SHADERS);
21883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	addFunctionCases<FloatBitsToUintCase>	(this,	"floatbitstouint",	true,	false,	false,	NEW_SHADERS);
21893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
21903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	addFunctionCases<FrexpCase>				(this,	"frexp",			true,	false,	false,	ALL_SHADERS);
21913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	addFunctionCases<LdexpCase>				(this,	"ldexp",			true,	false,	false,	ALL_SHADERS);
21923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	addFunctionCases<FmaCase>				(this,	"fma",				true,	false,	false,	ALL_SHADERS);
21933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
21943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	// (u)intBitsToFloat()
21953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	{
21963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		const deUint32		shaderBits	= NEW_SHADERS;
21973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		tcu::TestCaseGroup* intGroup	= new tcu::TestCaseGroup(m_testCtx, "intbitstofloat",	"intBitsToFloat() Tests");
21983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		tcu::TestCaseGroup* uintGroup	= new tcu::TestCaseGroup(m_testCtx, "uintbitstofloat",	"uintBitsToFloat() Tests");
21993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
22003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		addChild(intGroup);
22013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		addChild(uintGroup);
22023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
22033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		for (int vecSize = 1; vecSize < 4; vecSize++)
22043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		{
22053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const glu::DataType		intType		= vecSize > 1 ? glu::getDataTypeIntVec(vecSize) : glu::TYPE_INT;
22063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			const glu::DataType		uintType	= vecSize > 1 ? glu::getDataTypeUintVec(vecSize) : glu::TYPE_UINT;
22073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
22083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			for (int shaderType = 0; shaderType < glu::SHADERTYPE_LAST; shaderType++)
22093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			{
22103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				if (shaderBits & (1<<shaderType))
22113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				{
22123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					intGroup->addChild(new BitsToFloatCase(m_context, intType, glu::ShaderType(shaderType)));
22133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry					uintGroup->addChild(new BitsToFloatCase(m_context, uintType, glu::ShaderType(shaderType)));
22143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry				}
22153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry			}
22163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry		}
22173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry	}
22183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}
22193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry
22203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry} // Functional
22213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry} // gles31
22223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry} // deqp
2223