1e5c31af7Sopenharmony_ci/*-------------------------------------------------------------------------
2e5c31af7Sopenharmony_ci * drawElements Quality Program OpenGL ES 3.0 Module
3e5c31af7Sopenharmony_ci * -------------------------------------------------
4e5c31af7Sopenharmony_ci *
5e5c31af7Sopenharmony_ci * Copyright 2014 The Android Open Source Project
6e5c31af7Sopenharmony_ci *
7e5c31af7Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
8e5c31af7Sopenharmony_ci * you may not use this file except in compliance with the License.
9e5c31af7Sopenharmony_ci * You may obtain a copy of the License at
10e5c31af7Sopenharmony_ci *
11e5c31af7Sopenharmony_ci *      http://www.apache.org/licenses/LICENSE-2.0
12e5c31af7Sopenharmony_ci *
13e5c31af7Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
14e5c31af7Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
15e5c31af7Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16e5c31af7Sopenharmony_ci * See the License for the specific language governing permissions and
17e5c31af7Sopenharmony_ci * limitations under the License.
18e5c31af7Sopenharmony_ci *
19e5c31af7Sopenharmony_ci *//*!
20e5c31af7Sopenharmony_ci * \file
21e5c31af7Sopenharmony_ci * \brief Common built-in function tests.
22e5c31af7Sopenharmony_ci *//*--------------------------------------------------------------------*/
23e5c31af7Sopenharmony_ci
24e5c31af7Sopenharmony_ci#include "es3fShaderCommonFunctionTests.hpp"
25e5c31af7Sopenharmony_ci#include "glsShaderExecUtil.hpp"
26e5c31af7Sopenharmony_ci#include "tcuTestLog.hpp"
27e5c31af7Sopenharmony_ci#include "tcuFormatUtil.hpp"
28e5c31af7Sopenharmony_ci#include "tcuVectorUtil.hpp"
29e5c31af7Sopenharmony_ci#include "tcuFloat.hpp"
30e5c31af7Sopenharmony_ci#include "deRandom.hpp"
31e5c31af7Sopenharmony_ci#include "deMath.h"
32e5c31af7Sopenharmony_ci#include "deString.h"
33e5c31af7Sopenharmony_ci
34e5c31af7Sopenharmony_cinamespace deqp
35e5c31af7Sopenharmony_ci{
36e5c31af7Sopenharmony_cinamespace gles3
37e5c31af7Sopenharmony_ci{
38e5c31af7Sopenharmony_cinamespace Functional
39e5c31af7Sopenharmony_ci{
40e5c31af7Sopenharmony_ci
41e5c31af7Sopenharmony_ciusing std::vector;
42e5c31af7Sopenharmony_ciusing std::string;
43e5c31af7Sopenharmony_ciusing tcu::TestLog;
44e5c31af7Sopenharmony_ciusing namespace gls::ShaderExecUtil;
45e5c31af7Sopenharmony_ci
46e5c31af7Sopenharmony_ciusing tcu::Vec2;
47e5c31af7Sopenharmony_ciusing tcu::Vec3;
48e5c31af7Sopenharmony_ciusing tcu::Vec4;
49e5c31af7Sopenharmony_ciusing tcu::IVec2;
50e5c31af7Sopenharmony_ciusing tcu::IVec3;
51e5c31af7Sopenharmony_ciusing tcu::IVec4;
52e5c31af7Sopenharmony_ci
53e5c31af7Sopenharmony_ci// Utilities
54e5c31af7Sopenharmony_ci
55e5c31af7Sopenharmony_citemplate<typename T, int Size>
56e5c31af7Sopenharmony_cistruct VecArrayAccess
57e5c31af7Sopenharmony_ci{
58e5c31af7Sopenharmony_cipublic:
59e5c31af7Sopenharmony_ci									VecArrayAccess	(const void* ptr) : m_array((tcu::Vector<T, Size>*)ptr) {}
60e5c31af7Sopenharmony_ci									~VecArrayAccess	(void) {}
61e5c31af7Sopenharmony_ci
62e5c31af7Sopenharmony_ci	const tcu::Vector<T, Size>&		operator[]		(size_t offset) const	{ return m_array[offset];	}
63e5c31af7Sopenharmony_ci	tcu::Vector<T, Size>&			operator[]		(size_t offset)			{ return m_array[offset];	}
64e5c31af7Sopenharmony_ci
65e5c31af7Sopenharmony_ciprivate:
66e5c31af7Sopenharmony_ci	tcu::Vector<T, Size>*			m_array;
67e5c31af7Sopenharmony_ci};
68e5c31af7Sopenharmony_ci
69e5c31af7Sopenharmony_citemplate<typename T, int Size>
70e5c31af7Sopenharmony_cistatic void fillRandomVectors (de::Random& rnd, const tcu::Vector<T, Size>& minValue, const tcu::Vector<T, Size>& maxValue, void* dst, int numValues, int offset = 0)
71e5c31af7Sopenharmony_ci{
72e5c31af7Sopenharmony_ci	VecArrayAccess<T, Size> access(dst);
73e5c31af7Sopenharmony_ci	for (int ndx = 0; ndx < numValues; ndx++)
74e5c31af7Sopenharmony_ci		access[offset + ndx] = tcu::randomVector<T, Size>(rnd, minValue, maxValue);
75e5c31af7Sopenharmony_ci}
76e5c31af7Sopenharmony_ci
77e5c31af7Sopenharmony_citemplate<typename T>
78e5c31af7Sopenharmony_cistatic void fillRandomScalars (de::Random& rnd, T minValue, T maxValue, void* dst, int numValues, int offset = 0)
79e5c31af7Sopenharmony_ci{
80e5c31af7Sopenharmony_ci	T* typedPtr = (T*)dst;
81e5c31af7Sopenharmony_ci	for (int ndx = 0; ndx < numValues; ndx++)
82e5c31af7Sopenharmony_ci		typedPtr[offset + ndx] = de::randomScalar<T>(rnd, minValue, maxValue);
83e5c31af7Sopenharmony_ci}
84e5c31af7Sopenharmony_ci
85e5c31af7Sopenharmony_ciinline int numBitsLostInOp (float input, float output)
86e5c31af7Sopenharmony_ci{
87e5c31af7Sopenharmony_ci	const int	inExp		= tcu::Float32(input).exponent();
88e5c31af7Sopenharmony_ci	const int	outExp		= tcu::Float32(output).exponent();
89e5c31af7Sopenharmony_ci
90e5c31af7Sopenharmony_ci	return de::max(0, inExp-outExp); // Lost due to mantissa shift.
91e5c31af7Sopenharmony_ci}
92e5c31af7Sopenharmony_ci
93e5c31af7Sopenharmony_ciinline deUint32 getUlpDiff (float a, float b)
94e5c31af7Sopenharmony_ci{
95e5c31af7Sopenharmony_ci	const deUint32	aBits	= tcu::Float32(a).bits();
96e5c31af7Sopenharmony_ci	const deUint32	bBits	= tcu::Float32(b).bits();
97e5c31af7Sopenharmony_ci	return aBits > bBits ? aBits - bBits : bBits - aBits;
98e5c31af7Sopenharmony_ci}
99e5c31af7Sopenharmony_ci
100e5c31af7Sopenharmony_ciinline deUint32 getUlpDiffIgnoreZeroSign (float a, float b)
101e5c31af7Sopenharmony_ci{
102e5c31af7Sopenharmony_ci	if (tcu::Float32(a).isZero())
103e5c31af7Sopenharmony_ci		return getUlpDiff(tcu::Float32::construct(tcu::Float32(b).sign(), 0, 0).asFloat(), b);
104e5c31af7Sopenharmony_ci	else if (tcu::Float32(b).isZero())
105e5c31af7Sopenharmony_ci		return getUlpDiff(a, tcu::Float32::construct(tcu::Float32(a).sign(), 0, 0).asFloat());
106e5c31af7Sopenharmony_ci	else
107e5c31af7Sopenharmony_ci		return getUlpDiff(a, b);
108e5c31af7Sopenharmony_ci}
109e5c31af7Sopenharmony_ci
110e5c31af7Sopenharmony_ciinline bool supportsSignedZero (glu::Precision precision)
111e5c31af7Sopenharmony_ci{
112e5c31af7Sopenharmony_ci	// \note GLSL ES 3.0 doesn't really require support for -0, but we require it for highp
113e5c31af7Sopenharmony_ci	//		 as it is very widely supported.
114e5c31af7Sopenharmony_ci	return precision == glu::PRECISION_HIGHP;
115e5c31af7Sopenharmony_ci}
116e5c31af7Sopenharmony_ci
117e5c31af7Sopenharmony_ciinline float getEpsFromMaxUlpDiff (float value, deUint32 ulpDiff)
118e5c31af7Sopenharmony_ci{
119e5c31af7Sopenharmony_ci	const int exp = tcu::Float32(value).exponent();
120e5c31af7Sopenharmony_ci	return tcu::Float32::construct(+1, exp, (1u<<23) | ulpDiff).asFloat() - tcu::Float32::construct(+1, exp, 1u<<23).asFloat();
121e5c31af7Sopenharmony_ci}
122e5c31af7Sopenharmony_ci
123e5c31af7Sopenharmony_ciinline deUint32 getMaxUlpDiffFromBits (int numAccurateBits)
124e5c31af7Sopenharmony_ci{
125e5c31af7Sopenharmony_ci	const int		numGarbageBits	= 23-numAccurateBits;
126e5c31af7Sopenharmony_ci	const deUint32	mask			= (1u<<numGarbageBits)-1u;
127e5c31af7Sopenharmony_ci
128e5c31af7Sopenharmony_ci	return mask;
129e5c31af7Sopenharmony_ci}
130e5c31af7Sopenharmony_ci
131e5c31af7Sopenharmony_ciinline float getEpsFromBits (float value, int numAccurateBits)
132e5c31af7Sopenharmony_ci{
133e5c31af7Sopenharmony_ci	return getEpsFromMaxUlpDiff(value, getMaxUlpDiffFromBits(numAccurateBits));
134e5c31af7Sopenharmony_ci}
135e5c31af7Sopenharmony_ci
136e5c31af7Sopenharmony_cistatic int getMinMantissaBits (glu::Precision precision)
137e5c31af7Sopenharmony_ci{
138e5c31af7Sopenharmony_ci	const int bits[] =
139e5c31af7Sopenharmony_ci	{
140e5c31af7Sopenharmony_ci		7,		// lowp
141e5c31af7Sopenharmony_ci		10,		// mediump
142e5c31af7Sopenharmony_ci		23		// highp
143e5c31af7Sopenharmony_ci	};
144e5c31af7Sopenharmony_ci	DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(bits) == glu::PRECISION_LAST);
145e5c31af7Sopenharmony_ci	DE_ASSERT(de::inBounds<int>(precision, 0, DE_LENGTH_OF_ARRAY(bits)));
146e5c31af7Sopenharmony_ci	return bits[precision];
147e5c31af7Sopenharmony_ci}
148e5c31af7Sopenharmony_ci
149e5c31af7Sopenharmony_ci// CommonFunctionCase
150e5c31af7Sopenharmony_ci
151e5c31af7Sopenharmony_ciclass CommonFunctionCase : public TestCase
152e5c31af7Sopenharmony_ci{
153e5c31af7Sopenharmony_cipublic:
154e5c31af7Sopenharmony_ci							CommonFunctionCase		(Context& context, const char* name, const char* description, glu::ShaderType shaderType);
155e5c31af7Sopenharmony_ci							~CommonFunctionCase		(void);
156e5c31af7Sopenharmony_ci
157e5c31af7Sopenharmony_ci	void					init					(void);
158e5c31af7Sopenharmony_ci	void					deinit					(void);
159e5c31af7Sopenharmony_ci	IterateResult			iterate					(void);
160e5c31af7Sopenharmony_ci
161e5c31af7Sopenharmony_ciprotected:
162e5c31af7Sopenharmony_ci							CommonFunctionCase		(const CommonFunctionCase& other);
163e5c31af7Sopenharmony_ci	CommonFunctionCase&		operator=				(const CommonFunctionCase& other);
164e5c31af7Sopenharmony_ci
165e5c31af7Sopenharmony_ci	virtual void			getInputValues			(int numValues, void* const* values) const = 0;
166e5c31af7Sopenharmony_ci	virtual bool			compare					(const void* const* inputs, const void* const* outputs) = 0;
167e5c31af7Sopenharmony_ci
168e5c31af7Sopenharmony_ci	glu::ShaderType			m_shaderType;
169e5c31af7Sopenharmony_ci	ShaderSpec				m_spec;
170e5c31af7Sopenharmony_ci	int						m_numValues;
171e5c31af7Sopenharmony_ci
172e5c31af7Sopenharmony_ci	std::ostringstream		m_failMsg;				//!< Comparison failure help message.
173e5c31af7Sopenharmony_ci
174e5c31af7Sopenharmony_ciprivate:
175e5c31af7Sopenharmony_ci	ShaderExecutor*			m_executor;
176e5c31af7Sopenharmony_ci};
177e5c31af7Sopenharmony_ci
178e5c31af7Sopenharmony_ciCommonFunctionCase::CommonFunctionCase (Context& context, const char* name, const char* description, glu::ShaderType shaderType)
179e5c31af7Sopenharmony_ci	: TestCase		(context, name, description)
180e5c31af7Sopenharmony_ci	, m_shaderType	(shaderType)
181e5c31af7Sopenharmony_ci	, m_numValues	(100)
182e5c31af7Sopenharmony_ci	, m_executor	(DE_NULL)
183e5c31af7Sopenharmony_ci{
184e5c31af7Sopenharmony_ci	m_spec.version = glu::GLSL_VERSION_300_ES;
185e5c31af7Sopenharmony_ci}
186e5c31af7Sopenharmony_ci
187e5c31af7Sopenharmony_ciCommonFunctionCase::~CommonFunctionCase (void)
188e5c31af7Sopenharmony_ci{
189e5c31af7Sopenharmony_ci	CommonFunctionCase::deinit();
190e5c31af7Sopenharmony_ci}
191e5c31af7Sopenharmony_ci
192e5c31af7Sopenharmony_civoid CommonFunctionCase::init (void)
193e5c31af7Sopenharmony_ci{
194e5c31af7Sopenharmony_ci	DE_ASSERT(!m_executor);
195e5c31af7Sopenharmony_ci
196e5c31af7Sopenharmony_ci	m_executor = createExecutor(m_context.getRenderContext(), m_shaderType, m_spec);
197e5c31af7Sopenharmony_ci	m_testCtx.getLog() << m_executor;
198e5c31af7Sopenharmony_ci
199e5c31af7Sopenharmony_ci	if (!m_executor->isOk())
200e5c31af7Sopenharmony_ci		throw tcu::TestError("Compile failed");
201e5c31af7Sopenharmony_ci}
202e5c31af7Sopenharmony_ci
203e5c31af7Sopenharmony_civoid CommonFunctionCase::deinit (void)
204e5c31af7Sopenharmony_ci{
205e5c31af7Sopenharmony_ci	delete m_executor;
206e5c31af7Sopenharmony_ci	m_executor = DE_NULL;
207e5c31af7Sopenharmony_ci}
208e5c31af7Sopenharmony_ci
209e5c31af7Sopenharmony_cistatic vector<int> getScalarSizes (const vector<Symbol>& symbols)
210e5c31af7Sopenharmony_ci{
211e5c31af7Sopenharmony_ci	vector<int> sizes(symbols.size());
212e5c31af7Sopenharmony_ci	for (int ndx = 0; ndx < (int)symbols.size(); ++ndx)
213e5c31af7Sopenharmony_ci		sizes[ndx] = symbols[ndx].varType.getScalarSize();
214e5c31af7Sopenharmony_ci	return sizes;
215e5c31af7Sopenharmony_ci}
216e5c31af7Sopenharmony_ci
217e5c31af7Sopenharmony_cistatic int computeTotalScalarSize (const vector<Symbol>& symbols)
218e5c31af7Sopenharmony_ci{
219e5c31af7Sopenharmony_ci	int totalSize = 0;
220e5c31af7Sopenharmony_ci	for (vector<Symbol>::const_iterator sym = symbols.begin(); sym != symbols.end(); ++sym)
221e5c31af7Sopenharmony_ci		totalSize += sym->varType.getScalarSize();
222e5c31af7Sopenharmony_ci	return totalSize;
223e5c31af7Sopenharmony_ci}
224e5c31af7Sopenharmony_ci
225e5c31af7Sopenharmony_cistatic vector<void*> getInputOutputPointers (const vector<Symbol>& symbols, vector<deUint32>& data, const int numValues)
226e5c31af7Sopenharmony_ci{
227e5c31af7Sopenharmony_ci	vector<void*>	pointers		(symbols.size());
228e5c31af7Sopenharmony_ci	int				curScalarOffset	= 0;
229e5c31af7Sopenharmony_ci
230e5c31af7Sopenharmony_ci	for (int varNdx = 0; varNdx < (int)symbols.size(); ++varNdx)
231e5c31af7Sopenharmony_ci	{
232e5c31af7Sopenharmony_ci		const Symbol&	var				= symbols[varNdx];
233e5c31af7Sopenharmony_ci		const int		scalarSize		= var.varType.getScalarSize();
234e5c31af7Sopenharmony_ci
235e5c31af7Sopenharmony_ci		// Uses planar layout as input/output specs do not support strides.
236e5c31af7Sopenharmony_ci		pointers[varNdx] = &data[curScalarOffset];
237e5c31af7Sopenharmony_ci		curScalarOffset += scalarSize*numValues;
238e5c31af7Sopenharmony_ci	}
239e5c31af7Sopenharmony_ci
240e5c31af7Sopenharmony_ci	DE_ASSERT(curScalarOffset == (int)data.size());
241e5c31af7Sopenharmony_ci
242e5c31af7Sopenharmony_ci	return pointers;
243e5c31af7Sopenharmony_ci}
244e5c31af7Sopenharmony_ci
245e5c31af7Sopenharmony_ci// \todo [2013-08-08 pyry] Make generic utility and move to glu?
246e5c31af7Sopenharmony_ci
247e5c31af7Sopenharmony_cistruct HexFloat
248e5c31af7Sopenharmony_ci{
249e5c31af7Sopenharmony_ci	const float value;
250e5c31af7Sopenharmony_ci	HexFloat (const float value_) : value(value_) {}
251e5c31af7Sopenharmony_ci};
252e5c31af7Sopenharmony_ci
253e5c31af7Sopenharmony_cistd::ostream& operator<< (std::ostream& str, const HexFloat& v)
254e5c31af7Sopenharmony_ci{
255e5c31af7Sopenharmony_ci	return str << v.value << " / " << tcu::toHex(tcu::Float32(v.value).bits());
256e5c31af7Sopenharmony_ci}
257e5c31af7Sopenharmony_ci
258e5c31af7Sopenharmony_cistruct HexBool
259e5c31af7Sopenharmony_ci{
260e5c31af7Sopenharmony_ci	const deUint32 value;
261e5c31af7Sopenharmony_ci	HexBool (const deUint32 value_) : value(value_) {}
262e5c31af7Sopenharmony_ci};
263e5c31af7Sopenharmony_ci
264e5c31af7Sopenharmony_cistd::ostream& operator<< (std::ostream& str, const HexBool& v)
265e5c31af7Sopenharmony_ci{
266e5c31af7Sopenharmony_ci	return str << (v.value ? "true" : "false") << " / " << tcu::toHex(v.value);
267e5c31af7Sopenharmony_ci}
268e5c31af7Sopenharmony_ci
269e5c31af7Sopenharmony_cistruct VarValue
270e5c31af7Sopenharmony_ci{
271e5c31af7Sopenharmony_ci	const glu::VarType&	type;
272e5c31af7Sopenharmony_ci	const void*			value;
273e5c31af7Sopenharmony_ci
274e5c31af7Sopenharmony_ci	VarValue (const glu::VarType& type_, const void* value_) : type(type_), value(value_) {}
275e5c31af7Sopenharmony_ci};
276e5c31af7Sopenharmony_ci
277e5c31af7Sopenharmony_cistd::ostream& operator<< (std::ostream& str, const VarValue& varValue)
278e5c31af7Sopenharmony_ci{
279e5c31af7Sopenharmony_ci	DE_ASSERT(varValue.type.isBasicType());
280e5c31af7Sopenharmony_ci
281e5c31af7Sopenharmony_ci	const glu::DataType		basicType		= varValue.type.getBasicType();
282e5c31af7Sopenharmony_ci	const glu::DataType		scalarType		= glu::getDataTypeScalarType(basicType);
283e5c31af7Sopenharmony_ci	const int				numComponents	= glu::getDataTypeScalarSize(basicType);
284e5c31af7Sopenharmony_ci
285e5c31af7Sopenharmony_ci	if (numComponents > 1)
286e5c31af7Sopenharmony_ci		str << glu::getDataTypeName(basicType) << "(";
287e5c31af7Sopenharmony_ci
288e5c31af7Sopenharmony_ci	for (int compNdx = 0; compNdx < numComponents; compNdx++)
289e5c31af7Sopenharmony_ci	{
290e5c31af7Sopenharmony_ci		if (compNdx != 0)
291e5c31af7Sopenharmony_ci			str << ", ";
292e5c31af7Sopenharmony_ci
293e5c31af7Sopenharmony_ci		switch (scalarType)
294e5c31af7Sopenharmony_ci		{
295e5c31af7Sopenharmony_ci			case glu::TYPE_FLOAT:	str << HexFloat(((const float*)varValue.value)[compNdx]);			break;
296e5c31af7Sopenharmony_ci			case glu::TYPE_INT:		str << ((const deInt32*)varValue.value)[compNdx];					break;
297e5c31af7Sopenharmony_ci			case glu::TYPE_UINT:	str << tcu::toHex(((const deUint32*)varValue.value)[compNdx]);		break;
298e5c31af7Sopenharmony_ci			case glu::TYPE_BOOL:	str << HexBool(((const deUint32*)varValue.value)[compNdx]);			break;
299e5c31af7Sopenharmony_ci
300e5c31af7Sopenharmony_ci			default:
301e5c31af7Sopenharmony_ci				DE_ASSERT(false);
302e5c31af7Sopenharmony_ci		}
303e5c31af7Sopenharmony_ci	}
304e5c31af7Sopenharmony_ci
305e5c31af7Sopenharmony_ci	if (numComponents > 1)
306e5c31af7Sopenharmony_ci		str << ")";
307e5c31af7Sopenharmony_ci
308e5c31af7Sopenharmony_ci	return str;
309e5c31af7Sopenharmony_ci}
310e5c31af7Sopenharmony_ci
311e5c31af7Sopenharmony_ciCommonFunctionCase::IterateResult CommonFunctionCase::iterate (void)
312e5c31af7Sopenharmony_ci{
313e5c31af7Sopenharmony_ci	const int				numInputScalars			= computeTotalScalarSize(m_spec.inputs);
314e5c31af7Sopenharmony_ci	const int				numOutputScalars		= computeTotalScalarSize(m_spec.outputs);
315e5c31af7Sopenharmony_ci	vector<deUint32>		inputData				(numInputScalars * m_numValues);
316e5c31af7Sopenharmony_ci	vector<deUint32>		outputData				(numOutputScalars * m_numValues);
317e5c31af7Sopenharmony_ci	const vector<void*>		inputPointers			= getInputOutputPointers(m_spec.inputs, inputData, m_numValues);
318e5c31af7Sopenharmony_ci	const vector<void*>		outputPointers			= getInputOutputPointers(m_spec.outputs, outputData, m_numValues);
319e5c31af7Sopenharmony_ci
320e5c31af7Sopenharmony_ci	// Initialize input data.
321e5c31af7Sopenharmony_ci	getInputValues(m_numValues, &inputPointers[0]);
322e5c31af7Sopenharmony_ci
323e5c31af7Sopenharmony_ci	// Execute shader.
324e5c31af7Sopenharmony_ci	m_executor->useProgram();
325e5c31af7Sopenharmony_ci	m_executor->execute(m_numValues, &inputPointers[0], &outputPointers[0]);
326e5c31af7Sopenharmony_ci
327e5c31af7Sopenharmony_ci	// Compare results.
328e5c31af7Sopenharmony_ci	{
329e5c31af7Sopenharmony_ci		const vector<int>		inScalarSizes		= getScalarSizes(m_spec.inputs);
330e5c31af7Sopenharmony_ci		const vector<int>		outScalarSizes		= getScalarSizes(m_spec.outputs);
331e5c31af7Sopenharmony_ci		vector<void*>			curInputPtr			(inputPointers.size());
332e5c31af7Sopenharmony_ci		vector<void*>			curOutputPtr		(outputPointers.size());
333e5c31af7Sopenharmony_ci		int						numFailed			= 0;
334e5c31af7Sopenharmony_ci
335e5c31af7Sopenharmony_ci		for (int valNdx = 0; valNdx < m_numValues; valNdx++)
336e5c31af7Sopenharmony_ci		{
337e5c31af7Sopenharmony_ci			// Set up pointers for comparison.
338e5c31af7Sopenharmony_ci			for (int inNdx = 0; inNdx < (int)curInputPtr.size(); ++inNdx)
339e5c31af7Sopenharmony_ci				curInputPtr[inNdx] = (deUint32*)inputPointers[inNdx] + inScalarSizes[inNdx]*valNdx;
340e5c31af7Sopenharmony_ci
341e5c31af7Sopenharmony_ci			for (int outNdx = 0; outNdx < (int)curOutputPtr.size(); ++outNdx)
342e5c31af7Sopenharmony_ci				curOutputPtr[outNdx] = (deUint32*)outputPointers[outNdx] + outScalarSizes[outNdx]*valNdx;
343e5c31af7Sopenharmony_ci
344e5c31af7Sopenharmony_ci			if (!compare(&curInputPtr[0], &curOutputPtr[0]))
345e5c31af7Sopenharmony_ci			{
346e5c31af7Sopenharmony_ci				// \todo [2013-08-08 pyry] We probably want to log reference value as well?
347e5c31af7Sopenharmony_ci
348e5c31af7Sopenharmony_ci				m_testCtx.getLog() << TestLog::Message << "ERROR: comparison failed for value " << valNdx << ":\n  " << m_failMsg.str() << TestLog::EndMessage;
349e5c31af7Sopenharmony_ci
350e5c31af7Sopenharmony_ci				m_testCtx.getLog() << TestLog::Message << "  inputs:" << TestLog::EndMessage;
351e5c31af7Sopenharmony_ci				for (int inNdx = 0; inNdx < (int)curInputPtr.size(); inNdx++)
352e5c31af7Sopenharmony_ci					m_testCtx.getLog() << TestLog::Message << "    " << m_spec.inputs[inNdx].name << " = "
353e5c31af7Sopenharmony_ci														   << VarValue(m_spec.inputs[inNdx].varType, curInputPtr[inNdx])
354e5c31af7Sopenharmony_ci									   << TestLog::EndMessage;
355e5c31af7Sopenharmony_ci
356e5c31af7Sopenharmony_ci				m_testCtx.getLog() << TestLog::Message << "  outputs:" << TestLog::EndMessage;
357e5c31af7Sopenharmony_ci				for (int outNdx = 0; outNdx < (int)curOutputPtr.size(); outNdx++)
358e5c31af7Sopenharmony_ci					m_testCtx.getLog() << TestLog::Message << "    " << m_spec.outputs[outNdx].name << " = "
359e5c31af7Sopenharmony_ci														   << VarValue(m_spec.outputs[outNdx].varType, curOutputPtr[outNdx])
360e5c31af7Sopenharmony_ci									   << TestLog::EndMessage;
361e5c31af7Sopenharmony_ci
362e5c31af7Sopenharmony_ci				m_failMsg.str("");
363e5c31af7Sopenharmony_ci				m_failMsg.clear();
364e5c31af7Sopenharmony_ci				numFailed += 1;
365e5c31af7Sopenharmony_ci			}
366e5c31af7Sopenharmony_ci		}
367e5c31af7Sopenharmony_ci
368e5c31af7Sopenharmony_ci		m_testCtx.getLog() << TestLog::Message << (m_numValues - numFailed) << " / " << m_numValues << " values passed" << TestLog::EndMessage;
369e5c31af7Sopenharmony_ci
370e5c31af7Sopenharmony_ci		m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS	: QP_TEST_RESULT_FAIL,
371e5c31af7Sopenharmony_ci								numFailed == 0 ? "Pass"					: "Result comparison failed");
372e5c31af7Sopenharmony_ci	}
373e5c31af7Sopenharmony_ci
374e5c31af7Sopenharmony_ci	return STOP;
375e5c31af7Sopenharmony_ci}
376e5c31af7Sopenharmony_ci
377e5c31af7Sopenharmony_cistatic std::string getCommonFuncCaseName (glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
378e5c31af7Sopenharmony_ci{
379e5c31af7Sopenharmony_ci	return string(glu::getDataTypeName(baseType)) + getPrecisionPostfix(precision) + getShaderTypePostfix(shaderType);
380e5c31af7Sopenharmony_ci}
381e5c31af7Sopenharmony_ci
382e5c31af7Sopenharmony_ciclass AbsCase : public CommonFunctionCase
383e5c31af7Sopenharmony_ci{
384e5c31af7Sopenharmony_cipublic:
385e5c31af7Sopenharmony_ci	AbsCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
386e5c31af7Sopenharmony_ci		: CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "abs", shaderType)
387e5c31af7Sopenharmony_ci	{
388e5c31af7Sopenharmony_ci		m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
389e5c31af7Sopenharmony_ci		m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision)));
390e5c31af7Sopenharmony_ci		m_spec.source = "out0 = abs(in0);";
391e5c31af7Sopenharmony_ci	}
392e5c31af7Sopenharmony_ci
393e5c31af7Sopenharmony_ci	void getInputValues (int numValues, void* const* values) const
394e5c31af7Sopenharmony_ci	{
395e5c31af7Sopenharmony_ci		const Vec2 floatRanges[] =
396e5c31af7Sopenharmony_ci		{
397e5c31af7Sopenharmony_ci			Vec2(-2.0f,		2.0f),	// lowp
398e5c31af7Sopenharmony_ci			Vec2(-1e3f,		1e3f),	// mediump
399e5c31af7Sopenharmony_ci			Vec2(-1e7f,		1e7f)	// highp
400e5c31af7Sopenharmony_ci		};
401e5c31af7Sopenharmony_ci		const IVec2 intRanges[] =
402e5c31af7Sopenharmony_ci		{
403e5c31af7Sopenharmony_ci			IVec2(-(1<<7)+1,	(1<<7)-1),
404e5c31af7Sopenharmony_ci			IVec2(-(1<<15)+1,	(1<<15)-1),
405e5c31af7Sopenharmony_ci			IVec2(0x80000001,	0x7fffffff)
406e5c31af7Sopenharmony_ci		};
407e5c31af7Sopenharmony_ci
408e5c31af7Sopenharmony_ci		de::Random				rnd			(deStringHash(getName()) ^ 0x235facu);
409e5c31af7Sopenharmony_ci		const glu::DataType		type		= m_spec.inputs[0].varType.getBasicType();
410e5c31af7Sopenharmony_ci		const glu::Precision	precision	= m_spec.inputs[0].varType.getPrecision();
411e5c31af7Sopenharmony_ci		const int				scalarSize	= glu::getDataTypeScalarSize(type);
412e5c31af7Sopenharmony_ci
413e5c31af7Sopenharmony_ci		if (glu::isDataTypeFloatOrVec(type))
414e5c31af7Sopenharmony_ci			fillRandomScalars(rnd, floatRanges[precision].x(), floatRanges[precision].y(), values[0], numValues*scalarSize);
415e5c31af7Sopenharmony_ci		else
416e5c31af7Sopenharmony_ci			fillRandomScalars(rnd, intRanges[precision].x(), intRanges[precision].y(), values[0], numValues*scalarSize);
417e5c31af7Sopenharmony_ci	}
418e5c31af7Sopenharmony_ci
419e5c31af7Sopenharmony_ci	bool compare (const void* const* inputs, const void* const* outputs)
420e5c31af7Sopenharmony_ci	{
421e5c31af7Sopenharmony_ci		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
422e5c31af7Sopenharmony_ci		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
423e5c31af7Sopenharmony_ci		const int				scalarSize		= glu::getDataTypeScalarSize(type);
424e5c31af7Sopenharmony_ci
425e5c31af7Sopenharmony_ci		if (glu::isDataTypeFloatOrVec(type))
426e5c31af7Sopenharmony_ci		{
427e5c31af7Sopenharmony_ci			const int		mantissaBits	= getMinMantissaBits(precision);
428e5c31af7Sopenharmony_ci			const deUint32	maxUlpDiff		= (1u<<(23-mantissaBits))-1u;
429e5c31af7Sopenharmony_ci
430e5c31af7Sopenharmony_ci			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
431e5c31af7Sopenharmony_ci			{
432e5c31af7Sopenharmony_ci				const float		in0			= ((const float*)inputs[0])[compNdx];
433e5c31af7Sopenharmony_ci				const float		out0		= ((const float*)outputs[0])[compNdx];
434e5c31af7Sopenharmony_ci				const float		ref0		= de::abs(in0);
435e5c31af7Sopenharmony_ci				const deUint32	ulpDiff0	= getUlpDiff(out0, ref0);
436e5c31af7Sopenharmony_ci
437e5c31af7Sopenharmony_ci				if (ulpDiff0 > maxUlpDiff)
438e5c31af7Sopenharmony_ci				{
439e5c31af7Sopenharmony_ci					m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref0) << " with ULP threshold " << maxUlpDiff << ", got ULP diff " << ulpDiff0;
440e5c31af7Sopenharmony_ci					return false;
441e5c31af7Sopenharmony_ci				}
442e5c31af7Sopenharmony_ci			}
443e5c31af7Sopenharmony_ci		}
444e5c31af7Sopenharmony_ci		else
445e5c31af7Sopenharmony_ci		{
446e5c31af7Sopenharmony_ci			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
447e5c31af7Sopenharmony_ci			{
448e5c31af7Sopenharmony_ci				const int	in0		= ((const int*)inputs[0])[compNdx];
449e5c31af7Sopenharmony_ci				const int	out0	= ((const int*)outputs[0])[compNdx];
450e5c31af7Sopenharmony_ci				const int	ref0	= de::abs(in0);
451e5c31af7Sopenharmony_ci
452e5c31af7Sopenharmony_ci				if (out0 != ref0)
453e5c31af7Sopenharmony_ci				{
454e5c31af7Sopenharmony_ci					m_failMsg << "Expected [" << compNdx << "] = " << ref0;
455e5c31af7Sopenharmony_ci					return false;
456e5c31af7Sopenharmony_ci				}
457e5c31af7Sopenharmony_ci			}
458e5c31af7Sopenharmony_ci		}
459e5c31af7Sopenharmony_ci
460e5c31af7Sopenharmony_ci		return true;
461e5c31af7Sopenharmony_ci	}
462e5c31af7Sopenharmony_ci};
463e5c31af7Sopenharmony_ci
464e5c31af7Sopenharmony_ciclass SignCase : public CommonFunctionCase
465e5c31af7Sopenharmony_ci{
466e5c31af7Sopenharmony_cipublic:
467e5c31af7Sopenharmony_ci	SignCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
468e5c31af7Sopenharmony_ci		: CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "sign", shaderType)
469e5c31af7Sopenharmony_ci	{
470e5c31af7Sopenharmony_ci		m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
471e5c31af7Sopenharmony_ci		m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision)));
472e5c31af7Sopenharmony_ci		m_spec.source = "out0 = sign(in0);";
473e5c31af7Sopenharmony_ci	}
474e5c31af7Sopenharmony_ci
475e5c31af7Sopenharmony_ci	void getInputValues (int numValues, void* const* values) const
476e5c31af7Sopenharmony_ci	{
477e5c31af7Sopenharmony_ci		const Vec2 floatRanges[] =
478e5c31af7Sopenharmony_ci		{
479e5c31af7Sopenharmony_ci			Vec2(-2.0f,		2.0f),	// lowp
480e5c31af7Sopenharmony_ci			Vec2(-1e4f,		1e4f),	// mediump	- note: may end up as inf
481e5c31af7Sopenharmony_ci			Vec2(-1e8f,		1e8f)	// highp	- note: may end up as inf
482e5c31af7Sopenharmony_ci		};
483e5c31af7Sopenharmony_ci		const IVec2 intRanges[] =
484e5c31af7Sopenharmony_ci		{
485e5c31af7Sopenharmony_ci			IVec2(-(1<<7),		(1<<7)-1),
486e5c31af7Sopenharmony_ci			IVec2(-(1<<15),		(1<<15)-1),
487e5c31af7Sopenharmony_ci			IVec2(0x80000000,	0x7fffffff)
488e5c31af7Sopenharmony_ci		};
489e5c31af7Sopenharmony_ci
490e5c31af7Sopenharmony_ci		de::Random				rnd			(deStringHash(getName()) ^ 0x324u);
491e5c31af7Sopenharmony_ci		const glu::DataType		type		= m_spec.inputs[0].varType.getBasicType();
492e5c31af7Sopenharmony_ci		const glu::Precision	precision	= m_spec.inputs[0].varType.getPrecision();
493e5c31af7Sopenharmony_ci		const int				scalarSize	= glu::getDataTypeScalarSize(type);
494e5c31af7Sopenharmony_ci
495e5c31af7Sopenharmony_ci		if (glu::isDataTypeFloatOrVec(type))
496e5c31af7Sopenharmony_ci		{
497e5c31af7Sopenharmony_ci			// Special cases.
498e5c31af7Sopenharmony_ci			std::fill((float*)values[0],				(float*)values[0] + scalarSize,		+1.0f);
499e5c31af7Sopenharmony_ci			std::fill((float*)values[0] + scalarSize*1,	(float*)values[0] + scalarSize*2,	-1.0f);
500e5c31af7Sopenharmony_ci			std::fill((float*)values[0] + scalarSize*2,	(float*)values[0] + scalarSize*3,	0.0f);
501e5c31af7Sopenharmony_ci			fillRandomScalars(rnd, floatRanges[precision].x(), floatRanges[precision].y(), (float*)values[0] + scalarSize*3, (numValues-3)*scalarSize);
502e5c31af7Sopenharmony_ci		}
503e5c31af7Sopenharmony_ci		else
504e5c31af7Sopenharmony_ci		{
505e5c31af7Sopenharmony_ci			std::fill((int*)values[0],					(int*)values[0] + scalarSize,		+1);
506e5c31af7Sopenharmony_ci			std::fill((int*)values[0] + scalarSize*1,	(int*)values[0] + scalarSize*2,		-1);
507e5c31af7Sopenharmony_ci			std::fill((int*)values[0] + scalarSize*2,	(int*)values[0] + scalarSize*3,		0);
508e5c31af7Sopenharmony_ci			fillRandomScalars(rnd, intRanges[precision].x(), intRanges[precision].y(), (int*)values[0] + scalarSize*3, (numValues-3)*scalarSize);
509e5c31af7Sopenharmony_ci		}
510e5c31af7Sopenharmony_ci	}
511e5c31af7Sopenharmony_ci
512e5c31af7Sopenharmony_ci	bool compare (const void* const* inputs, const void* const* outputs)
513e5c31af7Sopenharmony_ci	{
514e5c31af7Sopenharmony_ci		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
515e5c31af7Sopenharmony_ci		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
516e5c31af7Sopenharmony_ci		const int				scalarSize		= glu::getDataTypeScalarSize(type);
517e5c31af7Sopenharmony_ci
518e5c31af7Sopenharmony_ci		if (glu::isDataTypeFloatOrVec(type))
519e5c31af7Sopenharmony_ci		{
520e5c31af7Sopenharmony_ci			// Both highp and mediump should be able to represent -1, 0, and +1 exactly
521e5c31af7Sopenharmony_ci			const deUint32 maxUlpDiff = precision == glu::PRECISION_LOWP ? getMaxUlpDiffFromBits(getMinMantissaBits(precision)) : 0;
522e5c31af7Sopenharmony_ci
523e5c31af7Sopenharmony_ci			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
524e5c31af7Sopenharmony_ci			{
525e5c31af7Sopenharmony_ci				const float		in0			= ((const float*)inputs[0])[compNdx];
526e5c31af7Sopenharmony_ci				const float		out0		= ((const float*)outputs[0])[compNdx];
527e5c31af7Sopenharmony_ci				const float		ref0		= in0 < 0.0f ? -1.0f :
528e5c31af7Sopenharmony_ci											  in0 > 0.0f ? +1.0f : 0.0f;
529e5c31af7Sopenharmony_ci				const deUint32	ulpDiff0	= getUlpDiff(out0, ref0);
530e5c31af7Sopenharmony_ci
531e5c31af7Sopenharmony_ci				if (ulpDiff0 > maxUlpDiff)
532e5c31af7Sopenharmony_ci				{
533e5c31af7Sopenharmony_ci					m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref0) << " with ULP threshold " << maxUlpDiff << ", got ULP diff " << ulpDiff0;
534e5c31af7Sopenharmony_ci					return false;
535e5c31af7Sopenharmony_ci				}
536e5c31af7Sopenharmony_ci			}
537e5c31af7Sopenharmony_ci		}
538e5c31af7Sopenharmony_ci		else
539e5c31af7Sopenharmony_ci		{
540e5c31af7Sopenharmony_ci			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
541e5c31af7Sopenharmony_ci			{
542e5c31af7Sopenharmony_ci				const int	in0		= ((const int*)inputs[0])[compNdx];
543e5c31af7Sopenharmony_ci				const int	out0	= ((const int*)outputs[0])[compNdx];
544e5c31af7Sopenharmony_ci				const int	ref0	= in0 < 0 ? -1 :
545e5c31af7Sopenharmony_ci									  in0 > 0 ? +1 : 0;
546e5c31af7Sopenharmony_ci
547e5c31af7Sopenharmony_ci				if (out0 != ref0)
548e5c31af7Sopenharmony_ci				{
549e5c31af7Sopenharmony_ci					m_failMsg << "Expected [" << compNdx << "] = " << ref0;
550e5c31af7Sopenharmony_ci					return false;
551e5c31af7Sopenharmony_ci				}
552e5c31af7Sopenharmony_ci			}
553e5c31af7Sopenharmony_ci		}
554e5c31af7Sopenharmony_ci
555e5c31af7Sopenharmony_ci		return true;
556e5c31af7Sopenharmony_ci	}
557e5c31af7Sopenharmony_ci};
558e5c31af7Sopenharmony_ci
559e5c31af7Sopenharmony_cistatic float roundEven (float v)
560e5c31af7Sopenharmony_ci{
561e5c31af7Sopenharmony_ci	const float		q			= deFloatFrac(v);
562e5c31af7Sopenharmony_ci	const int		truncated	= int(v-q);
563e5c31af7Sopenharmony_ci	const int		rounded		= (q > 0.5f)							? (truncated + 1) :	// Rounded up
564e5c31af7Sopenharmony_ci									(q == 0.5f && (truncated % 2 != 0))	? (truncated + 1) :	// Round to nearest even at 0.5
565e5c31af7Sopenharmony_ci									truncated;												// Rounded down
566e5c31af7Sopenharmony_ci
567e5c31af7Sopenharmony_ci	return float(rounded);
568e5c31af7Sopenharmony_ci}
569e5c31af7Sopenharmony_ci
570e5c31af7Sopenharmony_ciclass RoundEvenCase : public CommonFunctionCase
571e5c31af7Sopenharmony_ci{
572e5c31af7Sopenharmony_cipublic:
573e5c31af7Sopenharmony_ci	RoundEvenCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
574e5c31af7Sopenharmony_ci		: CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "roundEven", shaderType)
575e5c31af7Sopenharmony_ci	{
576e5c31af7Sopenharmony_ci		m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
577e5c31af7Sopenharmony_ci		m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision)));
578e5c31af7Sopenharmony_ci		m_spec.source = "out0 = roundEven(in0);";
579e5c31af7Sopenharmony_ci	}
580e5c31af7Sopenharmony_ci
581e5c31af7Sopenharmony_ci	void getInputValues (int numValues, void* const* values) const
582e5c31af7Sopenharmony_ci	{
583e5c31af7Sopenharmony_ci		const Vec2 ranges[] =
584e5c31af7Sopenharmony_ci		{
585e5c31af7Sopenharmony_ci			Vec2(-2.0f,		2.0f),	// lowp
586e5c31af7Sopenharmony_ci			Vec2(-1e3f,		1e3f),	// mediump
587e5c31af7Sopenharmony_ci			Vec2(-1e7f,		1e7f)	// highp
588e5c31af7Sopenharmony_ci		};
589e5c31af7Sopenharmony_ci
590e5c31af7Sopenharmony_ci		de::Random				rnd				(deStringHash(getName()) ^ 0xac23fu);
591e5c31af7Sopenharmony_ci		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
592e5c31af7Sopenharmony_ci		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
593e5c31af7Sopenharmony_ci		const int				scalarSize		= glu::getDataTypeScalarSize(type);
594e5c31af7Sopenharmony_ci		int						numSpecialCases	= 0;
595e5c31af7Sopenharmony_ci
596e5c31af7Sopenharmony_ci		// Special cases.
597e5c31af7Sopenharmony_ci		if (precision != glu::PRECISION_LOWP)
598e5c31af7Sopenharmony_ci		{
599e5c31af7Sopenharmony_ci			DE_ASSERT(numValues >= 20);
600e5c31af7Sopenharmony_ci			for (int ndx = 0; ndx < 20; ndx++)
601e5c31af7Sopenharmony_ci			{
602e5c31af7Sopenharmony_ci				const float v = de::clamp(float(ndx) - 10.5f, ranges[precision].x(), ranges[precision].y());
603e5c31af7Sopenharmony_ci				std::fill((float*)values[0], (float*)values[0] + scalarSize, v);
604e5c31af7Sopenharmony_ci				numSpecialCases += 1;
605e5c31af7Sopenharmony_ci			}
606e5c31af7Sopenharmony_ci		}
607e5c31af7Sopenharmony_ci
608e5c31af7Sopenharmony_ci		// Random cases.
609e5c31af7Sopenharmony_ci		fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), (float*)values[0] + numSpecialCases*scalarSize, (numValues-numSpecialCases)*scalarSize);
610e5c31af7Sopenharmony_ci
611e5c31af7Sopenharmony_ci		// If precision is mediump, make sure values can be represented in fp16 exactly
612e5c31af7Sopenharmony_ci		if (precision == glu::PRECISION_MEDIUMP)
613e5c31af7Sopenharmony_ci		{
614e5c31af7Sopenharmony_ci			for (int ndx = 0; ndx < numValues*scalarSize; ndx++)
615e5c31af7Sopenharmony_ci				((float*)values[0])[ndx] = tcu::Float16(((float*)values[0])[ndx]).asFloat();
616e5c31af7Sopenharmony_ci		}
617e5c31af7Sopenharmony_ci	}
618e5c31af7Sopenharmony_ci
619e5c31af7Sopenharmony_ci	bool compare (const void* const* inputs, const void* const* outputs)
620e5c31af7Sopenharmony_ci	{
621e5c31af7Sopenharmony_ci		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
622e5c31af7Sopenharmony_ci		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
623e5c31af7Sopenharmony_ci		const bool				hasSignedZero	= supportsSignedZero(precision);
624e5c31af7Sopenharmony_ci		const int				scalarSize		= glu::getDataTypeScalarSize(type);
625e5c31af7Sopenharmony_ci
626e5c31af7Sopenharmony_ci		if (precision == glu::PRECISION_HIGHP || precision == glu::PRECISION_MEDIUMP)
627e5c31af7Sopenharmony_ci		{
628e5c31af7Sopenharmony_ci			// Require exact rounding result.
629e5c31af7Sopenharmony_ci			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
630e5c31af7Sopenharmony_ci			{
631e5c31af7Sopenharmony_ci				const float		in0			= ((const float*)inputs[0])[compNdx];
632e5c31af7Sopenharmony_ci				const float		out0		= ((const float*)outputs[0])[compNdx];
633e5c31af7Sopenharmony_ci				const float		ref			= roundEven(in0);
634e5c31af7Sopenharmony_ci
635e5c31af7Sopenharmony_ci				const deUint32	ulpDiff		= hasSignedZero ? getUlpDiff(out0, ref) : getUlpDiffIgnoreZeroSign(out0, ref);
636e5c31af7Sopenharmony_ci
637e5c31af7Sopenharmony_ci				if (ulpDiff > 0)
638e5c31af7Sopenharmony_ci				{
639e5c31af7Sopenharmony_ci					m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref) << ", got ULP diff " << tcu::toHex(ulpDiff);
640e5c31af7Sopenharmony_ci					return false;
641e5c31af7Sopenharmony_ci				}
642e5c31af7Sopenharmony_ci			}
643e5c31af7Sopenharmony_ci		}
644e5c31af7Sopenharmony_ci		else
645e5c31af7Sopenharmony_ci		{
646e5c31af7Sopenharmony_ci			const int		mantissaBits	= getMinMantissaBits(precision);
647e5c31af7Sopenharmony_ci			const deUint32	maxUlpDiff		= getMaxUlpDiffFromBits(mantissaBits);	// ULP diff for rounded integer value.
648e5c31af7Sopenharmony_ci			const float		eps				= getEpsFromBits(1.0f, mantissaBits);	// epsilon for rounding bounds
649e5c31af7Sopenharmony_ci
650e5c31af7Sopenharmony_ci			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
651e5c31af7Sopenharmony_ci			{
652e5c31af7Sopenharmony_ci				const float		in0			= ((const float*)inputs[0])[compNdx];
653e5c31af7Sopenharmony_ci				const float		out0		= ((const float*)outputs[0])[compNdx];
654e5c31af7Sopenharmony_ci				const int		minRes		= int(roundEven(in0-eps));
655e5c31af7Sopenharmony_ci				const int		maxRes		= int(roundEven(in0+eps));
656e5c31af7Sopenharmony_ci				bool			anyOk		= false;
657e5c31af7Sopenharmony_ci
658e5c31af7Sopenharmony_ci				for (int roundedVal = minRes; roundedVal <= maxRes; roundedVal++)
659e5c31af7Sopenharmony_ci				{
660e5c31af7Sopenharmony_ci					const deUint32 ulpDiff = getUlpDiffIgnoreZeroSign(out0, float(roundedVal));
661e5c31af7Sopenharmony_ci
662e5c31af7Sopenharmony_ci					if (ulpDiff <= maxUlpDiff)
663e5c31af7Sopenharmony_ci					{
664e5c31af7Sopenharmony_ci						anyOk = true;
665e5c31af7Sopenharmony_ci						break;
666e5c31af7Sopenharmony_ci					}
667e5c31af7Sopenharmony_ci				}
668e5c31af7Sopenharmony_ci
669e5c31af7Sopenharmony_ci				if (!anyOk)
670e5c31af7Sopenharmony_ci				{
671e5c31af7Sopenharmony_ci					m_failMsg << "Expected [" << compNdx << "] = [" << minRes << ", " << maxRes << "] with ULP threshold " << tcu::toHex(maxUlpDiff);
672e5c31af7Sopenharmony_ci					return false;
673e5c31af7Sopenharmony_ci				}
674e5c31af7Sopenharmony_ci			}
675e5c31af7Sopenharmony_ci		}
676e5c31af7Sopenharmony_ci
677e5c31af7Sopenharmony_ci		return true;
678e5c31af7Sopenharmony_ci	}
679e5c31af7Sopenharmony_ci};
680e5c31af7Sopenharmony_ci
681e5c31af7Sopenharmony_ciclass ModfCase : public CommonFunctionCase
682e5c31af7Sopenharmony_ci{
683e5c31af7Sopenharmony_cipublic:
684e5c31af7Sopenharmony_ci	ModfCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
685e5c31af7Sopenharmony_ci		: CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "modf", shaderType)
686e5c31af7Sopenharmony_ci	{
687e5c31af7Sopenharmony_ci		m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
688e5c31af7Sopenharmony_ci		m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision)));
689e5c31af7Sopenharmony_ci		m_spec.outputs.push_back(Symbol("out1", glu::VarType(baseType, precision)));
690e5c31af7Sopenharmony_ci		m_spec.source = "out0 = modf(in0, out1);";
691e5c31af7Sopenharmony_ci	}
692e5c31af7Sopenharmony_ci
693e5c31af7Sopenharmony_ci	void getInputValues (int numValues, void* const* values) const
694e5c31af7Sopenharmony_ci	{
695e5c31af7Sopenharmony_ci		const Vec2 ranges[] =
696e5c31af7Sopenharmony_ci		{
697e5c31af7Sopenharmony_ci			Vec2(-2.0f,		2.0f),	// lowp
698e5c31af7Sopenharmony_ci			Vec2(-1e3f,		1e3f),	// mediump
699e5c31af7Sopenharmony_ci			Vec2(-1e7f,		1e7f)	// highp
700e5c31af7Sopenharmony_ci		};
701e5c31af7Sopenharmony_ci
702e5c31af7Sopenharmony_ci		de::Random				rnd			(deStringHash(getName()) ^ 0xac23fu);
703e5c31af7Sopenharmony_ci		const glu::DataType		type		= m_spec.inputs[0].varType.getBasicType();
704e5c31af7Sopenharmony_ci		const glu::Precision	precision	= m_spec.inputs[0].varType.getPrecision();
705e5c31af7Sopenharmony_ci		const int				scalarSize	= glu::getDataTypeScalarSize(type);
706e5c31af7Sopenharmony_ci
707e5c31af7Sopenharmony_ci		fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), values[0], numValues*scalarSize);
708e5c31af7Sopenharmony_ci	}
709e5c31af7Sopenharmony_ci
710e5c31af7Sopenharmony_ci	bool compare (const void* const* inputs, const void* const* outputs)
711e5c31af7Sopenharmony_ci	{
712e5c31af7Sopenharmony_ci		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
713e5c31af7Sopenharmony_ci		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
714e5c31af7Sopenharmony_ci		const bool				hasZeroSign		= supportsSignedZero(precision);
715e5c31af7Sopenharmony_ci		const int				scalarSize		= glu::getDataTypeScalarSize(type);
716e5c31af7Sopenharmony_ci
717e5c31af7Sopenharmony_ci		const int				mantissaBits	= getMinMantissaBits(precision);
718e5c31af7Sopenharmony_ci
719e5c31af7Sopenharmony_ci		for (int compNdx = 0; compNdx < scalarSize; compNdx++)
720e5c31af7Sopenharmony_ci		{
721e5c31af7Sopenharmony_ci			const float		in0			= ((const float*)inputs[0])[compNdx];
722e5c31af7Sopenharmony_ci			const float		out0		= ((const float*)outputs[0])[compNdx];
723e5c31af7Sopenharmony_ci			const float		out1		= ((const float*)outputs[1])[compNdx];
724e5c31af7Sopenharmony_ci
725e5c31af7Sopenharmony_ci			const float		refOut1		= float(int(in0));
726e5c31af7Sopenharmony_ci			const float		refOut0		= in0 - refOut1;
727e5c31af7Sopenharmony_ci
728e5c31af7Sopenharmony_ci			const int		bitsLost	= precision != glu::PRECISION_HIGHP ? numBitsLostInOp(in0, refOut0) : 0;
729e5c31af7Sopenharmony_ci			const deUint32	maxUlpDiff	= getMaxUlpDiffFromBits(de::max(mantissaBits - bitsLost, 0));
730e5c31af7Sopenharmony_ci
731e5c31af7Sopenharmony_ci			const float		resSum		= out0 + out1;
732e5c31af7Sopenharmony_ci
733e5c31af7Sopenharmony_ci			const deUint32	ulpDiff		= hasZeroSign ? getUlpDiff(resSum, in0) : getUlpDiffIgnoreZeroSign(resSum, in0);
734e5c31af7Sopenharmony_ci
735e5c31af7Sopenharmony_ci			if (ulpDiff > maxUlpDiff)
736e5c31af7Sopenharmony_ci			{
737e5c31af7Sopenharmony_ci				m_failMsg << "Expected [" << compNdx << "] = (" << HexFloat(refOut0) << ") + (" << HexFloat(refOut1) << ") = " << HexFloat(in0) << " with ULP threshold "
738e5c31af7Sopenharmony_ci							<< tcu::toHex(maxUlpDiff) << ", got ULP diff " << tcu::toHex(ulpDiff);
739e5c31af7Sopenharmony_ci				return false;
740e5c31af7Sopenharmony_ci			}
741e5c31af7Sopenharmony_ci		}
742e5c31af7Sopenharmony_ci
743e5c31af7Sopenharmony_ci		return true;
744e5c31af7Sopenharmony_ci	}
745e5c31af7Sopenharmony_ci};
746e5c31af7Sopenharmony_ci
747e5c31af7Sopenharmony_ciclass IsnanCase : public CommonFunctionCase
748e5c31af7Sopenharmony_ci{
749e5c31af7Sopenharmony_cipublic:
750e5c31af7Sopenharmony_ci	IsnanCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
751e5c31af7Sopenharmony_ci		: CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "isnan", shaderType)
752e5c31af7Sopenharmony_ci	{
753e5c31af7Sopenharmony_ci		DE_ASSERT(glu::isDataTypeFloatOrVec(baseType));
754e5c31af7Sopenharmony_ci
755e5c31af7Sopenharmony_ci		const int			vecSize		= glu::getDataTypeScalarSize(baseType);
756e5c31af7Sopenharmony_ci		const glu::DataType	boolType	= vecSize > 1 ? glu::getDataTypeBoolVec(vecSize) : glu::TYPE_BOOL;
757e5c31af7Sopenharmony_ci
758e5c31af7Sopenharmony_ci		m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
759e5c31af7Sopenharmony_ci		m_spec.outputs.push_back(Symbol("out0", glu::VarType(boolType, glu::PRECISION_LAST)));
760e5c31af7Sopenharmony_ci		m_spec.source = "out0 = isnan(in0);";
761e5c31af7Sopenharmony_ci	}
762e5c31af7Sopenharmony_ci
763e5c31af7Sopenharmony_ci	void getInputValues (int numValues, void* const* values) const
764e5c31af7Sopenharmony_ci	{
765e5c31af7Sopenharmony_ci		de::Random				rnd				(deStringHash(getName()) ^ 0xc2a39fu);
766e5c31af7Sopenharmony_ci		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
767e5c31af7Sopenharmony_ci		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
768e5c31af7Sopenharmony_ci		const int				scalarSize		= glu::getDataTypeScalarSize(type);
769e5c31af7Sopenharmony_ci		const int				mantissaBits	= getMinMantissaBits(precision);
770e5c31af7Sopenharmony_ci		const deUint32			mantissaMask	= ~getMaxUlpDiffFromBits(mantissaBits) & ((1u<<23)-1u);
771e5c31af7Sopenharmony_ci
772e5c31af7Sopenharmony_ci		for (int valNdx = 0; valNdx < numValues*scalarSize; valNdx++)
773e5c31af7Sopenharmony_ci		{
774e5c31af7Sopenharmony_ci			const bool		isNan		= rnd.getFloat() > 0.3f;
775e5c31af7Sopenharmony_ci			const bool		isInf		= !isNan && rnd.getFloat() > 0.4f;
776e5c31af7Sopenharmony_ci			const deUint32	mantissa	= !isInf ? ((1u<<22) | (rnd.getUint32() & mantissaMask)) : 0;
777e5c31af7Sopenharmony_ci			const deUint32	exp			= !isNan && !isInf ? (rnd.getUint32() & 0x7fu) : 0xffu;
778e5c31af7Sopenharmony_ci			const deUint32	sign		= rnd.getUint32() & 0x1u;
779e5c31af7Sopenharmony_ci			const deUint32	value		= (sign << 31) | (exp << 23) | mantissa;
780e5c31af7Sopenharmony_ci
781e5c31af7Sopenharmony_ci			DE_ASSERT(tcu::Float32(value).isInf() == isInf && tcu::Float32(value).isNaN() == isNan);
782e5c31af7Sopenharmony_ci
783e5c31af7Sopenharmony_ci			((deUint32*)values[0])[valNdx] = value;
784e5c31af7Sopenharmony_ci		}
785e5c31af7Sopenharmony_ci	}
786e5c31af7Sopenharmony_ci
787e5c31af7Sopenharmony_ci	bool compare (const void* const* inputs, const void* const* outputs)
788e5c31af7Sopenharmony_ci	{
789e5c31af7Sopenharmony_ci		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
790e5c31af7Sopenharmony_ci		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
791e5c31af7Sopenharmony_ci		const int				scalarSize		= glu::getDataTypeScalarSize(type);
792e5c31af7Sopenharmony_ci
793e5c31af7Sopenharmony_ci		if (precision == glu::PRECISION_HIGHP)
794e5c31af7Sopenharmony_ci		{
795e5c31af7Sopenharmony_ci			// Only highp is required to support inf/nan
796e5c31af7Sopenharmony_ci			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
797e5c31af7Sopenharmony_ci			{
798e5c31af7Sopenharmony_ci				const float		in0		= ((const float*)inputs[0])[compNdx];
799e5c31af7Sopenharmony_ci				const deUint32	out0	= ((const deUint32*)outputs[0])[compNdx];
800e5c31af7Sopenharmony_ci				const deUint32	ref		= tcu::Float32(in0).isNaN() ? 1u : 0u;
801e5c31af7Sopenharmony_ci
802e5c31af7Sopenharmony_ci				if (out0 != ref)
803e5c31af7Sopenharmony_ci				{
804e5c31af7Sopenharmony_ci					m_failMsg << "Expected [" << compNdx << "] = " << HexBool(ref);
805e5c31af7Sopenharmony_ci					return false;
806e5c31af7Sopenharmony_ci				}
807e5c31af7Sopenharmony_ci			}
808e5c31af7Sopenharmony_ci		}
809e5c31af7Sopenharmony_ci		else
810e5c31af7Sopenharmony_ci		{
811e5c31af7Sopenharmony_ci			// Value can be either 0 or 1
812e5c31af7Sopenharmony_ci			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
813e5c31af7Sopenharmony_ci			{
814e5c31af7Sopenharmony_ci				const int out0 = ((const int*)outputs[0])[compNdx];
815e5c31af7Sopenharmony_ci
816e5c31af7Sopenharmony_ci				if (out0 != 0 && out0 != 1)
817e5c31af7Sopenharmony_ci				{
818e5c31af7Sopenharmony_ci					m_failMsg << "Expected [" << compNdx << "] = 0 / 1";
819e5c31af7Sopenharmony_ci					return false;
820e5c31af7Sopenharmony_ci				}
821e5c31af7Sopenharmony_ci			}
822e5c31af7Sopenharmony_ci		}
823e5c31af7Sopenharmony_ci
824e5c31af7Sopenharmony_ci		return true;
825e5c31af7Sopenharmony_ci	}
826e5c31af7Sopenharmony_ci};
827e5c31af7Sopenharmony_ci
828e5c31af7Sopenharmony_ciclass IsinfCase : public CommonFunctionCase
829e5c31af7Sopenharmony_ci{
830e5c31af7Sopenharmony_cipublic:
831e5c31af7Sopenharmony_ci	IsinfCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
832e5c31af7Sopenharmony_ci		: CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "isinf", shaderType)
833e5c31af7Sopenharmony_ci	{
834e5c31af7Sopenharmony_ci		DE_ASSERT(glu::isDataTypeFloatOrVec(baseType));
835e5c31af7Sopenharmony_ci
836e5c31af7Sopenharmony_ci		const int			vecSize		= glu::getDataTypeScalarSize(baseType);
837e5c31af7Sopenharmony_ci		const glu::DataType	boolType	= vecSize > 1 ? glu::getDataTypeBoolVec(vecSize) : glu::TYPE_BOOL;
838e5c31af7Sopenharmony_ci
839e5c31af7Sopenharmony_ci		m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
840e5c31af7Sopenharmony_ci		m_spec.outputs.push_back(Symbol("out0", glu::VarType(boolType, glu::PRECISION_LAST)));
841e5c31af7Sopenharmony_ci		m_spec.source = "out0 = isinf(in0);";
842e5c31af7Sopenharmony_ci	}
843e5c31af7Sopenharmony_ci
844e5c31af7Sopenharmony_ci	void getInputValues (int numValues, void* const* values) const
845e5c31af7Sopenharmony_ci	{
846e5c31af7Sopenharmony_ci		de::Random				rnd				(deStringHash(getName()) ^ 0xc2a39fu);
847e5c31af7Sopenharmony_ci		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
848e5c31af7Sopenharmony_ci		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
849e5c31af7Sopenharmony_ci		const int				scalarSize		= glu::getDataTypeScalarSize(type);
850e5c31af7Sopenharmony_ci		const int				mantissaBits	= getMinMantissaBits(precision);
851e5c31af7Sopenharmony_ci		const deUint32			mantissaMask	= ~getMaxUlpDiffFromBits(mantissaBits) & ((1u<<23)-1u);
852e5c31af7Sopenharmony_ci
853e5c31af7Sopenharmony_ci		for (int valNdx = 0; valNdx < numValues*scalarSize; valNdx++)
854e5c31af7Sopenharmony_ci		{
855e5c31af7Sopenharmony_ci			const bool		isInf		= rnd.getFloat() > 0.3f;
856e5c31af7Sopenharmony_ci			const bool		isNan		= !isInf && rnd.getFloat() > 0.4f;
857e5c31af7Sopenharmony_ci			const deUint32	mantissa	= !isInf ? ((1u<<22) | (rnd.getUint32() & mantissaMask)) : 0;
858e5c31af7Sopenharmony_ci			const deUint32	exp			= !isNan && !isInf ? (rnd.getUint32() & 0x7fu) : 0xffu;
859e5c31af7Sopenharmony_ci			const deUint32	sign		= rnd.getUint32() & 0x1u;
860e5c31af7Sopenharmony_ci			const deUint32	value		= (sign << 31) | (exp << 23) | mantissa;
861e5c31af7Sopenharmony_ci
862e5c31af7Sopenharmony_ci			DE_ASSERT(tcu::Float32(value).isInf() == isInf && tcu::Float32(value).isNaN() == isNan);
863e5c31af7Sopenharmony_ci
864e5c31af7Sopenharmony_ci			((deUint32*)values[0])[valNdx] = value;
865e5c31af7Sopenharmony_ci		}
866e5c31af7Sopenharmony_ci	}
867e5c31af7Sopenharmony_ci
868e5c31af7Sopenharmony_ci	bool compare (const void* const* inputs, const void* const* outputs)
869e5c31af7Sopenharmony_ci	{
870e5c31af7Sopenharmony_ci		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
871e5c31af7Sopenharmony_ci		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
872e5c31af7Sopenharmony_ci		const int				scalarSize		= glu::getDataTypeScalarSize(type);
873e5c31af7Sopenharmony_ci
874e5c31af7Sopenharmony_ci		if (precision == glu::PRECISION_HIGHP)
875e5c31af7Sopenharmony_ci		{
876e5c31af7Sopenharmony_ci			// Only highp is required to support inf/nan
877e5c31af7Sopenharmony_ci			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
878e5c31af7Sopenharmony_ci			{
879e5c31af7Sopenharmony_ci				const float		in0		= ((const float*)inputs[0])[compNdx];
880e5c31af7Sopenharmony_ci				const deUint32	out0	= ((const deUint32*)outputs[0])[compNdx];
881e5c31af7Sopenharmony_ci				const deUint32	ref		= tcu::Float32(in0).isInf() ? 1u : 0u;
882e5c31af7Sopenharmony_ci
883e5c31af7Sopenharmony_ci				if (out0 != ref)
884e5c31af7Sopenharmony_ci				{
885e5c31af7Sopenharmony_ci					m_failMsg << "Expected [" << compNdx << "] = " << HexBool(ref);
886e5c31af7Sopenharmony_ci					return false;
887e5c31af7Sopenharmony_ci				}
888e5c31af7Sopenharmony_ci			}
889e5c31af7Sopenharmony_ci		}
890e5c31af7Sopenharmony_ci		else
891e5c31af7Sopenharmony_ci		{
892e5c31af7Sopenharmony_ci			// Value can be either 0 or 1
893e5c31af7Sopenharmony_ci			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
894e5c31af7Sopenharmony_ci			{
895e5c31af7Sopenharmony_ci				const int out0 = ((const int*)outputs[0])[compNdx];
896e5c31af7Sopenharmony_ci
897e5c31af7Sopenharmony_ci				if (out0 != 0 && out0 != 1)
898e5c31af7Sopenharmony_ci				{
899e5c31af7Sopenharmony_ci					m_failMsg << "Expected [" << compNdx << "] = 0 / 1";
900e5c31af7Sopenharmony_ci					return false;
901e5c31af7Sopenharmony_ci				}
902e5c31af7Sopenharmony_ci			}
903e5c31af7Sopenharmony_ci		}
904e5c31af7Sopenharmony_ci
905e5c31af7Sopenharmony_ci		return true;
906e5c31af7Sopenharmony_ci	}
907e5c31af7Sopenharmony_ci};
908e5c31af7Sopenharmony_ci
909e5c31af7Sopenharmony_ciclass FloatBitsToUintIntCase : public CommonFunctionCase
910e5c31af7Sopenharmony_ci{
911e5c31af7Sopenharmony_cipublic:
912e5c31af7Sopenharmony_ci	FloatBitsToUintIntCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType, bool outIsSigned)
913e5c31af7Sopenharmony_ci		: CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), outIsSigned ? "floatBitsToInt" : "floatBitsToUint", shaderType)
914e5c31af7Sopenharmony_ci	{
915e5c31af7Sopenharmony_ci		const int			vecSize		= glu::getDataTypeScalarSize(baseType);
916e5c31af7Sopenharmony_ci		const glu::DataType	intType		= outIsSigned ? (vecSize > 1 ? glu::getDataTypeIntVec(vecSize) : glu::TYPE_INT)
917e5c31af7Sopenharmony_ci													  : (vecSize > 1 ? glu::getDataTypeUintVec(vecSize) : glu::TYPE_UINT);
918e5c31af7Sopenharmony_ci
919e5c31af7Sopenharmony_ci		m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
920e5c31af7Sopenharmony_ci		m_spec.outputs.push_back(Symbol("out0", glu::VarType(intType, glu::PRECISION_HIGHP)));
921e5c31af7Sopenharmony_ci		m_spec.source = outIsSigned ? "out0 = floatBitsToInt(in0);" : "out0 = floatBitsToUint(in0);";
922e5c31af7Sopenharmony_ci	}
923e5c31af7Sopenharmony_ci
924e5c31af7Sopenharmony_ci	void getInputValues (int numValues, void* const* values) const
925e5c31af7Sopenharmony_ci	{
926e5c31af7Sopenharmony_ci		const Vec2 ranges[] =
927e5c31af7Sopenharmony_ci		{
928e5c31af7Sopenharmony_ci			Vec2(-2.0f,		2.0f),	// lowp
929e5c31af7Sopenharmony_ci			Vec2(-1e3f,		1e3f),	// mediump
930e5c31af7Sopenharmony_ci			Vec2(-1e7f,		1e7f)	// highp
931e5c31af7Sopenharmony_ci		};
932e5c31af7Sopenharmony_ci
933e5c31af7Sopenharmony_ci		de::Random				rnd			(deStringHash(getName()) ^ 0x2790au);
934e5c31af7Sopenharmony_ci		const glu::DataType		type		= m_spec.inputs[0].varType.getBasicType();
935e5c31af7Sopenharmony_ci		const glu::Precision	precision	= m_spec.inputs[0].varType.getPrecision();
936e5c31af7Sopenharmony_ci		const int				scalarSize	= glu::getDataTypeScalarSize(type);
937e5c31af7Sopenharmony_ci
938e5c31af7Sopenharmony_ci		fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), values[0], numValues*scalarSize);
939e5c31af7Sopenharmony_ci	}
940e5c31af7Sopenharmony_ci
941e5c31af7Sopenharmony_ci	bool compare (const void* const* inputs, const void* const* outputs)
942e5c31af7Sopenharmony_ci	{
943e5c31af7Sopenharmony_ci		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
944e5c31af7Sopenharmony_ci		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
945e5c31af7Sopenharmony_ci		const int				scalarSize		= glu::getDataTypeScalarSize(type);
946e5c31af7Sopenharmony_ci
947e5c31af7Sopenharmony_ci		const int				mantissaBits	= getMinMantissaBits(precision);
948e5c31af7Sopenharmony_ci		const int				maxUlpDiff		= getMaxUlpDiffFromBits(mantissaBits);
949e5c31af7Sopenharmony_ci
950e5c31af7Sopenharmony_ci		for (int compNdx = 0; compNdx < scalarSize; compNdx++)
951e5c31af7Sopenharmony_ci		{
952e5c31af7Sopenharmony_ci			const float		in0			= ((const float*)inputs[0])[compNdx];
953e5c31af7Sopenharmony_ci			const deUint32	out0		= ((const deUint32*)outputs[0])[compNdx];
954e5c31af7Sopenharmony_ci			const deUint32	refOut0		= tcu::Float32(in0).bits();
955e5c31af7Sopenharmony_ci			const int		ulpDiff		= de::abs((int)out0 - (int)refOut0);
956e5c31af7Sopenharmony_ci
957e5c31af7Sopenharmony_ci			if (ulpDiff > maxUlpDiff)
958e5c31af7Sopenharmony_ci			{
959e5c31af7Sopenharmony_ci				m_failMsg << "Expected [" << compNdx << "] = " << tcu::toHex(refOut0) << " with threshold "
960e5c31af7Sopenharmony_ci							<< tcu::toHex(maxUlpDiff) << ", got diff " << tcu::toHex(ulpDiff);
961e5c31af7Sopenharmony_ci				return false;
962e5c31af7Sopenharmony_ci			}
963e5c31af7Sopenharmony_ci		}
964e5c31af7Sopenharmony_ci
965e5c31af7Sopenharmony_ci		return true;
966e5c31af7Sopenharmony_ci	}
967e5c31af7Sopenharmony_ci};
968e5c31af7Sopenharmony_ci
969e5c31af7Sopenharmony_ciclass FloatBitsToIntCase : public FloatBitsToUintIntCase
970e5c31af7Sopenharmony_ci{
971e5c31af7Sopenharmony_cipublic:
972e5c31af7Sopenharmony_ci	FloatBitsToIntCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
973e5c31af7Sopenharmony_ci		: FloatBitsToUintIntCase(context, baseType, precision, shaderType, true)
974e5c31af7Sopenharmony_ci	{
975e5c31af7Sopenharmony_ci	}
976e5c31af7Sopenharmony_ci};
977e5c31af7Sopenharmony_ci
978e5c31af7Sopenharmony_ciclass FloatBitsToUintCase : public FloatBitsToUintIntCase
979e5c31af7Sopenharmony_ci{
980e5c31af7Sopenharmony_cipublic:
981e5c31af7Sopenharmony_ci	FloatBitsToUintCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
982e5c31af7Sopenharmony_ci		: FloatBitsToUintIntCase(context, baseType, precision, shaderType, false)
983e5c31af7Sopenharmony_ci	{
984e5c31af7Sopenharmony_ci	}
985e5c31af7Sopenharmony_ci};
986e5c31af7Sopenharmony_ci
987e5c31af7Sopenharmony_ciclass BitsToFloatCase : public CommonFunctionCase
988e5c31af7Sopenharmony_ci{
989e5c31af7Sopenharmony_cipublic:
990e5c31af7Sopenharmony_ci	BitsToFloatCase (Context& context, glu::DataType baseType, glu::ShaderType shaderType)
991e5c31af7Sopenharmony_ci		: CommonFunctionCase(context, getCommonFuncCaseName(baseType, glu::PRECISION_HIGHP, shaderType).c_str(), glu::isDataTypeIntOrIVec(baseType) ? "intBitsToFloat" : "uintBitsToFloat", shaderType)
992e5c31af7Sopenharmony_ci	{
993e5c31af7Sopenharmony_ci		const bool			inIsSigned	= glu::isDataTypeIntOrIVec(baseType);
994e5c31af7Sopenharmony_ci		const int			vecSize		= glu::getDataTypeScalarSize(baseType);
995e5c31af7Sopenharmony_ci		const glu::DataType	floatType	= vecSize > 1 ? glu::getDataTypeFloatVec(vecSize) : glu::TYPE_FLOAT;
996e5c31af7Sopenharmony_ci
997e5c31af7Sopenharmony_ci		m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, glu::PRECISION_HIGHP)));
998e5c31af7Sopenharmony_ci		m_spec.outputs.push_back(Symbol("out0", glu::VarType(floatType, glu::PRECISION_HIGHP)));
999e5c31af7Sopenharmony_ci		m_spec.source = inIsSigned ? "out0 = intBitsToFloat(in0);" : "out0 = uintBitsToFloat(in0);";
1000e5c31af7Sopenharmony_ci	}
1001e5c31af7Sopenharmony_ci
1002e5c31af7Sopenharmony_ci	void getInputValues (int numValues, void* const* values) const
1003e5c31af7Sopenharmony_ci	{
1004e5c31af7Sopenharmony_ci		de::Random				rnd			(deStringHash(getName()) ^ 0xbbb225u);
1005e5c31af7Sopenharmony_ci		const glu::DataType		type		= m_spec.inputs[0].varType.getBasicType();
1006e5c31af7Sopenharmony_ci		const int				scalarSize	= glu::getDataTypeScalarSize(type);
1007e5c31af7Sopenharmony_ci		const Vec2				range		(-1e8f, +1e8f);
1008e5c31af7Sopenharmony_ci
1009e5c31af7Sopenharmony_ci		// \note Filled as floats.
1010e5c31af7Sopenharmony_ci		fillRandomScalars(rnd, range.x(), range.y(), values[0], numValues*scalarSize);
1011e5c31af7Sopenharmony_ci	}
1012e5c31af7Sopenharmony_ci
1013e5c31af7Sopenharmony_ci	bool compare (const void* const* inputs, const void* const* outputs)
1014e5c31af7Sopenharmony_ci	{
1015e5c31af7Sopenharmony_ci		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
1016e5c31af7Sopenharmony_ci		const int				scalarSize		= glu::getDataTypeScalarSize(type);
1017e5c31af7Sopenharmony_ci		const deUint32			maxUlpDiff		= 0;
1018e5c31af7Sopenharmony_ci
1019e5c31af7Sopenharmony_ci		for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1020e5c31af7Sopenharmony_ci		{
1021e5c31af7Sopenharmony_ci			const float		in0			= ((const float*)inputs[0])[compNdx];
1022e5c31af7Sopenharmony_ci			const float		out0		= ((const float*)outputs[0])[compNdx];
1023e5c31af7Sopenharmony_ci			const deUint32	ulpDiff		= getUlpDiff(in0, out0);
1024e5c31af7Sopenharmony_ci
1025e5c31af7Sopenharmony_ci			if (ulpDiff > maxUlpDiff)
1026e5c31af7Sopenharmony_ci			{
1027e5c31af7Sopenharmony_ci				m_failMsg << "Expected [" << compNdx << "] = " << tcu::toHex(tcu::Float32(in0).bits()) << " with ULP threshold "
1028e5c31af7Sopenharmony_ci							<< tcu::toHex(maxUlpDiff) << ", got ULP diff " << tcu::toHex(ulpDiff);
1029e5c31af7Sopenharmony_ci				return false;
1030e5c31af7Sopenharmony_ci			}
1031e5c31af7Sopenharmony_ci		}
1032e5c31af7Sopenharmony_ci
1033e5c31af7Sopenharmony_ci		return true;
1034e5c31af7Sopenharmony_ci	}
1035e5c31af7Sopenharmony_ci};
1036e5c31af7Sopenharmony_ci
1037e5c31af7Sopenharmony_ciclass FloorCase : public CommonFunctionCase
1038e5c31af7Sopenharmony_ci{
1039e5c31af7Sopenharmony_cipublic:
1040e5c31af7Sopenharmony_ci	FloorCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
1041e5c31af7Sopenharmony_ci		: CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "floor", shaderType)
1042e5c31af7Sopenharmony_ci	{
1043e5c31af7Sopenharmony_ci		m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
1044e5c31af7Sopenharmony_ci		m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision)));
1045e5c31af7Sopenharmony_ci		m_spec.source = "out0 = floor(in0);";
1046e5c31af7Sopenharmony_ci	}
1047e5c31af7Sopenharmony_ci
1048e5c31af7Sopenharmony_ci	void getInputValues (int numValues, void* const* values) const
1049e5c31af7Sopenharmony_ci	{
1050e5c31af7Sopenharmony_ci		const Vec2 ranges[] =
1051e5c31af7Sopenharmony_ci		{
1052e5c31af7Sopenharmony_ci			Vec2(-2.0f,		2.0f),	// lowp
1053e5c31af7Sopenharmony_ci			Vec2(-1e3f,		1e3f),	// mediump
1054e5c31af7Sopenharmony_ci			Vec2(-1e7f,		1e7f)	// highp
1055e5c31af7Sopenharmony_ci		};
1056e5c31af7Sopenharmony_ci
1057e5c31af7Sopenharmony_ci		de::Random				rnd			(deStringHash(getName()) ^ 0xac23fu);
1058e5c31af7Sopenharmony_ci		const glu::DataType		type		= m_spec.inputs[0].varType.getBasicType();
1059e5c31af7Sopenharmony_ci		const glu::Precision	precision	= m_spec.inputs[0].varType.getPrecision();
1060e5c31af7Sopenharmony_ci		const int				scalarSize	= glu::getDataTypeScalarSize(type);
1061e5c31af7Sopenharmony_ci		// Random cases.
1062e5c31af7Sopenharmony_ci		fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), (float*)values[0], numValues*scalarSize);
1063e5c31af7Sopenharmony_ci
1064e5c31af7Sopenharmony_ci		// If precision is mediump, make sure values can be represented in fp16 exactly
1065e5c31af7Sopenharmony_ci		if (precision == glu::PRECISION_MEDIUMP)
1066e5c31af7Sopenharmony_ci		{
1067e5c31af7Sopenharmony_ci			for (int ndx = 0; ndx < numValues*scalarSize; ndx++)
1068e5c31af7Sopenharmony_ci				((float*)values[0])[ndx] = tcu::Float16(((float*)values[0])[ndx]).asFloat();
1069e5c31af7Sopenharmony_ci		}
1070e5c31af7Sopenharmony_ci	}
1071e5c31af7Sopenharmony_ci
1072e5c31af7Sopenharmony_ci	bool compare (const void* const* inputs, const void* const* outputs)
1073e5c31af7Sopenharmony_ci	{
1074e5c31af7Sopenharmony_ci		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
1075e5c31af7Sopenharmony_ci		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
1076e5c31af7Sopenharmony_ci		const int				scalarSize		= glu::getDataTypeScalarSize(type);
1077e5c31af7Sopenharmony_ci
1078e5c31af7Sopenharmony_ci		if (precision == glu::PRECISION_HIGHP || precision == glu::PRECISION_MEDIUMP)
1079e5c31af7Sopenharmony_ci		{
1080e5c31af7Sopenharmony_ci			// Require exact result.
1081e5c31af7Sopenharmony_ci			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1082e5c31af7Sopenharmony_ci			{
1083e5c31af7Sopenharmony_ci				const float		in0			= ((const float*)inputs[0])[compNdx];
1084e5c31af7Sopenharmony_ci				const float		out0		= ((const float*)outputs[0])[compNdx];
1085e5c31af7Sopenharmony_ci				const float		ref			= deFloatFloor(in0);
1086e5c31af7Sopenharmony_ci
1087e5c31af7Sopenharmony_ci				const deUint32	ulpDiff		= getUlpDiff(out0, ref);
1088e5c31af7Sopenharmony_ci
1089e5c31af7Sopenharmony_ci				if (ulpDiff > 0)
1090e5c31af7Sopenharmony_ci				{
1091e5c31af7Sopenharmony_ci					m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref) << ", got ULP diff " << tcu::toHex(ulpDiff);
1092e5c31af7Sopenharmony_ci					return false;
1093e5c31af7Sopenharmony_ci				}
1094e5c31af7Sopenharmony_ci			}
1095e5c31af7Sopenharmony_ci		}
1096e5c31af7Sopenharmony_ci		else
1097e5c31af7Sopenharmony_ci		{
1098e5c31af7Sopenharmony_ci			const int		mantissaBits	= getMinMantissaBits(precision);
1099e5c31af7Sopenharmony_ci			const deUint32	maxUlpDiff		= getMaxUlpDiffFromBits(mantissaBits);	// ULP diff for rounded integer value.
1100e5c31af7Sopenharmony_ci			const float		eps				= getEpsFromBits(1.0f, mantissaBits);	// epsilon for rounding bounds
1101e5c31af7Sopenharmony_ci
1102e5c31af7Sopenharmony_ci			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1103e5c31af7Sopenharmony_ci			{
1104e5c31af7Sopenharmony_ci				const float		in0			= ((const float*)inputs[0])[compNdx];
1105e5c31af7Sopenharmony_ci				const float		out0		= ((const float*)outputs[0])[compNdx];
1106e5c31af7Sopenharmony_ci				const int		minRes		= int(deFloatFloor(in0-eps));
1107e5c31af7Sopenharmony_ci				const int		maxRes		= int(deFloatFloor(in0+eps));
1108e5c31af7Sopenharmony_ci				bool			anyOk		= false;
1109e5c31af7Sopenharmony_ci
1110e5c31af7Sopenharmony_ci				for (int roundedVal = minRes; roundedVal <= maxRes; roundedVal++)
1111e5c31af7Sopenharmony_ci				{
1112e5c31af7Sopenharmony_ci					const deUint32 ulpDiff = getUlpDiff(out0, float(roundedVal));
1113e5c31af7Sopenharmony_ci
1114e5c31af7Sopenharmony_ci					if (ulpDiff <= maxUlpDiff)
1115e5c31af7Sopenharmony_ci					{
1116e5c31af7Sopenharmony_ci						anyOk = true;
1117e5c31af7Sopenharmony_ci						break;
1118e5c31af7Sopenharmony_ci					}
1119e5c31af7Sopenharmony_ci				}
1120e5c31af7Sopenharmony_ci
1121e5c31af7Sopenharmony_ci				if (!anyOk)
1122e5c31af7Sopenharmony_ci				{
1123e5c31af7Sopenharmony_ci					m_failMsg << "Expected [" << compNdx << "] = [" << minRes << ", " << maxRes << "] with ULP threshold " << tcu::toHex(maxUlpDiff);
1124e5c31af7Sopenharmony_ci					return false;
1125e5c31af7Sopenharmony_ci				}
1126e5c31af7Sopenharmony_ci			}
1127e5c31af7Sopenharmony_ci		}
1128e5c31af7Sopenharmony_ci
1129e5c31af7Sopenharmony_ci		return true;
1130e5c31af7Sopenharmony_ci	}
1131e5c31af7Sopenharmony_ci};
1132e5c31af7Sopenharmony_ci
1133e5c31af7Sopenharmony_ciclass TruncCase : public CommonFunctionCase
1134e5c31af7Sopenharmony_ci{
1135e5c31af7Sopenharmony_cipublic:
1136e5c31af7Sopenharmony_ci	TruncCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
1137e5c31af7Sopenharmony_ci		: CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "trunc", shaderType)
1138e5c31af7Sopenharmony_ci	{
1139e5c31af7Sopenharmony_ci		m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
1140e5c31af7Sopenharmony_ci		m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision)));
1141e5c31af7Sopenharmony_ci		m_spec.source = "out0 = trunc(in0);";
1142e5c31af7Sopenharmony_ci	}
1143e5c31af7Sopenharmony_ci
1144e5c31af7Sopenharmony_ci	void getInputValues (int numValues, void* const* values) const
1145e5c31af7Sopenharmony_ci	{
1146e5c31af7Sopenharmony_ci		const Vec2 ranges[] =
1147e5c31af7Sopenharmony_ci		{
1148e5c31af7Sopenharmony_ci			Vec2(-2.0f,		2.0f),	// lowp
1149e5c31af7Sopenharmony_ci			Vec2(-1e3f,		1e3f),	// mediump
1150e5c31af7Sopenharmony_ci			Vec2(-1e7f,		1e7f)	// highp
1151e5c31af7Sopenharmony_ci		};
1152e5c31af7Sopenharmony_ci
1153e5c31af7Sopenharmony_ci		de::Random				rnd				(deStringHash(getName()) ^ 0xac23fu);
1154e5c31af7Sopenharmony_ci		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
1155e5c31af7Sopenharmony_ci		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
1156e5c31af7Sopenharmony_ci		const int				scalarSize		= glu::getDataTypeScalarSize(type);
1157e5c31af7Sopenharmony_ci		const float				specialCases[]	= { 0.0f, -0.0f, -0.9f, 0.9f, 1.0f, -1.0f };
1158e5c31af7Sopenharmony_ci		const int				numSpecialCases	= DE_LENGTH_OF_ARRAY(specialCases);
1159e5c31af7Sopenharmony_ci
1160e5c31af7Sopenharmony_ci		// Special cases
1161e5c31af7Sopenharmony_ci		for (int caseNdx = 0; caseNdx < numSpecialCases; caseNdx++)
1162e5c31af7Sopenharmony_ci		{
1163e5c31af7Sopenharmony_ci			for (int scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++)
1164e5c31af7Sopenharmony_ci				((float*)values[0])[caseNdx*scalarSize + scalarNdx] = specialCases[caseNdx];
1165e5c31af7Sopenharmony_ci		}
1166e5c31af7Sopenharmony_ci
1167e5c31af7Sopenharmony_ci		// Random cases.
1168e5c31af7Sopenharmony_ci		fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), (float*)values[0] + scalarSize*numSpecialCases, (numValues-numSpecialCases)*scalarSize);
1169e5c31af7Sopenharmony_ci
1170e5c31af7Sopenharmony_ci		// If precision is mediump, make sure values can be represented in fp16 exactly
1171e5c31af7Sopenharmony_ci		if (precision == glu::PRECISION_MEDIUMP)
1172e5c31af7Sopenharmony_ci		{
1173e5c31af7Sopenharmony_ci			for (int ndx = 0; ndx < numValues*scalarSize; ndx++)
1174e5c31af7Sopenharmony_ci				((float*)values[0])[ndx] = tcu::Float16(((float*)values[0])[ndx]).asFloat();
1175e5c31af7Sopenharmony_ci		}
1176e5c31af7Sopenharmony_ci	}
1177e5c31af7Sopenharmony_ci
1178e5c31af7Sopenharmony_ci	bool compare (const void* const* inputs, const void* const* outputs)
1179e5c31af7Sopenharmony_ci	{
1180e5c31af7Sopenharmony_ci		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
1181e5c31af7Sopenharmony_ci		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
1182e5c31af7Sopenharmony_ci		const int				scalarSize		= glu::getDataTypeScalarSize(type);
1183e5c31af7Sopenharmony_ci
1184e5c31af7Sopenharmony_ci		if (precision == glu::PRECISION_HIGHP || precision == glu::PRECISION_MEDIUMP)
1185e5c31af7Sopenharmony_ci		{
1186e5c31af7Sopenharmony_ci			// Require exact result.
1187e5c31af7Sopenharmony_ci			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1188e5c31af7Sopenharmony_ci			{
1189e5c31af7Sopenharmony_ci				const float		in0			= ((const float*)inputs[0])[compNdx];
1190e5c31af7Sopenharmony_ci				const float		out0		= ((const float*)outputs[0])[compNdx];
1191e5c31af7Sopenharmony_ci				const bool		isNeg		= tcu::Float32(in0).sign() < 0;
1192e5c31af7Sopenharmony_ci				const float		ref			= isNeg ? (-float(int(-in0))) : float(int(in0));
1193e5c31af7Sopenharmony_ci
1194e5c31af7Sopenharmony_ci				// \note: trunc() function definition is a bit broad on negative zeros. Ignore result sign if zero.
1195e5c31af7Sopenharmony_ci				const deUint32	ulpDiff		= getUlpDiffIgnoreZeroSign(out0, ref);
1196e5c31af7Sopenharmony_ci
1197e5c31af7Sopenharmony_ci				if (ulpDiff > 0)
1198e5c31af7Sopenharmony_ci				{
1199e5c31af7Sopenharmony_ci					m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref) << ", got ULP diff " << tcu::toHex(ulpDiff);
1200e5c31af7Sopenharmony_ci					return false;
1201e5c31af7Sopenharmony_ci				}
1202e5c31af7Sopenharmony_ci			}
1203e5c31af7Sopenharmony_ci		}
1204e5c31af7Sopenharmony_ci		else
1205e5c31af7Sopenharmony_ci		{
1206e5c31af7Sopenharmony_ci			const int		mantissaBits	= getMinMantissaBits(precision);
1207e5c31af7Sopenharmony_ci			const deUint32	maxUlpDiff		= getMaxUlpDiffFromBits(mantissaBits);	// ULP diff for rounded integer value.
1208e5c31af7Sopenharmony_ci			const float		eps				= getEpsFromBits(1.0f, mantissaBits);	// epsilon for rounding bounds
1209e5c31af7Sopenharmony_ci
1210e5c31af7Sopenharmony_ci			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1211e5c31af7Sopenharmony_ci			{
1212e5c31af7Sopenharmony_ci				const float		in0			= ((const float*)inputs[0])[compNdx];
1213e5c31af7Sopenharmony_ci				const float		out0		= ((const float*)outputs[0])[compNdx];
1214e5c31af7Sopenharmony_ci				const int		minRes		= int(in0-eps);
1215e5c31af7Sopenharmony_ci				const int		maxRes		= int(in0+eps);
1216e5c31af7Sopenharmony_ci				bool			anyOk		= false;
1217e5c31af7Sopenharmony_ci
1218e5c31af7Sopenharmony_ci				for (int roundedVal = minRes; roundedVal <= maxRes; roundedVal++)
1219e5c31af7Sopenharmony_ci				{
1220e5c31af7Sopenharmony_ci					const deUint32 ulpDiff = getUlpDiffIgnoreZeroSign(out0, float(roundedVal));
1221e5c31af7Sopenharmony_ci
1222e5c31af7Sopenharmony_ci					if (ulpDiff <= maxUlpDiff)
1223e5c31af7Sopenharmony_ci					{
1224e5c31af7Sopenharmony_ci						anyOk = true;
1225e5c31af7Sopenharmony_ci						break;
1226e5c31af7Sopenharmony_ci					}
1227e5c31af7Sopenharmony_ci				}
1228e5c31af7Sopenharmony_ci
1229e5c31af7Sopenharmony_ci				if (!anyOk)
1230e5c31af7Sopenharmony_ci				{
1231e5c31af7Sopenharmony_ci					m_failMsg << "Expected [" << compNdx << "] = [" << minRes << ", " << maxRes << "] with ULP threshold " << tcu::toHex(maxUlpDiff);
1232e5c31af7Sopenharmony_ci					return false;
1233e5c31af7Sopenharmony_ci				}
1234e5c31af7Sopenharmony_ci			}
1235e5c31af7Sopenharmony_ci		}
1236e5c31af7Sopenharmony_ci
1237e5c31af7Sopenharmony_ci		return true;
1238e5c31af7Sopenharmony_ci	}
1239e5c31af7Sopenharmony_ci};
1240e5c31af7Sopenharmony_ci
1241e5c31af7Sopenharmony_ciclass RoundCase : public CommonFunctionCase
1242e5c31af7Sopenharmony_ci{
1243e5c31af7Sopenharmony_cipublic:
1244e5c31af7Sopenharmony_ci	RoundCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
1245e5c31af7Sopenharmony_ci		: CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "round", shaderType)
1246e5c31af7Sopenharmony_ci	{
1247e5c31af7Sopenharmony_ci		m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
1248e5c31af7Sopenharmony_ci		m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision)));
1249e5c31af7Sopenharmony_ci		m_spec.source = "out0 = round(in0);";
1250e5c31af7Sopenharmony_ci	}
1251e5c31af7Sopenharmony_ci
1252e5c31af7Sopenharmony_ci	void getInputValues (int numValues, void* const* values) const
1253e5c31af7Sopenharmony_ci	{
1254e5c31af7Sopenharmony_ci		const Vec2 ranges[] =
1255e5c31af7Sopenharmony_ci		{
1256e5c31af7Sopenharmony_ci			Vec2(-2.0f,		2.0f),	// lowp
1257e5c31af7Sopenharmony_ci			Vec2(-1e3f,		1e3f),	// mediump
1258e5c31af7Sopenharmony_ci			Vec2(-1e7f,		1e7f)	// highp
1259e5c31af7Sopenharmony_ci		};
1260e5c31af7Sopenharmony_ci
1261e5c31af7Sopenharmony_ci		de::Random				rnd				(deStringHash(getName()) ^ 0xac23fu);
1262e5c31af7Sopenharmony_ci		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
1263e5c31af7Sopenharmony_ci		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
1264e5c31af7Sopenharmony_ci		const int				scalarSize		= glu::getDataTypeScalarSize(type);
1265e5c31af7Sopenharmony_ci		int						numSpecialCases	= 0;
1266e5c31af7Sopenharmony_ci
1267e5c31af7Sopenharmony_ci		// Special cases.
1268e5c31af7Sopenharmony_ci		if (precision != glu::PRECISION_LOWP)
1269e5c31af7Sopenharmony_ci		{
1270e5c31af7Sopenharmony_ci			DE_ASSERT(numValues >= 10);
1271e5c31af7Sopenharmony_ci			for (int ndx = 0; ndx < 10; ndx++)
1272e5c31af7Sopenharmony_ci			{
1273e5c31af7Sopenharmony_ci				const float v = de::clamp(float(ndx) - 5.5f, ranges[precision].x(), ranges[precision].y());
1274e5c31af7Sopenharmony_ci				std::fill((float*)values[0], (float*)values[0] + scalarSize, v);
1275e5c31af7Sopenharmony_ci				numSpecialCases += 1;
1276e5c31af7Sopenharmony_ci			}
1277e5c31af7Sopenharmony_ci		}
1278e5c31af7Sopenharmony_ci
1279e5c31af7Sopenharmony_ci		// Random cases.
1280e5c31af7Sopenharmony_ci		fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), (float*)values[0] + numSpecialCases*scalarSize, (numValues-numSpecialCases)*scalarSize);
1281e5c31af7Sopenharmony_ci
1282e5c31af7Sopenharmony_ci		// If precision is mediump, make sure values can be represented in fp16 exactly
1283e5c31af7Sopenharmony_ci		if (precision == glu::PRECISION_MEDIUMP)
1284e5c31af7Sopenharmony_ci		{
1285e5c31af7Sopenharmony_ci			for (int ndx = 0; ndx < numValues*scalarSize; ndx++)
1286e5c31af7Sopenharmony_ci				((float*)values[0])[ndx] = tcu::Float16(((float*)values[0])[ndx]).asFloat();
1287e5c31af7Sopenharmony_ci		}
1288e5c31af7Sopenharmony_ci	}
1289e5c31af7Sopenharmony_ci
1290e5c31af7Sopenharmony_ci	bool compare (const void* const* inputs, const void* const* outputs)
1291e5c31af7Sopenharmony_ci	{
1292e5c31af7Sopenharmony_ci		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
1293e5c31af7Sopenharmony_ci		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
1294e5c31af7Sopenharmony_ci		const bool				hasZeroSign		= supportsSignedZero(precision);
1295e5c31af7Sopenharmony_ci		const int				scalarSize		= glu::getDataTypeScalarSize(type);
1296e5c31af7Sopenharmony_ci
1297e5c31af7Sopenharmony_ci		if (precision == glu::PRECISION_HIGHP || precision == glu::PRECISION_MEDIUMP)
1298e5c31af7Sopenharmony_ci		{
1299e5c31af7Sopenharmony_ci			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1300e5c31af7Sopenharmony_ci			{
1301e5c31af7Sopenharmony_ci				const float		in0			= ((const float*)inputs[0])[compNdx];
1302e5c31af7Sopenharmony_ci				const float		out0		= ((const float*)outputs[0])[compNdx];
1303e5c31af7Sopenharmony_ci
1304e5c31af7Sopenharmony_ci				if (deFloatFrac(in0) == 0.5f)
1305e5c31af7Sopenharmony_ci				{
1306e5c31af7Sopenharmony_ci					// Allow both ceil(in) and floor(in)
1307e5c31af7Sopenharmony_ci					const float		ref0		= deFloatFloor(in0);
1308e5c31af7Sopenharmony_ci					const float		ref1		= deFloatCeil(in0);
1309e5c31af7Sopenharmony_ci					const deUint32	ulpDiff0	= hasZeroSign ? getUlpDiff(out0, ref0) : getUlpDiffIgnoreZeroSign(out0, ref0);
1310e5c31af7Sopenharmony_ci					const deUint32	ulpDiff1	= hasZeroSign ? getUlpDiff(out0, ref1) : getUlpDiffIgnoreZeroSign(out0, ref1);
1311e5c31af7Sopenharmony_ci
1312e5c31af7Sopenharmony_ci					if (ulpDiff0 > 0 && ulpDiff1 > 0)
1313e5c31af7Sopenharmony_ci					{
1314e5c31af7Sopenharmony_ci						m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref0) << " or " << HexFloat(ref1) << ", got ULP diff " << tcu::toHex(de::min(ulpDiff0, ulpDiff1));
1315e5c31af7Sopenharmony_ci						return false;
1316e5c31af7Sopenharmony_ci					}
1317e5c31af7Sopenharmony_ci				}
1318e5c31af7Sopenharmony_ci				else
1319e5c31af7Sopenharmony_ci				{
1320e5c31af7Sopenharmony_ci					// Require exact result
1321e5c31af7Sopenharmony_ci					const float		ref		= roundEven(in0);
1322e5c31af7Sopenharmony_ci					const deUint32	ulpDiff	= hasZeroSign ? getUlpDiff(out0, ref) : getUlpDiffIgnoreZeroSign(out0, ref);
1323e5c31af7Sopenharmony_ci
1324e5c31af7Sopenharmony_ci					if (ulpDiff > 0)
1325e5c31af7Sopenharmony_ci					{
1326e5c31af7Sopenharmony_ci						m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref) << ", got ULP diff " << tcu::toHex(ulpDiff);
1327e5c31af7Sopenharmony_ci						return false;
1328e5c31af7Sopenharmony_ci					}
1329e5c31af7Sopenharmony_ci				}
1330e5c31af7Sopenharmony_ci			}
1331e5c31af7Sopenharmony_ci		}
1332e5c31af7Sopenharmony_ci		else
1333e5c31af7Sopenharmony_ci		{
1334e5c31af7Sopenharmony_ci			const int		mantissaBits	= getMinMantissaBits(precision);
1335e5c31af7Sopenharmony_ci			const deUint32	maxUlpDiff		= getMaxUlpDiffFromBits(mantissaBits);	// ULP diff for rounded integer value.
1336e5c31af7Sopenharmony_ci			const float		eps				= getEpsFromBits(1.0f, mantissaBits);	// epsilon for rounding bounds
1337e5c31af7Sopenharmony_ci
1338e5c31af7Sopenharmony_ci			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1339e5c31af7Sopenharmony_ci			{
1340e5c31af7Sopenharmony_ci				const float		in0			= ((const float*)inputs[0])[compNdx];
1341e5c31af7Sopenharmony_ci				const float		out0		= ((const float*)outputs[0])[compNdx];
1342e5c31af7Sopenharmony_ci				const int		minRes		= int(roundEven(in0-eps));
1343e5c31af7Sopenharmony_ci				const int		maxRes		= int(roundEven(in0+eps));
1344e5c31af7Sopenharmony_ci				bool			anyOk		= false;
1345e5c31af7Sopenharmony_ci
1346e5c31af7Sopenharmony_ci				for (int roundedVal = minRes; roundedVal <= maxRes; roundedVal++)
1347e5c31af7Sopenharmony_ci				{
1348e5c31af7Sopenharmony_ci					const deUint32 ulpDiff = getUlpDiffIgnoreZeroSign(out0, float(roundedVal));
1349e5c31af7Sopenharmony_ci
1350e5c31af7Sopenharmony_ci					if (ulpDiff <= maxUlpDiff)
1351e5c31af7Sopenharmony_ci					{
1352e5c31af7Sopenharmony_ci						anyOk = true;
1353e5c31af7Sopenharmony_ci						break;
1354e5c31af7Sopenharmony_ci					}
1355e5c31af7Sopenharmony_ci				}
1356e5c31af7Sopenharmony_ci
1357e5c31af7Sopenharmony_ci				if (!anyOk)
1358e5c31af7Sopenharmony_ci				{
1359e5c31af7Sopenharmony_ci					m_failMsg << "Expected [" << compNdx << "] = [" << minRes << ", " << maxRes << "] with ULP threshold " << tcu::toHex(maxUlpDiff);
1360e5c31af7Sopenharmony_ci					return false;
1361e5c31af7Sopenharmony_ci				}
1362e5c31af7Sopenharmony_ci			}
1363e5c31af7Sopenharmony_ci		}
1364e5c31af7Sopenharmony_ci
1365e5c31af7Sopenharmony_ci		return true;
1366e5c31af7Sopenharmony_ci	}
1367e5c31af7Sopenharmony_ci};
1368e5c31af7Sopenharmony_ci
1369e5c31af7Sopenharmony_ciclass CeilCase : public CommonFunctionCase
1370e5c31af7Sopenharmony_ci{
1371e5c31af7Sopenharmony_cipublic:
1372e5c31af7Sopenharmony_ci	CeilCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
1373e5c31af7Sopenharmony_ci		: CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "ceil", shaderType)
1374e5c31af7Sopenharmony_ci	{
1375e5c31af7Sopenharmony_ci		m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
1376e5c31af7Sopenharmony_ci		m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision)));
1377e5c31af7Sopenharmony_ci		m_spec.source = "out0 = ceil(in0);";
1378e5c31af7Sopenharmony_ci	}
1379e5c31af7Sopenharmony_ci
1380e5c31af7Sopenharmony_ci	void getInputValues (int numValues, void* const* values) const
1381e5c31af7Sopenharmony_ci	{
1382e5c31af7Sopenharmony_ci		const Vec2 ranges[] =
1383e5c31af7Sopenharmony_ci		{
1384e5c31af7Sopenharmony_ci			Vec2(-2.0f,		2.0f),	// lowp
1385e5c31af7Sopenharmony_ci			Vec2(-1e3f,		1e3f),	// mediump
1386e5c31af7Sopenharmony_ci			Vec2(-1e7f,		1e7f)	// highp
1387e5c31af7Sopenharmony_ci		};
1388e5c31af7Sopenharmony_ci
1389e5c31af7Sopenharmony_ci		de::Random				rnd			(deStringHash(getName()) ^ 0xac23fu);
1390e5c31af7Sopenharmony_ci		const glu::DataType		type		= m_spec.inputs[0].varType.getBasicType();
1391e5c31af7Sopenharmony_ci		const glu::Precision	precision	= m_spec.inputs[0].varType.getPrecision();
1392e5c31af7Sopenharmony_ci		const int				scalarSize	= glu::getDataTypeScalarSize(type);
1393e5c31af7Sopenharmony_ci
1394e5c31af7Sopenharmony_ci		// Random cases.
1395e5c31af7Sopenharmony_ci		fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), (float*)values[0], numValues*scalarSize);
1396e5c31af7Sopenharmony_ci
1397e5c31af7Sopenharmony_ci		// If precision is mediump, make sure values can be represented in fp16 exactly
1398e5c31af7Sopenharmony_ci		if (precision == glu::PRECISION_MEDIUMP)
1399e5c31af7Sopenharmony_ci		{
1400e5c31af7Sopenharmony_ci			for (int ndx = 0; ndx < numValues*scalarSize; ndx++)
1401e5c31af7Sopenharmony_ci				((float*)values[0])[ndx] = tcu::Float16(((float*)values[0])[ndx]).asFloat();
1402e5c31af7Sopenharmony_ci		}
1403e5c31af7Sopenharmony_ci	}
1404e5c31af7Sopenharmony_ci
1405e5c31af7Sopenharmony_ci	bool compare (const void* const* inputs, const void* const* outputs)
1406e5c31af7Sopenharmony_ci	{
1407e5c31af7Sopenharmony_ci		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
1408e5c31af7Sopenharmony_ci		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
1409e5c31af7Sopenharmony_ci		const bool				hasZeroSign		= supportsSignedZero(precision);
1410e5c31af7Sopenharmony_ci		const int				scalarSize		= glu::getDataTypeScalarSize(type);
1411e5c31af7Sopenharmony_ci
1412e5c31af7Sopenharmony_ci		if (precision == glu::PRECISION_HIGHP || precision == glu::PRECISION_MEDIUMP)
1413e5c31af7Sopenharmony_ci		{
1414e5c31af7Sopenharmony_ci			// Require exact result.
1415e5c31af7Sopenharmony_ci			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1416e5c31af7Sopenharmony_ci			{
1417e5c31af7Sopenharmony_ci				const float		in0			= ((const float*)inputs[0])[compNdx];
1418e5c31af7Sopenharmony_ci				const float		out0		= ((const float*)outputs[0])[compNdx];
1419e5c31af7Sopenharmony_ci				const float		ref			= deFloatCeil(in0);
1420e5c31af7Sopenharmony_ci
1421e5c31af7Sopenharmony_ci				const deUint32	ulpDiff		= hasZeroSign ? getUlpDiff(out0, ref) : getUlpDiffIgnoreZeroSign(out0, ref);
1422e5c31af7Sopenharmony_ci
1423e5c31af7Sopenharmony_ci				if (ulpDiff > 0)
1424e5c31af7Sopenharmony_ci				{
1425e5c31af7Sopenharmony_ci					m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref) << ", got ULP diff " << tcu::toHex(ulpDiff);
1426e5c31af7Sopenharmony_ci					return false;
1427e5c31af7Sopenharmony_ci				}
1428e5c31af7Sopenharmony_ci			}
1429e5c31af7Sopenharmony_ci		}
1430e5c31af7Sopenharmony_ci		else
1431e5c31af7Sopenharmony_ci		{
1432e5c31af7Sopenharmony_ci			const int		mantissaBits	= getMinMantissaBits(precision);
1433e5c31af7Sopenharmony_ci			const deUint32	maxUlpDiff		= getMaxUlpDiffFromBits(mantissaBits);	// ULP diff for rounded integer value.
1434e5c31af7Sopenharmony_ci			const float		eps				= getEpsFromBits(1.0f, mantissaBits);	// epsilon for rounding bounds
1435e5c31af7Sopenharmony_ci
1436e5c31af7Sopenharmony_ci			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1437e5c31af7Sopenharmony_ci			{
1438e5c31af7Sopenharmony_ci				const float		in0			= ((const float*)inputs[0])[compNdx];
1439e5c31af7Sopenharmony_ci				const float		out0		= ((const float*)outputs[0])[compNdx];
1440e5c31af7Sopenharmony_ci				const int		minRes		= int(deFloatCeil(in0-eps));
1441e5c31af7Sopenharmony_ci				const int		maxRes		= int(deFloatCeil(in0+eps));
1442e5c31af7Sopenharmony_ci				bool			anyOk		= false;
1443e5c31af7Sopenharmony_ci
1444e5c31af7Sopenharmony_ci				for (int roundedVal = minRes; roundedVal <= maxRes; roundedVal++)
1445e5c31af7Sopenharmony_ci				{
1446e5c31af7Sopenharmony_ci					const deUint32 ulpDiff = getUlpDiffIgnoreZeroSign(out0, float(roundedVal));
1447e5c31af7Sopenharmony_ci
1448e5c31af7Sopenharmony_ci					if (ulpDiff <= maxUlpDiff)
1449e5c31af7Sopenharmony_ci					{
1450e5c31af7Sopenharmony_ci						anyOk = true;
1451e5c31af7Sopenharmony_ci						break;
1452e5c31af7Sopenharmony_ci					}
1453e5c31af7Sopenharmony_ci				}
1454e5c31af7Sopenharmony_ci
1455e5c31af7Sopenharmony_ci				if (!anyOk && de::inRange(0, minRes, maxRes))
1456e5c31af7Sopenharmony_ci				{
1457e5c31af7Sopenharmony_ci					// Allow -0 as well.
1458e5c31af7Sopenharmony_ci					const int ulpDiff = de::abs((int)tcu::Float32(out0).bits() - (int)0x80000000u);
1459e5c31af7Sopenharmony_ci					anyOk = ((deUint32)ulpDiff <= maxUlpDiff);
1460e5c31af7Sopenharmony_ci				}
1461e5c31af7Sopenharmony_ci
1462e5c31af7Sopenharmony_ci				if (!anyOk)
1463e5c31af7Sopenharmony_ci				{
1464e5c31af7Sopenharmony_ci					m_failMsg << "Expected [" << compNdx << "] = [" << minRes << ", " << maxRes << "] with ULP threshold " << tcu::toHex(maxUlpDiff);
1465e5c31af7Sopenharmony_ci					return false;
1466e5c31af7Sopenharmony_ci				}
1467e5c31af7Sopenharmony_ci			}
1468e5c31af7Sopenharmony_ci		}
1469e5c31af7Sopenharmony_ci
1470e5c31af7Sopenharmony_ci		return true;
1471e5c31af7Sopenharmony_ci	}
1472e5c31af7Sopenharmony_ci};
1473e5c31af7Sopenharmony_ci
1474e5c31af7Sopenharmony_ciclass FractCase : public CommonFunctionCase
1475e5c31af7Sopenharmony_ci{
1476e5c31af7Sopenharmony_cipublic:
1477e5c31af7Sopenharmony_ci	FractCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
1478e5c31af7Sopenharmony_ci		: CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "fract", shaderType)
1479e5c31af7Sopenharmony_ci	{
1480e5c31af7Sopenharmony_ci		m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
1481e5c31af7Sopenharmony_ci		m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision)));
1482e5c31af7Sopenharmony_ci		m_spec.source = "out0 = fract(in0);";
1483e5c31af7Sopenharmony_ci	}
1484e5c31af7Sopenharmony_ci
1485e5c31af7Sopenharmony_ci	void getInputValues (int numValues, void* const* values) const
1486e5c31af7Sopenharmony_ci	{
1487e5c31af7Sopenharmony_ci		const Vec2 ranges[] =
1488e5c31af7Sopenharmony_ci		{
1489e5c31af7Sopenharmony_ci			Vec2(-2.0f,		2.0f),	// lowp
1490e5c31af7Sopenharmony_ci			Vec2(-1e3f,		1e3f),	// mediump
1491e5c31af7Sopenharmony_ci			Vec2(-1e7f,		1e7f)	// highp
1492e5c31af7Sopenharmony_ci		};
1493e5c31af7Sopenharmony_ci
1494e5c31af7Sopenharmony_ci		de::Random				rnd				(deStringHash(getName()) ^ 0xac23fu);
1495e5c31af7Sopenharmony_ci		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
1496e5c31af7Sopenharmony_ci		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
1497e5c31af7Sopenharmony_ci		const int				scalarSize		= glu::getDataTypeScalarSize(type);
1498e5c31af7Sopenharmony_ci		int						numSpecialCases	= 0;
1499e5c31af7Sopenharmony_ci
1500e5c31af7Sopenharmony_ci		// Special cases.
1501e5c31af7Sopenharmony_ci		if (precision != glu::PRECISION_LOWP)
1502e5c31af7Sopenharmony_ci		{
1503e5c31af7Sopenharmony_ci			DE_ASSERT(numValues >= 10);
1504e5c31af7Sopenharmony_ci			for (int ndx = 0; ndx < 10; ndx++)
1505e5c31af7Sopenharmony_ci			{
1506e5c31af7Sopenharmony_ci				const float v = de::clamp(float(ndx) - 5.5f, ranges[precision].x(), ranges[precision].y());
1507e5c31af7Sopenharmony_ci				std::fill((float*)values[0], (float*)values[0] + scalarSize, v);
1508e5c31af7Sopenharmony_ci				numSpecialCases += 1;
1509e5c31af7Sopenharmony_ci			}
1510e5c31af7Sopenharmony_ci		}
1511e5c31af7Sopenharmony_ci
1512e5c31af7Sopenharmony_ci		// Random cases.
1513e5c31af7Sopenharmony_ci		fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), (float*)values[0] + numSpecialCases*scalarSize, (numValues-numSpecialCases)*scalarSize);
1514e5c31af7Sopenharmony_ci
1515e5c31af7Sopenharmony_ci		// If precision is mediump, make sure values can be represented in fp16 exactly
1516e5c31af7Sopenharmony_ci		if (precision == glu::PRECISION_MEDIUMP)
1517e5c31af7Sopenharmony_ci		{
1518e5c31af7Sopenharmony_ci			for (int ndx = 0; ndx < numValues*scalarSize; ndx++)
1519e5c31af7Sopenharmony_ci				((float*)values[0])[ndx] = tcu::Float16(((float*)values[0])[ndx]).asFloat();
1520e5c31af7Sopenharmony_ci		}
1521e5c31af7Sopenharmony_ci	}
1522e5c31af7Sopenharmony_ci
1523e5c31af7Sopenharmony_ci	bool compare (const void* const* inputs, const void* const* outputs)
1524e5c31af7Sopenharmony_ci	{
1525e5c31af7Sopenharmony_ci		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
1526e5c31af7Sopenharmony_ci		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
1527e5c31af7Sopenharmony_ci		const bool				hasZeroSign		= supportsSignedZero(precision);
1528e5c31af7Sopenharmony_ci		const int				scalarSize		= glu::getDataTypeScalarSize(type);
1529e5c31af7Sopenharmony_ci
1530e5c31af7Sopenharmony_ci		if (precision == glu::PRECISION_HIGHP || precision == glu::PRECISION_MEDIUMP)
1531e5c31af7Sopenharmony_ci		{
1532e5c31af7Sopenharmony_ci			// Require exact result.
1533e5c31af7Sopenharmony_ci			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1534e5c31af7Sopenharmony_ci			{
1535e5c31af7Sopenharmony_ci				const float		in0			= ((const float*)inputs[0])[compNdx];
1536e5c31af7Sopenharmony_ci				const float		out0		= ((const float*)outputs[0])[compNdx];
1537e5c31af7Sopenharmony_ci				const float		ref			= deFloatFrac(in0);
1538e5c31af7Sopenharmony_ci
1539e5c31af7Sopenharmony_ci				const deUint32	ulpDiff		= hasZeroSign ? getUlpDiff(out0, ref) : getUlpDiffIgnoreZeroSign(out0, ref);
1540e5c31af7Sopenharmony_ci
1541e5c31af7Sopenharmony_ci				if (ulpDiff > 0)
1542e5c31af7Sopenharmony_ci				{
1543e5c31af7Sopenharmony_ci					m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref) << ", got ULP diff " << tcu::toHex(ulpDiff);
1544e5c31af7Sopenharmony_ci					return false;
1545e5c31af7Sopenharmony_ci				}
1546e5c31af7Sopenharmony_ci			}
1547e5c31af7Sopenharmony_ci		}
1548e5c31af7Sopenharmony_ci		else
1549e5c31af7Sopenharmony_ci		{
1550e5c31af7Sopenharmony_ci			const int		mantissaBits	= getMinMantissaBits(precision);
1551e5c31af7Sopenharmony_ci			const float		eps				= getEpsFromBits(1.0f, mantissaBits);	// epsilon for rounding bounds
1552e5c31af7Sopenharmony_ci
1553e5c31af7Sopenharmony_ci			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1554e5c31af7Sopenharmony_ci			{
1555e5c31af7Sopenharmony_ci				const float		in0			= ((const float*)inputs[0])[compNdx];
1556e5c31af7Sopenharmony_ci				const float		out0		= ((const float*)outputs[0])[compNdx];
1557e5c31af7Sopenharmony_ci
1558e5c31af7Sopenharmony_ci				if (int(deFloatFloor(in0-eps)) == int(deFloatFloor(in0+eps)))
1559e5c31af7Sopenharmony_ci				{
1560e5c31af7Sopenharmony_ci					const float		ref			= deFloatFrac(in0);
1561e5c31af7Sopenharmony_ci					const int		bitsLost	= numBitsLostInOp(in0, ref);
1562e5c31af7Sopenharmony_ci					const deUint32	maxUlpDiff	= getMaxUlpDiffFromBits(de::max(0, mantissaBits-bitsLost));	// ULP diff for rounded integer value.
1563e5c31af7Sopenharmony_ci					const deUint32	ulpDiff		= getUlpDiffIgnoreZeroSign(out0, ref);
1564e5c31af7Sopenharmony_ci
1565e5c31af7Sopenharmony_ci					if (ulpDiff > maxUlpDiff)
1566e5c31af7Sopenharmony_ci					{
1567e5c31af7Sopenharmony_ci						m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref) << " with ULP threshold " << tcu::toHex(maxUlpDiff) << ", got diff " << tcu::toHex(ulpDiff);
1568e5c31af7Sopenharmony_ci						return false;
1569e5c31af7Sopenharmony_ci					}
1570e5c31af7Sopenharmony_ci				}
1571e5c31af7Sopenharmony_ci				else
1572e5c31af7Sopenharmony_ci				{
1573e5c31af7Sopenharmony_ci					if (out0 >= 1.0f)
1574e5c31af7Sopenharmony_ci					{
1575e5c31af7Sopenharmony_ci						m_failMsg << "Expected [" << compNdx << "] < 1.0";
1576e5c31af7Sopenharmony_ci						return false;
1577e5c31af7Sopenharmony_ci					}
1578e5c31af7Sopenharmony_ci				}
1579e5c31af7Sopenharmony_ci			}
1580e5c31af7Sopenharmony_ci		}
1581e5c31af7Sopenharmony_ci
1582e5c31af7Sopenharmony_ci		return true;
1583e5c31af7Sopenharmony_ci	}
1584e5c31af7Sopenharmony_ci};
1585e5c31af7Sopenharmony_ci
1586e5c31af7Sopenharmony_ciShaderCommonFunctionTests::ShaderCommonFunctionTests (Context& context)
1587e5c31af7Sopenharmony_ci	: TestCaseGroup(context, "common", "Common function tests")
1588e5c31af7Sopenharmony_ci{
1589e5c31af7Sopenharmony_ci}
1590e5c31af7Sopenharmony_ci
1591e5c31af7Sopenharmony_ciShaderCommonFunctionTests::~ShaderCommonFunctionTests (void)
1592e5c31af7Sopenharmony_ci{
1593e5c31af7Sopenharmony_ci}
1594e5c31af7Sopenharmony_ci
1595e5c31af7Sopenharmony_citemplate<class TestClass>
1596e5c31af7Sopenharmony_cistatic void addFunctionCases (TestCaseGroup* parent, const char* functionName, bool floatTypes, bool intTypes, bool uintTypes)
1597e5c31af7Sopenharmony_ci{
1598e5c31af7Sopenharmony_ci	tcu::TestCaseGroup* group = new tcu::TestCaseGroup(parent->getTestContext(), functionName, functionName);
1599e5c31af7Sopenharmony_ci	parent->addChild(group);
1600e5c31af7Sopenharmony_ci
1601e5c31af7Sopenharmony_ci	const glu::DataType scalarTypes[] =
1602e5c31af7Sopenharmony_ci	{
1603e5c31af7Sopenharmony_ci		glu::TYPE_FLOAT,
1604e5c31af7Sopenharmony_ci		glu::TYPE_INT,
1605e5c31af7Sopenharmony_ci		glu::TYPE_UINT
1606e5c31af7Sopenharmony_ci	};
1607e5c31af7Sopenharmony_ci
1608e5c31af7Sopenharmony_ci	for (int scalarTypeNdx = 0; scalarTypeNdx < DE_LENGTH_OF_ARRAY(scalarTypes); scalarTypeNdx++)
1609e5c31af7Sopenharmony_ci	{
1610e5c31af7Sopenharmony_ci		const glu::DataType scalarType = scalarTypes[scalarTypeNdx];
1611e5c31af7Sopenharmony_ci
1612e5c31af7Sopenharmony_ci		if ((!floatTypes && scalarType == glu::TYPE_FLOAT)	||
1613e5c31af7Sopenharmony_ci			(!intTypes && scalarType == glu::TYPE_INT)		||
1614e5c31af7Sopenharmony_ci			(!uintTypes && scalarType == glu::TYPE_UINT))
1615e5c31af7Sopenharmony_ci			continue;
1616e5c31af7Sopenharmony_ci
1617e5c31af7Sopenharmony_ci		for (int vecSize = 1; vecSize <= 4; vecSize++)
1618e5c31af7Sopenharmony_ci		{
1619e5c31af7Sopenharmony_ci			for (int prec = glu::PRECISION_LOWP; prec <= glu::PRECISION_HIGHP; prec++)
1620e5c31af7Sopenharmony_ci			{
1621e5c31af7Sopenharmony_ci				for (int shaderType = glu::SHADERTYPE_VERTEX; shaderType <= glu::SHADERTYPE_FRAGMENT; shaderType++)
1622e5c31af7Sopenharmony_ci					group->addChild(new TestClass(parent->getContext(), glu::DataType(scalarType + vecSize - 1), glu::Precision(prec), glu::ShaderType(shaderType)));
1623e5c31af7Sopenharmony_ci			}
1624e5c31af7Sopenharmony_ci		}
1625e5c31af7Sopenharmony_ci	}
1626e5c31af7Sopenharmony_ci}
1627e5c31af7Sopenharmony_ci
1628e5c31af7Sopenharmony_civoid ShaderCommonFunctionTests::init (void)
1629e5c31af7Sopenharmony_ci{
1630e5c31af7Sopenharmony_ci	//																	Float?	Int?	Uint?
1631e5c31af7Sopenharmony_ci	addFunctionCases<AbsCase>				(this,	"abs",				true,	true,	false);
1632e5c31af7Sopenharmony_ci	addFunctionCases<SignCase>				(this,	"sign",				true,	true,	false);
1633e5c31af7Sopenharmony_ci	addFunctionCases<FloorCase>				(this,	"floor",			true,	false,	false);
1634e5c31af7Sopenharmony_ci	addFunctionCases<TruncCase>				(this,	"trunc",			true,	false,	false);
1635e5c31af7Sopenharmony_ci	addFunctionCases<RoundCase>				(this,	"round",			true,	false,	false);
1636e5c31af7Sopenharmony_ci	addFunctionCases<RoundEvenCase>			(this,	"roundeven",		true,	false,	false);
1637e5c31af7Sopenharmony_ci	addFunctionCases<CeilCase>				(this,	"ceil",				true,	false,	false);
1638e5c31af7Sopenharmony_ci	addFunctionCases<FractCase>				(this,	"fract",			true,	false,	false);
1639e5c31af7Sopenharmony_ci	// mod
1640e5c31af7Sopenharmony_ci	addFunctionCases<ModfCase>				(this,	"modf",				true,	false,	false);
1641e5c31af7Sopenharmony_ci	// min
1642e5c31af7Sopenharmony_ci	// max
1643e5c31af7Sopenharmony_ci	// clamp
1644e5c31af7Sopenharmony_ci	// mix
1645e5c31af7Sopenharmony_ci	// step
1646e5c31af7Sopenharmony_ci	// smoothstep
1647e5c31af7Sopenharmony_ci	addFunctionCases<IsnanCase>				(this,	"isnan",			true,	false,	false);
1648e5c31af7Sopenharmony_ci	addFunctionCases<IsinfCase>				(this,	"isinf",			true,	false,	false);
1649e5c31af7Sopenharmony_ci	addFunctionCases<FloatBitsToIntCase>	(this,	"floatbitstoint",	true,	false,	false);
1650e5c31af7Sopenharmony_ci	addFunctionCases<FloatBitsToUintCase>	(this,	"floatbitstouint",	true,	false,	false);
1651e5c31af7Sopenharmony_ci
1652e5c31af7Sopenharmony_ci	// (u)intBitsToFloat()
1653e5c31af7Sopenharmony_ci	{
1654e5c31af7Sopenharmony_ci		tcu::TestCaseGroup* intGroup	= new tcu::TestCaseGroup(m_testCtx, "intbitstofloat",	"intBitsToFloat() Tests");
1655e5c31af7Sopenharmony_ci		tcu::TestCaseGroup* uintGroup	= new tcu::TestCaseGroup(m_testCtx, "uintbitstofloat",	"uintBitsToFloat() Tests");
1656e5c31af7Sopenharmony_ci
1657e5c31af7Sopenharmony_ci		addChild(intGroup);
1658e5c31af7Sopenharmony_ci		addChild(uintGroup);
1659e5c31af7Sopenharmony_ci
1660e5c31af7Sopenharmony_ci		for (int vecSize = 1; vecSize < 4; vecSize++)
1661e5c31af7Sopenharmony_ci		{
1662e5c31af7Sopenharmony_ci			const glu::DataType		intType		= vecSize > 1 ? glu::getDataTypeIntVec(vecSize) : glu::TYPE_INT;
1663e5c31af7Sopenharmony_ci			const glu::DataType		uintType	= vecSize > 1 ? glu::getDataTypeUintVec(vecSize) : glu::TYPE_UINT;
1664e5c31af7Sopenharmony_ci
1665e5c31af7Sopenharmony_ci			for (int shaderType = glu::SHADERTYPE_VERTEX; shaderType <= glu::SHADERTYPE_FRAGMENT; shaderType++)
1666e5c31af7Sopenharmony_ci			{
1667e5c31af7Sopenharmony_ci				intGroup->addChild(new BitsToFloatCase(m_context, intType, glu::ShaderType(shaderType)));
1668e5c31af7Sopenharmony_ci				uintGroup->addChild(new BitsToFloatCase(m_context, uintType, glu::ShaderType(shaderType)));
1669e5c31af7Sopenharmony_ci			}
1670e5c31af7Sopenharmony_ci		}
1671e5c31af7Sopenharmony_ci	}
1672e5c31af7Sopenharmony_ci}
1673e5c31af7Sopenharmony_ci
1674e5c31af7Sopenharmony_ci} // Functional
1675e5c31af7Sopenharmony_ci} // gles3
1676e5c31af7Sopenharmony_ci} // deqp
1677