• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2015 The Khronos Group Inc.
6  * Copyright (c) 2015 Samsung Electronics Co., Ltd.
7  * Copyright (c) 2016 The Android Open Source Project
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  *//*!
22  * \file
23  * \brief Common built-in function tests.
24  *//*--------------------------------------------------------------------*/
25 
26 #include "vktShaderCommonFunctionTests.hpp"
27 #include "vktShaderExecutor.hpp"
28 #include "vkQueryUtil.hpp"
29 #include "gluContextInfo.hpp"
30 #include "tcuTestLog.hpp"
31 #include "tcuFormatUtil.hpp"
32 #include "tcuFloat.hpp"
33 #include "tcuInterval.hpp"
34 #include "tcuFloatFormat.hpp"
35 #include "tcuVectorUtil.hpp"
36 #include "deRandom.hpp"
37 #include "deMath.h"
38 #include "deString.h"
39 #include "deArrayUtil.hpp"
40 #include "deSharedPtr.hpp"
41 #include <algorithm>
42 
43 namespace vkt
44 {
45 
46 namespace shaderexecutor
47 {
48 
49 
50 using std::vector;
51 using std::string;
52 using tcu::TestLog;
53 
54 using tcu::Vec2;
55 using tcu::Vec3;
56 using tcu::Vec4;
57 using tcu::IVec2;
58 using tcu::IVec3;
59 using tcu::IVec4;
60 
61 namespace
62 {
63 
64 // Utilities
65 
66 template<typename T, int Size>
67 struct VecArrayAccess
68 {
69 public:
VecArrayAccessvkt::shaderexecutor::__anonf42db1200111::VecArrayAccess70 									VecArrayAccess	(const void* ptr) : m_array((tcu::Vector<T, Size>*)ptr) {}
~VecArrayAccessvkt::shaderexecutor::__anonf42db1200111::VecArrayAccess71 									~VecArrayAccess	(void) {}
72 
operator []vkt::shaderexecutor::__anonf42db1200111::VecArrayAccess73 	const tcu::Vector<T, Size>&		operator[]		(size_t offset) const	{ return m_array[offset];	}
operator []vkt::shaderexecutor::__anonf42db1200111::VecArrayAccess74 	tcu::Vector<T, Size>&			operator[]		(size_t offset)			{ return m_array[offset];	}
75 
76 private:
77 	tcu::Vector<T, Size>*			m_array;
78 };
79 
80 template<typename T, int Size>
fillRandomVectors(de::Random & rnd,const tcu::Vector<T,Size> & minValue,const tcu::Vector<T,Size> & maxValue,void * dst,int numValues,int offset=0)81 static void fillRandomVectors (de::Random& rnd, const tcu::Vector<T, Size>& minValue, const tcu::Vector<T, Size>& maxValue, void* dst, int numValues, int offset = 0)
82 {
83 	VecArrayAccess<T, Size> access(dst);
84 	for (int ndx = 0; ndx < numValues; ndx++)
85 		access[offset + ndx] = tcu::randomVector<T, Size>(rnd, minValue, maxValue);
86 }
87 
88 template<typename T>
fillRandomScalars(de::Random & rnd,T minValue,T maxValue,void * dst,int numValues,int offset=0)89 static void fillRandomScalars (de::Random& rnd, T minValue, T maxValue, void* dst, int numValues, int offset = 0)
90 {
91 	T* typedPtr = (T*)dst;
92 	for (int ndx = 0; ndx < numValues; ndx++)
93 		typedPtr[offset + ndx] = de::randomScalar<T>(rnd, minValue, maxValue);
94 }
95 
getUlpDiff(float a,float b)96 inline deUint32 getUlpDiff (float a, float b)
97 {
98 	const deUint32	aBits	= tcu::Float32(a).bits();
99 	const deUint32	bBits	= tcu::Float32(b).bits();
100 	return aBits > bBits ? aBits - bBits : bBits - aBits;
101 }
102 
getUlpDiffIgnoreZeroSign(float a,float b)103 inline deUint32 getUlpDiffIgnoreZeroSign (float a, float b)
104 {
105 	if (tcu::Float32(a).isZero())
106 		return getUlpDiff(tcu::Float32::construct(tcu::Float32(b).sign(), 0, 0).asFloat(), b);
107 	else if (tcu::Float32(b).isZero())
108 		return getUlpDiff(a, tcu::Float32::construct(tcu::Float32(a).sign(), 0, 0).asFloat());
109 	else
110 		return getUlpDiff(a, b);
111 }
112 
getMaxUlpDiffFromBits(int numAccurateBits,int numTotalBits)113 inline deUint64 getMaxUlpDiffFromBits (int numAccurateBits, int numTotalBits)
114 {
115 	const int		numGarbageBits	= numTotalBits-numAccurateBits;
116 	const deUint64	mask			= (1ull<<numGarbageBits)-1ull;
117 
118 	return mask;
119 }
120 
getNumMantissaBits(glu::DataType type)121 static int getNumMantissaBits (glu::DataType type)
122 {
123 	DE_ASSERT(glu::isDataTypeFloatOrVec(type) || glu::isDataTypeDoubleOrDVec(type));
124 	return (glu::isDataTypeFloatOrVec(type) ? 23 : 52);
125 }
126 
getMinMantissaBits(glu::DataType type,glu::Precision precision)127 static int getMinMantissaBits (glu::DataType type, glu::Precision precision)
128 {
129 	if (glu::isDataTypeDoubleOrDVec(type))
130 	{
131 		return tcu::Float64::MANTISSA_BITS;
132 	}
133 
134 	// Float case.
135 	const int bits[] =
136 	{
137 		7,								// lowp
138 		tcu::Float16::MANTISSA_BITS,	// mediump
139 		tcu::Float32::MANTISSA_BITS,	// highp
140 	};
141 	DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(bits) == glu::PRECISION_LAST);
142 	DE_ASSERT(de::inBounds<int>(precision, 0, DE_LENGTH_OF_ARRAY(bits)));
143 	return bits[precision];
144 }
145 
getExponentBits(glu::DataType type)146 static int getExponentBits (glu::DataType type)
147 {
148 	DE_ASSERT(glu::isDataTypeFloatOrVec(type) || glu::isDataTypeDoubleOrDVec(type));
149 	return (glu::isDataTypeFloatOrVec(type) ? static_cast<int>(tcu::Float32::EXPONENT_BITS) : static_cast<int>(tcu::Float64::EXPONENT_BITS));
150 }
151 
getExponentMask(int exponentBits)152 static deUint32 getExponentMask (int exponentBits)
153 {
154 	DE_ASSERT(exponentBits > 0);
155 	return ((1u<<exponentBits) - 1u);
156 }
157 
getComponentByteSize(glu::DataType type)158 static int getComponentByteSize (glu::DataType type)
159 {
160 	const glu::DataType scalarType = glu::getDataTypeScalarType(type);
161 
162 	DE_ASSERT(	scalarType == glu::TYPE_FLOAT	||
163 				scalarType == glu::TYPE_FLOAT16	||
164 				scalarType == glu::TYPE_DOUBLE	||
165 				scalarType == glu::TYPE_INT		||
166 				scalarType == glu::TYPE_UINT	||
167 				scalarType == glu::TYPE_INT8	||
168 				scalarType == glu::TYPE_UINT8	||
169 				scalarType == glu::TYPE_INT16	||
170 				scalarType == glu::TYPE_UINT16	||
171 				scalarType == glu::TYPE_BOOL	);
172 
173 	switch (scalarType)
174 	{
175 	case glu::TYPE_INT8:
176 	case glu::TYPE_UINT8:
177 		return 1;
178 	case glu::TYPE_INT16:
179 	case glu::TYPE_UINT16:
180 	case glu::TYPE_FLOAT16:
181 		return 2;
182 	case glu::TYPE_BOOL:
183 	case glu::TYPE_INT:
184 	case glu::TYPE_UINT:
185 	case glu::TYPE_FLOAT:
186 		return 4;
187 	case glu::TYPE_DOUBLE:
188 		return 8;
189 	default:
190 		DE_ASSERT(false); break;
191 	}
192 	// Unreachable.
193 	return 0;
194 }
195 
getScalarSizes(const vector<Symbol> & symbols)196 static vector<int> getScalarSizes (const vector<Symbol>& symbols)
197 {
198 	vector<int> sizes(symbols.size());
199 	for (int ndx = 0; ndx < (int)symbols.size(); ++ndx)
200 		sizes[ndx] = symbols[ndx].varType.getScalarSize();
201 	return sizes;
202 }
203 
getComponentByteSizes(const vector<Symbol> & symbols)204 static vector<int> getComponentByteSizes (const vector<Symbol>& symbols)
205 {
206 	vector<int> sizes;
207 	sizes.reserve(symbols.size());
208 	for (const auto& sym : symbols)
209 		sizes.push_back(getComponentByteSize(sym.varType.getBasicType()));
210 	return sizes;
211 }
212 
computeTotalByteSize(const vector<Symbol> & symbols)213 static int computeTotalByteSize (const vector<Symbol>& symbols)
214 {
215 	int totalSize = 0;
216 	for (const auto& sym : symbols)
217 		totalSize += getComponentByteSize(sym.varType.getBasicType()) * sym.varType.getScalarSize();
218 	return totalSize;
219 }
220 
getInputOutputPointers(const vector<Symbol> & symbols,vector<deUint8> & data,const int numValues)221 static vector<void*> getInputOutputPointers (const vector<Symbol>& symbols, vector<deUint8>& data, const int numValues)
222 {
223 	vector<void*>	pointers		(symbols.size());
224 	int				curScalarOffset	= 0;
225 
226 	for (int varNdx = 0; varNdx < (int)symbols.size(); ++varNdx)
227 	{
228 		const Symbol&	var				= symbols[varNdx];
229 		const int		scalarSize		= var.varType.getScalarSize();
230 		const auto		componentBytes	= getComponentByteSize(var.varType.getBasicType());
231 
232 		// Uses planar layout as input/output specs do not support strides.
233 		pointers[varNdx] = &data[curScalarOffset];
234 		curScalarOffset += scalarSize*numValues*componentBytes;
235 	}
236 
237 	DE_ASSERT(curScalarOffset == (int)data.size());
238 
239 	return pointers;
240 }
241 
checkTypeSupport(Context & context,glu::DataType dataType)242 void checkTypeSupport (Context& context, glu::DataType dataType)
243 {
244 	if (glu::isDataTypeDoubleOrDVec(dataType))
245 	{
246 		const auto&	vki				= context.getInstanceInterface();
247 		const auto	physicalDevice	= context.getPhysicalDevice();
248 
249 		const auto features = vk::getPhysicalDeviceFeatures(vki, physicalDevice);
250 		if (!features.shaderFloat64)
251 			TCU_THROW(NotSupportedError, "64-bit floats not supported by the implementation");
252 	}
253 }
254 
255 // \todo [2013-08-08 pyry] Make generic utility and move to glu?
256 
257 struct HexFloat
258 {
259 	const float value;
HexFloatvkt::shaderexecutor::__anonf42db1200111::HexFloat260 	HexFloat (const float value_) : value(value_) {}
261 };
262 
operator <<(std::ostream & str,const HexFloat & v)263 std::ostream& operator<< (std::ostream& str, const HexFloat& v)
264 {
265 	return str << v.value << " / " << tcu::toHex(tcu::Float32(v.value).bits());
266 }
267 
268 struct HexDouble
269 {
270 	const double value;
HexDoublevkt::shaderexecutor::__anonf42db1200111::HexDouble271 	HexDouble (const double value_) : value(value_) {}
272 };
273 
operator <<(std::ostream & str,const HexDouble & v)274 std::ostream& operator<< (std::ostream& str, const HexDouble& v)
275 {
276 	return str << v.value << " / " << tcu::toHex(tcu::Float64(v.value).bits());
277 }
278 
279 struct HexBool
280 {
281 	const deUint32 value;
HexBoolvkt::shaderexecutor::__anonf42db1200111::HexBool282 	HexBool (const deUint32 value_) : value(value_) {}
283 };
284 
operator <<(std::ostream & str,const HexBool & v)285 std::ostream& operator<< (std::ostream& str, const HexBool& v)
286 {
287 	return str << (v.value ? "true" : "false") << " / " << tcu::toHex(v.value);
288 }
289 
290 struct VarValue
291 {
292 	const glu::VarType&	type;
293 	const void*			value;
294 
VarValuevkt::shaderexecutor::__anonf42db1200111::VarValue295 	VarValue (const glu::VarType& type_, const void* value_) : type(type_), value(value_) {}
296 };
297 
operator <<(std::ostream & str,const VarValue & varValue)298 std::ostream& operator<< (std::ostream& str, const VarValue& varValue)
299 {
300 	DE_ASSERT(varValue.type.isBasicType());
301 
302 	const glu::DataType		basicType		= varValue.type.getBasicType();
303 	const glu::DataType		scalarType		= glu::getDataTypeScalarType(basicType);
304 	const int				numComponents	= glu::getDataTypeScalarSize(basicType);
305 
306 	if (numComponents > 1)
307 		str << glu::getDataTypeName(basicType) << "(";
308 
309 	for (int compNdx = 0; compNdx < numComponents; compNdx++)
310 	{
311 		if (compNdx != 0)
312 			str << ", ";
313 
314 		switch (scalarType)
315 		{
316 			case glu::TYPE_FLOAT:	str << HexFloat(((const float*)varValue.value)[compNdx]);			break;
317 			case glu::TYPE_INT:		str << ((const deInt32*)varValue.value)[compNdx];					break;
318 			case glu::TYPE_UINT:	str << tcu::toHex(((const deUint32*)varValue.value)[compNdx]);		break;
319 			case glu::TYPE_BOOL:	str << HexBool(((const deUint32*)varValue.value)[compNdx]);			break;
320 			case glu::TYPE_DOUBLE:	str << HexDouble(((const double*)varValue.value)[compNdx]);			break;
321 
322 			default:
323 				DE_ASSERT(false);
324 		}
325 	}
326 
327 	if (numComponents > 1)
328 		str << ")";
329 
330 	return str;
331 }
332 
getCommonFuncCaseName(glu::DataType baseType,glu::Precision precision)333 static std::string getCommonFuncCaseName (glu::DataType baseType, glu::Precision precision)
334 {
335 	const bool isDouble = glu::isDataTypeDoubleOrDVec(baseType);
336 	return string(glu::getDataTypeName(baseType)) + (isDouble ? "" : getPrecisionPostfix(precision)) + "_compute";
337 }
338 
339 template<class TestClass>
addFunctionCases(tcu::TestCaseGroup * parent,const char * functionName,const std::vector<glu::DataType> & scalarTypes)340 static void addFunctionCases (tcu::TestCaseGroup* parent, const char* functionName, const std::vector<glu::DataType>& scalarTypes)
341 {
342 	tcu::TestCaseGroup* group = new tcu::TestCaseGroup(parent->getTestContext(), functionName, functionName);
343 	parent->addChild(group);
344 
345 	for (const auto scalarType : scalarTypes)
346 	{
347 		const bool	isDouble	= glu::isDataTypeDoubleOrDVec(scalarType);
348 		const int	lowestPrec	= (isDouble ? glu::PRECISION_LAST : glu::PRECISION_MEDIUMP);
349 		const int	highestPrec	= (isDouble ? glu::PRECISION_LAST : glu::PRECISION_HIGHP);
350 
351 		for (int vecSize = 1; vecSize <= 4; vecSize++)
352 		{
353 			for (int prec = lowestPrec; prec <= highestPrec; prec++)
354 			{
355 				group->addChild(new TestClass(parent->getTestContext(), glu::DataType(scalarType + vecSize - 1), glu::Precision(prec)));
356 			}
357 		}
358 	}
359 }
360 
361 // CommonFunctionCase
362 
363 class CommonFunctionCase : public TestCase
364 {
365 public:
366 										CommonFunctionCase			(tcu::TestContext& testCtx, const char* name, const char* description);
367 										~CommonFunctionCase			(void);
initPrograms(vk::SourceCollections & programCollection) const368 	virtual	void						initPrograms				(vk::SourceCollections& programCollection) const
369 										{
370 											generateSources(glu::SHADERTYPE_COMPUTE, m_spec, programCollection);
371 										}
372 
373 	virtual TestInstance*				createInstance				(Context& context) const = 0;
374 
375 protected:
376 										CommonFunctionCase			(const CommonFunctionCase&);
377 	CommonFunctionCase&					operator=					(const CommonFunctionCase&);
378 
379 	ShaderSpec							m_spec;
380 	const int							m_numValues;
381 };
382 
CommonFunctionCase(tcu::TestContext & testCtx,const char * name,const char * description)383 CommonFunctionCase::CommonFunctionCase (tcu::TestContext& testCtx, const char* name, const char* description)
384 	: TestCase		(testCtx, name, description)
385 	, m_numValues	(100)
386 {
387 }
388 
~CommonFunctionCase(void)389 CommonFunctionCase::~CommonFunctionCase (void)
390 {
391 }
392 
393 // CommonFunctionTestInstance
394 
395 class CommonFunctionTestInstance : public TestInstance
396 {
397 public:
CommonFunctionTestInstance(Context & context,const ShaderSpec & spec,int numValues,const char * name)398 										CommonFunctionTestInstance	(Context& context, const ShaderSpec& spec, int numValues, const char* name)
399 											: TestInstance	(context)
400 											, m_spec		(spec)
401 											, m_numValues	(numValues)
402 											, m_name		(name)
403 											, m_executor	(createExecutor(context, glu::SHADERTYPE_COMPUTE, spec))
404 										{
405 										}
406 	virtual tcu::TestStatus				iterate						(void);
407 
408 protected:
409 	virtual void						getInputValues				(int numValues, void* const* values) const = 0;
410 	virtual bool						compare						(const void* const* inputs, const void* const* outputs) = 0;
411 
412 	const ShaderSpec					m_spec;
413 	const int							m_numValues;
414 
415 	// \todo [2017-03-07 pyry] Hack used to generate seeds for test cases - get rid of this.
416 	const char*							m_name;
417 
418 	std::ostringstream					m_failMsg;					//!< Comparison failure help message.
419 
420 	de::UniquePtr<ShaderExecutor>		m_executor;
421 };
422 
iterate(void)423 tcu::TestStatus CommonFunctionTestInstance::iterate (void)
424 {
425 	const int				numInputBytes			= computeTotalByteSize(m_spec.inputs);
426 	const int				numOutputBytes			= computeTotalByteSize(m_spec.outputs);
427 	vector<deUint8>			inputData				(numInputBytes * m_numValues);
428 	vector<deUint8>			outputData				(numOutputBytes * m_numValues);
429 	const vector<void*>		inputPointers			= getInputOutputPointers(m_spec.inputs, inputData, m_numValues);
430 	const vector<void*>		outputPointers			= getInputOutputPointers(m_spec.outputs, outputData, m_numValues);
431 
432 	// Initialize input data.
433 	getInputValues(m_numValues, &inputPointers[0]);
434 
435 	// Execute shader.
436 	m_executor->execute(m_numValues, &inputPointers[0], &outputPointers[0]);
437 
438 	// Compare results.
439 	{
440 		const vector<int>		inScalarSizes		= getScalarSizes(m_spec.inputs);
441 		const vector<int>		outScalarSizes		= getScalarSizes(m_spec.outputs);
442 		const vector<int>		inCompByteSizes		= getComponentByteSizes(m_spec.inputs);
443 		const vector<int>		outCompByteSizes	= getComponentByteSizes(m_spec.outputs);
444 		vector<void*>			curInputPtr			(inputPointers.size());
445 		vector<void*>			curOutputPtr		(outputPointers.size());
446 		int						numFailed			= 0;
447 		tcu::TestContext&		testCtx				= m_context.getTestContext();
448 
449 		for (int valNdx = 0; valNdx < m_numValues; valNdx++)
450 		{
451 			// Set up pointers for comparison.
452 			for (int inNdx = 0; inNdx < (int)curInputPtr.size(); ++inNdx)
453 				curInputPtr[inNdx] = (deUint8*)inputPointers[inNdx] + inScalarSizes[inNdx]*inCompByteSizes[inNdx]*valNdx;
454 
455 			for (int outNdx = 0; outNdx < (int)curOutputPtr.size(); ++outNdx)
456 				curOutputPtr[outNdx] = (deUint8*)outputPointers[outNdx] + outScalarSizes[outNdx]*outCompByteSizes[outNdx]*valNdx;
457 
458 			if (!compare(&curInputPtr[0], &curOutputPtr[0]))
459 			{
460 				// \todo [2013-08-08 pyry] We probably want to log reference value as well?
461 
462 				testCtx.getLog() << TestLog::Message << "ERROR: comparison failed for value " << valNdx << ":\n  " << m_failMsg.str() << TestLog::EndMessage;
463 
464 				testCtx.getLog() << TestLog::Message << "  inputs:" << TestLog::EndMessage;
465 				for (int inNdx = 0; inNdx < (int)curInputPtr.size(); inNdx++)
466 					testCtx.getLog() << TestLog::Message << "    " << m_spec.inputs[inNdx].name << " = "
467 														   << VarValue(m_spec.inputs[inNdx].varType, curInputPtr[inNdx])
468 									   << TestLog::EndMessage;
469 
470 				testCtx.getLog() << TestLog::Message << "  outputs:" << TestLog::EndMessage;
471 				for (int outNdx = 0; outNdx < (int)curOutputPtr.size(); outNdx++)
472 					testCtx.getLog() << TestLog::Message << "    " << m_spec.outputs[outNdx].name << " = "
473 														   << VarValue(m_spec.outputs[outNdx].varType, curOutputPtr[outNdx])
474 									   << TestLog::EndMessage;
475 
476 				m_failMsg.str("");
477 				m_failMsg.clear();
478 				numFailed += 1;
479 			}
480 		}
481 
482 		testCtx.getLog() << TestLog::Message << (m_numValues - numFailed) << " / " << m_numValues << " values passed" << TestLog::EndMessage;
483 
484 		if (numFailed == 0)
485 			return tcu::TestStatus::pass("Pass");
486 		else
487 			return tcu::TestStatus::fail("Result comparison failed");
488 	}
489 }
490 
491 // Test cases
492 
493 class AbsCaseInstance : public CommonFunctionTestInstance
494 {
495 public:
AbsCaseInstance(Context & context,const ShaderSpec & spec,int numValues,const char * name)496 	AbsCaseInstance (Context& context, const ShaderSpec& spec, int numValues, const char* name)
497 		: CommonFunctionTestInstance	(context, spec, numValues, name)
498 	{
499 	}
500 
getInputValues(int numValues,void * const * values) const501 	void getInputValues (int numValues, void* const* values) const
502 	{
503 		const IVec2 intRanges[] =
504 		{
505 			IVec2(-(1<<7)+1,	(1<<7)-1),
506 			IVec2(-(1<<15)+1,	(1<<15)-1),
507 			IVec2(0x80000001,	0x7fffffff)
508 		};
509 
510 		de::Random				rnd			(deStringHash(m_name) ^ 0x235facu);
511 		const glu::DataType		type		= m_spec.inputs[0].varType.getBasicType();
512 		const glu::Precision	precision	= m_spec.inputs[0].varType.getPrecision();
513 		const int				scalarSize	= glu::getDataTypeScalarSize(type);
514 
515 		DE_ASSERT(!glu::isDataTypeFloatOrVec(type));
516 
517 		fillRandomScalars(rnd, intRanges[precision].x(), intRanges[precision].y(), values[0], numValues*scalarSize);
518 	}
519 
compare(const void * const * inputs,const void * const * outputs)520 	bool compare (const void* const* inputs, const void* const* outputs)
521 	{
522 		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
523 		const int				scalarSize		= glu::getDataTypeScalarSize(type);
524 
525 		DE_ASSERT(!glu::isDataTypeFloatOrVec(type));
526 
527 		for (int compNdx = 0; compNdx < scalarSize; compNdx++)
528 		{
529 			const int	in0		= ((const int*)inputs[0])[compNdx];
530 			const int	out0	= ((const int*)outputs[0])[compNdx];
531 			const int	ref0	= de::abs(in0);
532 
533 			if (out0 != ref0)
534 			{
535 				m_failMsg << "Expected [" << compNdx << "] = " << ref0;
536 				return false;
537 			}
538 		}
539 
540 		return true;
541 	}
542 };
543 
544 class AbsCase : public CommonFunctionCase
545 {
546 public:
AbsCase(tcu::TestContext & testCtx,glu::DataType baseType,glu::Precision precision)547 	AbsCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision)
548 		: CommonFunctionCase	(testCtx, getCommonFuncCaseName(baseType, precision).c_str(), "abs")
549 	{
550 		m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
551 		m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision)));
552 		m_spec.source = "out0 = abs(in0);";
553 	}
554 
createInstance(Context & ctx) const555 	TestInstance* createInstance (Context& ctx) const
556 	{
557 		return new AbsCaseInstance(ctx, m_spec, m_numValues, getName());
558 	}
559 };
560 
561 class SignCaseInstance : public CommonFunctionTestInstance
562 {
563 public:
SignCaseInstance(Context & context,const ShaderSpec & spec,int numValues,const char * name)564 	SignCaseInstance (Context& context, const ShaderSpec& spec, int numValues, const char* name)
565 		: CommonFunctionTestInstance	(context, spec, numValues, name)
566 	{
567 	}
568 
getInputValues(int numValues,void * const * values) const569 	void getInputValues (int numValues, void* const* values) const
570 	{
571 		const IVec2 intRanges[] =
572 		{
573 			IVec2(-(1<<7),		(1<<7)-1),
574 			IVec2(-(1<<15),		(1<<15)-1),
575 			IVec2(0x80000000,	0x7fffffff)
576 		};
577 
578 		de::Random				rnd			(deStringHash(m_name) ^ 0x324u);
579 		const glu::DataType		type		= m_spec.inputs[0].varType.getBasicType();
580 		const glu::Precision	precision	= m_spec.inputs[0].varType.getPrecision();
581 		const int				scalarSize	= glu::getDataTypeScalarSize(type);
582 
583 		DE_ASSERT(!glu::isDataTypeFloatOrVec(type));
584 
585 		std::fill((int*)values[0] + scalarSize*0, (int*)values[0] + scalarSize*1, +1);
586 		std::fill((int*)values[0] + scalarSize*1, (int*)values[0] + scalarSize*2, -1);
587 		std::fill((int*)values[0] + scalarSize*2, (int*)values[0] + scalarSize*3,  0);
588 		fillRandomScalars(rnd, intRanges[precision].x(), intRanges[precision].y(), (int*)values[0] + scalarSize*3, (numValues-3)*scalarSize);
589 	}
590 
compare(const void * const * inputs,const void * const * outputs)591 	bool compare (const void* const* inputs, const void* const* outputs)
592 	{
593 		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
594 		const int				scalarSize		= glu::getDataTypeScalarSize(type);
595 
596 		DE_ASSERT(!glu::isDataTypeFloatOrVec(type));
597 
598 		for (int compNdx = 0; compNdx < scalarSize; compNdx++)
599 		{
600 			const int	in0		= ((const int*)inputs[0])[compNdx];
601 			const int	out0	= ((const int*)outputs[0])[compNdx];
602 			const int	ref0	= in0 < 0 ? -1 :
603 								  in0 > 0 ? +1 : 0;
604 
605 			if (out0 != ref0)
606 			{
607 				m_failMsg << "Expected [" << compNdx << "] = " << ref0;
608 				return false;
609 			}
610 		}
611 
612 		return true;
613 	}
614 };
615 
616 class SignCase : public CommonFunctionCase
617 {
618 public:
SignCase(tcu::TestContext & testCtx,glu::DataType baseType,glu::Precision precision)619 	SignCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision)
620 		: CommonFunctionCase	(testCtx, getCommonFuncCaseName(baseType, precision).c_str(), "sign")
621 	{
622 		m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
623 		m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision)));
624 		m_spec.source = "out0 = sign(in0);";
625 	}
626 
createInstance(Context & ctx) const627 	TestInstance* createInstance (Context& ctx) const
628 	{
629 		return new SignCaseInstance(ctx, m_spec, m_numValues, getName());
630 	}
631 };
632 
infNanRandomFloats(int numValues,void * const * values,const char * name,const ShaderSpec & spec)633 static void infNanRandomFloats(int numValues, void* const* values, const char *name, const ShaderSpec& spec)
634 {
635 	constexpr deUint64		kOne			= 1;
636 	de::Random				rnd				(deStringHash(name) ^ 0xc2a39fu);
637 	const glu::DataType		type			= spec.inputs[0].varType.getBasicType();
638 	const glu::Precision	precision		= spec.inputs[0].varType.getPrecision();
639 	const int				scalarSize		= glu::getDataTypeScalarSize(type);
640 	const int				minMantissaBits	= getMinMantissaBits(type, precision);
641 	const int				numMantissaBits	= getNumMantissaBits(type);
642 	const deUint64			mantissaMask	= ~getMaxUlpDiffFromBits(minMantissaBits, numMantissaBits) & ((kOne<<numMantissaBits)-kOne);
643 	const int				exponentBits	= getExponentBits(type);
644 	const deUint32			exponentMask	= getExponentMask(exponentBits);
645 	const bool				isDouble		= glu::isDataTypeDoubleOrDVec(type);
646 	const deUint64			exponentBias	= (isDouble ? static_cast<deUint64>(tcu::Float64::EXPONENT_BIAS) : static_cast<deUint64>(tcu::Float32::EXPONENT_BIAS));
647 
648 	int numInf = 0;
649 	int numNan = 0;
650 	for (int valNdx = 0; valNdx < numValues*scalarSize; valNdx++)
651 	{
652 		// Roughly 25% chance of each of Inf and NaN
653 		const bool		isInf		= rnd.getFloat() > 0.75f;
654 		const bool		isNan		= !isInf && rnd.getFloat() > 0.66f;
655 		const deUint64	m			= rnd.getUint64() & mantissaMask;
656 		const deUint64	e			= static_cast<deUint64>(rnd.getUint32() & exponentMask);
657 		const deUint64	sign		= static_cast<deUint64>(rnd.getUint32() & 0x1u);
658 		// Ensure the 'quiet' bit is set on NaNs (also ensures we don't generate inf by mistake)
659 		const deUint64	mantissa	= isInf ? 0 : (isNan ? ((kOne<<(numMantissaBits-1)) | m) : m);
660 		const deUint64	exp			= (isNan || isInf) ? exponentMask : std::min(e, exponentBias);
661 		const deUint64	value		= (sign << (numMantissaBits + exponentBits)) | (exp << numMantissaBits) | static_cast<deUint32>(mantissa);
662 		if (isInf) numInf++;
663 		if (isNan) numNan++;
664 
665 		if (isDouble)
666 		{
667 			DE_ASSERT(tcu::Float64(value).isInf() == isInf && tcu::Float64(value).isNaN() == isNan);
668 			((deUint64*)values[0])[valNdx] = value;
669 		}
670 		else
671 		{
672 			const auto value32 = static_cast<deUint32>(value);
673 			DE_ASSERT(tcu::Float32(value32).isInf() == isInf && tcu::Float32(value32).isNaN() == isNan);
674 			((deUint32*)values[0])[valNdx] = value32;
675 		}
676 	}
677 	// Check for minimal coverage of intended cases.
678 	DE_ASSERT(0 < numInf);
679 	DE_ASSERT(0 < numNan);
680 	DE_ASSERT(numInf + numNan < numValues*scalarSize);
681 }
682 
683 class IsnanCaseInstance : public CommonFunctionTestInstance
684 {
685 public:
IsnanCaseInstance(Context & context,const ShaderSpec & spec,int numValues,const char * name)686 	IsnanCaseInstance (Context& context, const ShaderSpec& spec, int numValues, const char* name)
687 		: CommonFunctionTestInstance	(context, spec, numValues, name)
688 	{
689 	}
690 
getInputValues(int numValues,void * const * values) const691 	void getInputValues (int numValues, void* const* values) const
692 	{
693 		infNanRandomFloats(numValues, values, m_name, m_spec);
694 	}
695 
compare(const void * const * inputs,const void * const * outputs)696 	bool compare (const void* const* inputs, const void* const* outputs)
697 	{
698 		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
699 		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
700 		const int				scalarSize		= glu::getDataTypeScalarSize(type);
701 		const bool				isDouble		= glu::isDataTypeDoubleOrDVec(type);
702 
703 		for (int compNdx = 0; compNdx < scalarSize; compNdx++)
704 		{
705 			const bool	out0	= reinterpret_cast<const deUint32*>(outputs[0])[compNdx] != 0;
706 			bool		ok;
707 			bool		ref;
708 
709 			if (isDouble)
710 			{
711 				const double in0 = reinterpret_cast<const double*>(inputs[0])[compNdx];
712 				ref	= tcu::Float64(in0).isNaN();
713 				ok = (out0 == ref);
714 			}
715 			else
716 			{
717 				const float	in0	= reinterpret_cast<const float*>(inputs[0])[compNdx];
718 				ref	= tcu::Float32(in0).isNaN();
719 
720 				// NaN support only required for highp. Otherwise just check for false positives.
721 				if (precision == glu::PRECISION_HIGHP)
722 					ok = (out0 == ref);
723 				else
724 					ok = ref || !out0;
725 			}
726 
727 			if (!ok)
728 			{
729 				m_failMsg << "Expected [" << compNdx << "] = " << (ref ? "true" : "false");
730 				return false;
731 			}
732 		}
733 
734 		return true;
735 	}
736 };
737 
738 class IsnanCase : public CommonFunctionCase
739 {
740 public:
IsnanCase(tcu::TestContext & testCtx,glu::DataType baseType,glu::Precision precision)741 	IsnanCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision)
742 		: CommonFunctionCase	(testCtx, getCommonFuncCaseName(baseType, precision).c_str(), "isnan")
743 	{
744 		DE_ASSERT(glu::isDataTypeFloatOrVec(baseType) || glu::isDataTypeDoubleOrDVec(baseType));
745 
746 		const int			vecSize		= glu::getDataTypeScalarSize(baseType);
747 		const glu::DataType	boolType	= vecSize > 1 ? glu::getDataTypeBoolVec(vecSize) : glu::TYPE_BOOL;
748 
749 		m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
750 		m_spec.outputs.push_back(Symbol("out0", glu::VarType(boolType, glu::PRECISION_LAST)));
751 		m_spec.source = "out0 = isnan(in0);";
752 	}
753 
checkSupport(Context & context) const754 	void checkSupport (Context& context) const
755 	{
756 		checkTypeSupport(context, m_spec.inputs[0].varType.getBasicType());
757 	}
758 
createInstance(Context & ctx) const759 	TestInstance* createInstance (Context& ctx) const
760 	{
761 		return new IsnanCaseInstance(ctx, m_spec, m_numValues, getName());
762 	}
763 };
764 
765 class IsinfCaseInstance : public CommonFunctionTestInstance
766 {
767 public:
IsinfCaseInstance(Context & context,const ShaderSpec & spec,int numValues,const char * name)768 	IsinfCaseInstance (Context& context, const ShaderSpec& spec, int numValues, const char* name)
769 		: CommonFunctionTestInstance(context, spec, numValues, name)
770 	{
771 	}
772 
getInputValues(int numValues,void * const * values) const773 	void getInputValues (int numValues, void* const* values) const
774 	{
775 		infNanRandomFloats(numValues, values, m_name, m_spec);
776 	}
777 
compare(const void * const * inputs,const void * const * outputs)778 	bool compare (const void* const* inputs, const void* const* outputs)
779 	{
780 		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
781 		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
782 		const int				scalarSize		= glu::getDataTypeScalarSize(type);
783 		const bool				isDouble		= glu::isDataTypeDoubleOrDVec(type);
784 
785 		for (int compNdx = 0; compNdx < scalarSize; compNdx++)
786 		{
787 			const bool	out0 = reinterpret_cast<const deUint32*>(outputs[0])[compNdx] != 0;
788 			bool		ref;
789 			bool		ok;
790 
791 			if (isDouble)
792 			{
793 				const double in0 = reinterpret_cast<const double*>(inputs[0])[compNdx];
794 				ref = tcu::Float64(in0).isInf();
795 				ok = (out0 == ref);
796 			}
797 			else
798 			{
799 				const float in0 = reinterpret_cast<const float*>(inputs[0])[compNdx];
800 				if (precision == glu::PRECISION_HIGHP)
801 				{
802 					// Only highp is required to support inf/nan
803 					ref = tcu::Float32(in0).isInf();
804 					ok = (out0 == ref);
805 				}
806 				else
807 				{
808 					// Inf support is optional, check that inputs that are not Inf in mediump don't result in true.
809 					ref = tcu::Float16(in0).isInf();
810 					ok = (out0 || !ref);
811 				}
812 			}
813 
814 			if (!ok)
815 			{
816 				m_failMsg << "Expected [" << compNdx << "] = " << HexBool(ref);
817 				return false;
818 			}
819 		}
820 
821 		return true;
822 	}
823 };
824 
825 class IsinfCase : public CommonFunctionCase
826 {
827 public:
IsinfCase(tcu::TestContext & testCtx,glu::DataType baseType,glu::Precision precision)828 	IsinfCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision)
829 		: CommonFunctionCase	(testCtx, getCommonFuncCaseName(baseType, precision).c_str(), "isinf")
830 	{
831 		DE_ASSERT(glu::isDataTypeFloatOrVec(baseType) || glu::isDataTypeDoubleOrDVec(baseType));
832 
833 		const int			vecSize		= glu::getDataTypeScalarSize(baseType);
834 		const glu::DataType	boolType	= vecSize > 1 ? glu::getDataTypeBoolVec(vecSize) : glu::TYPE_BOOL;
835 
836 		m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
837 		m_spec.outputs.push_back(Symbol("out0", glu::VarType(boolType, glu::PRECISION_LAST)));
838 		m_spec.source = "out0 = isinf(in0);";
839 	}
840 
checkSupport(Context & context) const841 	void checkSupport (Context& context) const
842 	{
843 		checkTypeSupport(context, m_spec.inputs[0].varType.getBasicType());
844 	}
845 
createInstance(Context & ctx) const846 	TestInstance* createInstance (Context& ctx) const
847 	{
848 		return new IsinfCaseInstance(ctx, m_spec, m_numValues, getName());
849 	}
850 };
851 
852 class FloatBitsToUintIntCaseInstance : public CommonFunctionTestInstance
853 {
854 public:
FloatBitsToUintIntCaseInstance(Context & context,const ShaderSpec & spec,int numValues,const char * name)855 	FloatBitsToUintIntCaseInstance (Context& context, const ShaderSpec& spec, int numValues, const char* name)
856 		: CommonFunctionTestInstance	(context, spec, numValues, name)
857 	{
858 	}
859 
getInputValues(int numValues,void * const * values) const860 	void getInputValues (int numValues, void* const* values) const
861 	{
862 		const Vec2 ranges[] =
863 		{
864 			Vec2(-2.0f,		2.0f),	// lowp
865 			Vec2(-1e3f,		1e3f),	// mediump
866 			Vec2(-1e7f,		1e7f)	// highp
867 		};
868 
869 		de::Random				rnd			(deStringHash(m_name) ^ 0x2790au);
870 		const glu::DataType		type		= m_spec.inputs[0].varType.getBasicType();
871 		const glu::Precision	precision	= m_spec.inputs[0].varType.getPrecision();
872 		const int				scalarSize	= glu::getDataTypeScalarSize(type);
873 
874 		fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), values[0], numValues*scalarSize);
875 	}
876 
compare(const void * const * inputs,const void * const * outputs)877 	bool compare (const void* const* inputs, const void* const* outputs)
878 	{
879 		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
880 		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
881 		const int				scalarSize		= glu::getDataTypeScalarSize(type);
882 
883 		const int				minMantissaBits	= getMinMantissaBits(type, precision);
884 		const int				numMantissaBits	= getNumMantissaBits(type);
885 		const int				maxUlpDiff		= static_cast<int>(getMaxUlpDiffFromBits(minMantissaBits, numMantissaBits));
886 
887 		for (int compNdx = 0; compNdx < scalarSize; compNdx++)
888 		{
889 			const float		in0			= ((const float*)inputs[0])[compNdx];
890 			const deUint32	out0		= ((const deUint32*)outputs[0])[compNdx];
891 			const deUint32	refOut0		= tcu::Float32(in0).bits();
892 			const int		ulpDiff		= de::abs((int)out0 - (int)refOut0);
893 
894 			if (ulpDiff > maxUlpDiff)
895 			{
896 				m_failMsg << "Expected [" << compNdx << "] = " << tcu::toHex(refOut0) << " with threshold "
897 							<< tcu::toHex(maxUlpDiff) << ", got diff " << tcu::toHex(ulpDiff);
898 				return false;
899 			}
900 		}
901 
902 		return true;
903 	}
904 };
905 
906 class FloatBitsToUintIntCase : public CommonFunctionCase
907 {
908 public:
FloatBitsToUintIntCase(tcu::TestContext & testCtx,glu::DataType baseType,glu::Precision precision,bool outIsSigned)909 	FloatBitsToUintIntCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision, bool outIsSigned)
910 		: CommonFunctionCase	(testCtx, getCommonFuncCaseName(baseType, precision).c_str(), outIsSigned ? "floatBitsToInt" : "floatBitsToUint")
911 	{
912 		const int			vecSize		= glu::getDataTypeScalarSize(baseType);
913 		const glu::DataType	intType		= outIsSigned ? (vecSize > 1 ? glu::getDataTypeIntVec(vecSize) : glu::TYPE_INT)
914 													  : (vecSize > 1 ? glu::getDataTypeUintVec(vecSize) : glu::TYPE_UINT);
915 
916 		m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
917 		m_spec.outputs.push_back(Symbol("out0", glu::VarType(intType, glu::PRECISION_HIGHP)));
918 		m_spec.source = outIsSigned ? "out0 = floatBitsToInt(in0);" : "out0 = floatBitsToUint(in0);";
919 	}
920 
createInstance(Context & ctx) const921 	TestInstance* createInstance (Context& ctx) const
922 	{
923 		return new FloatBitsToUintIntCaseInstance(ctx, m_spec, m_numValues, getName());
924 	}
925 };
926 
927 class FloatBitsToIntCase : public FloatBitsToUintIntCase
928 {
929 public:
FloatBitsToIntCase(tcu::TestContext & testCtx,glu::DataType baseType,glu::Precision precision)930 	FloatBitsToIntCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision)
931 		: FloatBitsToUintIntCase	(testCtx, baseType, precision, true)
932 	{
933 	}
934 
935 };
936 
937 class FloatBitsToUintCase : public FloatBitsToUintIntCase
938 {
939 public:
FloatBitsToUintCase(tcu::TestContext & testCtx,glu::DataType baseType,glu::Precision precision)940 	FloatBitsToUintCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision)
941 		: FloatBitsToUintIntCase	(testCtx, baseType, precision, false)
942 	{
943 	}
944 };
945 
946 class BitsToFloatCaseInstance : public CommonFunctionTestInstance
947 {
948 public:
BitsToFloatCaseInstance(Context & context,const ShaderSpec & spec,int numValues,const char * name)949 	BitsToFloatCaseInstance (Context& context, const ShaderSpec& spec, int numValues, const char* name)
950 		: CommonFunctionTestInstance	(context, spec, numValues, name)
951 	{
952 	}
953 
getInputValues(int numValues,void * const * values) const954 	void getInputValues (int numValues, void* const* values) const
955 	{
956 		de::Random				rnd			(deStringHash(m_name) ^ 0xbbb225u);
957 		const glu::DataType		type		= m_spec.inputs[0].varType.getBasicType();
958 		const int				scalarSize	= glu::getDataTypeScalarSize(type);
959 		const Vec2				range		(-1e8f, +1e8f);
960 
961 		// \note Filled as floats.
962 		fillRandomScalars(rnd, range.x(), range.y(), values[0], numValues*scalarSize);
963 	}
964 
compare(const void * const * inputs,const void * const * outputs)965 	bool compare (const void* const* inputs, const void* const* outputs)
966 	{
967 		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
968 		const int				scalarSize		= glu::getDataTypeScalarSize(type);
969 		const deUint32			maxUlpDiff		= 0;
970 
971 		for (int compNdx = 0; compNdx < scalarSize; compNdx++)
972 		{
973 			const float		in0			= ((const float*)inputs[0])[compNdx];
974 			const float		out0		= ((const float*)outputs[0])[compNdx];
975 			const deUint32	ulpDiff		= getUlpDiffIgnoreZeroSign(in0, out0);
976 
977 			if (ulpDiff > maxUlpDiff)
978 			{
979 				m_failMsg << "Expected [" << compNdx << "] = " << tcu::toHex(tcu::Float32(in0).bits()) << " with ULP threshold "
980 							<< tcu::toHex(maxUlpDiff) << ", got ULP diff " << tcu::toHex(ulpDiff);
981 				return false;
982 			}
983 		}
984 
985 		return true;
986 	}
987 };
988 
989 class BitsToFloatCase : public CommonFunctionCase
990 {
991 public:
BitsToFloatCase(tcu::TestContext & testCtx,glu::DataType baseType)992 	BitsToFloatCase (tcu::TestContext& testCtx, glu::DataType baseType)
993 		: CommonFunctionCase	(testCtx, getCommonFuncCaseName(baseType, glu::PRECISION_HIGHP).c_str(), glu::isDataTypeIntOrIVec(baseType) ? "intBitsToFloat" : "uintBitsToFloat")
994 	{
995 		const bool			inIsSigned	= glu::isDataTypeIntOrIVec(baseType);
996 		const int			vecSize		= glu::getDataTypeScalarSize(baseType);
997 		const glu::DataType	floatType	= vecSize > 1 ? glu::getDataTypeFloatVec(vecSize) : glu::TYPE_FLOAT;
998 
999 		m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, glu::PRECISION_HIGHP)));
1000 		m_spec.outputs.push_back(Symbol("out0", glu::VarType(floatType, glu::PRECISION_HIGHP)));
1001 		m_spec.source = inIsSigned ? "out0 = intBitsToFloat(in0);" : "out0 = uintBitsToFloat(in0);";
1002 	}
1003 
createInstance(Context & ctx) const1004 	TestInstance* createInstance (Context& ctx) const
1005 	{
1006 		return new BitsToFloatCaseInstance(ctx, m_spec, m_numValues, getName());
1007 	}
1008 };
1009 
1010 } // anonymous
1011 
ShaderCommonFunctionTests(tcu::TestContext & testCtx)1012 ShaderCommonFunctionTests::ShaderCommonFunctionTests (tcu::TestContext& testCtx)
1013 	: tcu::TestCaseGroup	(testCtx, "common", "Common function tests")
1014 {
1015 }
1016 
~ShaderCommonFunctionTests(void)1017 ShaderCommonFunctionTests::~ShaderCommonFunctionTests (void)
1018 {
1019 }
1020 
init(void)1021 void ShaderCommonFunctionTests::init (void)
1022 {
1023 	static const std::vector<glu::DataType>	kIntOnly		(1u, glu::TYPE_INT);
1024 	static const std::vector<glu::DataType>	kFloatOnly		(1u, glu::TYPE_FLOAT);
1025 	static const std::vector<glu::DataType>	kFloatAndDouble	{glu::TYPE_FLOAT, glu::TYPE_DOUBLE};
1026 
1027 	addFunctionCases<AbsCase>				(this,	"abs",				kIntOnly);
1028 	addFunctionCases<SignCase>				(this,	"sign",				kIntOnly);
1029 	addFunctionCases<IsnanCase>				(this,	"isnan",			kFloatAndDouble);
1030 	addFunctionCases<IsinfCase>				(this,	"isinf",			kFloatAndDouble);
1031 	addFunctionCases<FloatBitsToIntCase>	(this,	"floatbitstoint",	kFloatOnly);
1032 	addFunctionCases<FloatBitsToUintCase>	(this,	"floatbitstouint",	kFloatOnly);
1033 
1034 	// (u)intBitsToFloat()
1035 	{
1036 		tcu::TestCaseGroup* intGroup	= new tcu::TestCaseGroup(m_testCtx, "intbitstofloat",	"intBitsToFloat() Tests");
1037 		tcu::TestCaseGroup* uintGroup	= new tcu::TestCaseGroup(m_testCtx, "uintbitstofloat",	"uintBitsToFloat() Tests");
1038 
1039 		addChild(intGroup);
1040 		addChild(uintGroup);
1041 
1042 		for (int vecSize = 1; vecSize < 4; vecSize++)
1043 		{
1044 			const glu::DataType		intType		= vecSize > 1 ? glu::getDataTypeIntVec(vecSize) : glu::TYPE_INT;
1045 			const glu::DataType		uintType	= vecSize > 1 ? glu::getDataTypeUintVec(vecSize) : glu::TYPE_UINT;
1046 
1047 			intGroup->addChild(new BitsToFloatCase(getTestContext(), intType));
1048 			uintGroup->addChild(new BitsToFloatCase(getTestContext(), uintType));
1049 		}
1050 	}
1051 }
1052 
1053 } // shaderexecutor
1054 } // vkt
1055