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 Integer built-in function tests.
24  *//*--------------------------------------------------------------------*/
25 
26 #include "vktShaderIntegerFunctionTests.hpp"
27 #include "vktShaderExecutor.hpp"
28 #include "tcuTestLog.hpp"
29 #include "tcuFormatUtil.hpp"
30 #include "tcuFloat.hpp"
31 #include "deRandom.hpp"
32 #include "deMath.h"
33 #include "deString.h"
34 #include "deInt32.h"
35 #include "deSharedPtr.hpp"
36 
37 #include <iostream>
38 
39 namespace vkt
40 {
41 namespace shaderexecutor
42 {
43 
44 using std::vector;
45 using std::string;
46 using tcu::TestLog;
47 
48 using tcu::IVec2;
49 using tcu::IVec3;
50 using tcu::IVec4;
51 using tcu::UVec2;
52 using tcu::UVec3;
53 using tcu::UVec4;
54 
55 // Utilities
56 
57 namespace
58 {
59 
60 struct HexFloat
61 {
62 	const float value;
HexFloatvkt::shaderexecutor::__anon6871bb470111::HexFloat63 	HexFloat (const float value_) : value(value_) {}
64 };
65 
operator <<(std::ostream & str,const HexFloat & v)66 std::ostream& operator<< (std::ostream& str, const HexFloat& v)
67 {
68 	return str << v.value << " / " << tcu::toHex(tcu::Float32(v.value).bits());
69 }
70 
71 struct VarValue
72 {
73 	const glu::VarType&	type;
74 	const void*			value;
75 
VarValuevkt::shaderexecutor::__anon6871bb470111::VarValue76 	VarValue (const glu::VarType& type_, const void* value_) : type(type_), value(value_) {}
77 };
78 
operator <<(std::ostream & str,const VarValue & varValue)79 std::ostream& operator<< (std::ostream& str, const VarValue& varValue)
80 {
81 	DE_ASSERT(varValue.type.isBasicType());
82 
83 	const glu::DataType		basicType		= varValue.type.getBasicType();
84 	const glu::DataType		scalarType		= glu::getDataTypeScalarType(basicType);
85 	const int				numComponents	= glu::getDataTypeScalarSize(basicType);
86 
87 	if (numComponents > 1)
88 		str << glu::getDataTypeName(basicType) << "(";
89 
90 	for (int compNdx = 0; compNdx < numComponents; compNdx++)
91 	{
92 		if (compNdx != 0)
93 			str << ", ";
94 
95 		switch (scalarType)
96 		{
97 			case glu::TYPE_FLOAT:	str << HexFloat(((const float*)varValue.value)[compNdx]);						break;
98 			case glu::TYPE_INT:		str << ((const deInt32*)varValue.value)[compNdx];								break;
99 			case glu::TYPE_UINT:	str << tcu::toHex(((const deUint32*)varValue.value)[compNdx]);					break;
100 			case glu::TYPE_BOOL:	str << (((const deUint32*)varValue.value)[compNdx] != 0 ? "true" : "false");	break;
101 
102 			default:
103 				DE_ASSERT(false);
104 		}
105 	}
106 
107 	if (numComponents > 1)
108 		str << ")";
109 
110 	return str;
111 }
112 
getShaderUintBitCount(glu::ShaderType shaderType,glu::Precision precision)113 inline int getShaderUintBitCount (glu::ShaderType shaderType, glu::Precision precision)
114 {
115 	// \todo [2013-10-31 pyry] Query from GL for vertex and fragment shaders.
116 	DE_UNREF(shaderType);
117 	const int bitCounts[] = { 9, 16, 32 };
118 	DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(bitCounts) == glu::PRECISION_LAST);
119 	return bitCounts[precision];
120 }
121 
extendSignTo32(deUint32 integer,deUint32 integerLength)122 static inline deUint32 extendSignTo32 (deUint32 integer, deUint32 integerLength)
123 {
124 	DE_ASSERT(integerLength > 0 && integerLength <= 32);
125 
126 	return deUint32(0 - deInt32((integer & (1 << (integerLength - 1))) << 1)) | integer;
127 }
128 
getLowBitMask(int integerLength)129 static inline deUint32 getLowBitMask (int integerLength)
130 {
131 	DE_ASSERT(integerLength >= 0 && integerLength <= 32);
132 
133 	// \note: shifting more or equal to 32 => undefined behavior. Avoid it by shifting in two parts (1 << (num-1) << 1)
134 	if (integerLength == 0u)
135 		return 0u;
136 	return ((1u << ((deUint32)integerLength - 1u)) << 1u) - 1u;
137 }
138 
generateRandomInputData(de::Random & rnd,glu::ShaderType shaderType,glu::DataType dataType,glu::Precision precision,deUint32 * dst,int numValues)139 static void generateRandomInputData (de::Random& rnd, glu::ShaderType shaderType, glu::DataType dataType, glu::Precision precision, deUint32* dst, int numValues)
140 {
141 	const int				scalarSize		= glu::getDataTypeScalarSize(dataType);
142 	const deUint32			integerLength	= (deUint32)getShaderUintBitCount(shaderType, precision);
143 	const deUint32			integerMask		= getLowBitMask(integerLength);
144 	const bool				isUnsigned		= glu::isDataTypeUintOrUVec(dataType);
145 
146 	if (isUnsigned)
147 	{
148 		for (int valueNdx = 0; valueNdx < numValues; ++valueNdx)
149 			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
150 				dst[valueNdx*scalarSize + compNdx] = rnd.getUint32() & integerMask;
151 	}
152 	else
153 	{
154 		for (int valueNdx = 0; valueNdx < numValues; ++valueNdx)
155 			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
156 				dst[valueNdx*scalarSize + compNdx] = extendSignTo32(rnd.getUint32() & integerMask, integerLength);
157 	}
158 }
159 
getScalarSizes(const vector<Symbol> & symbols)160 static vector<int> getScalarSizes (const vector<Symbol>& symbols)
161 {
162 	vector<int> sizes(symbols.size());
163 	for (int ndx = 0; ndx < (int)symbols.size(); ++ndx)
164 		sizes[ndx] = symbols[ndx].varType.getScalarSize();
165 	return sizes;
166 }
167 
computeTotalScalarSize(const vector<Symbol> & symbols)168 static int computeTotalScalarSize (const vector<Symbol>& symbols)
169 {
170 	int totalSize = 0;
171 	for (vector<Symbol>::const_iterator sym = symbols.begin(); sym != symbols.end(); ++sym)
172 		totalSize += sym->varType.getScalarSize();
173 	return totalSize;
174 }
175 
getInputOutputPointers(const vector<Symbol> & symbols,vector<deUint32> & data,const int numValues)176 static vector<void*> getInputOutputPointers (const vector<Symbol>& symbols, vector<deUint32>& data, const int numValues)
177 {
178 	vector<void*>	pointers		(symbols.size());
179 	int				curScalarOffset	= 0;
180 
181 	for (int varNdx = 0; varNdx < (int)symbols.size(); ++varNdx)
182 	{
183 		const Symbol&	var				= symbols[varNdx];
184 		const int		scalarSize		= var.varType.getScalarSize();
185 
186 		// Uses planar layout as input/output specs do not support strides.
187 		pointers[varNdx] = &data[curScalarOffset];
188 		curScalarOffset += scalarSize*numValues;
189 	}
190 
191 	DE_ASSERT(curScalarOffset == (int)data.size());
192 
193 	return pointers;
194 }
195 
getPrecisionPostfix(glu::Precision precision)196 static const char* getPrecisionPostfix (glu::Precision precision)
197 {
198 	static const char* s_postfix[] =
199 	{
200 		"_lowp",
201 		"_mediump",
202 		"_highp"
203 	};
204 	DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_postfix) == glu::PRECISION_LAST);
205 	DE_ASSERT(de::inBounds<int>(precision, 0, DE_LENGTH_OF_ARRAY(s_postfix)));
206 	return s_postfix[precision];
207 }
208 
getShaderTypePostfix(glu::ShaderType shaderType)209 static const char* getShaderTypePostfix (glu::ShaderType shaderType)
210 {
211 	static const char* s_postfix[] =
212 	{
213 		"_vertex",
214 		"_fragment",
215 		"_geometry",
216 		"_tess_control",
217 		"_tess_eval",
218 		"_compute"
219 	};
220 	DE_ASSERT(de::inBounds<int>(shaderType, 0, DE_LENGTH_OF_ARRAY(s_postfix)));
221 	return s_postfix[shaderType];
222 }
223 
getIntegerFuncCaseName(glu::DataType baseType,glu::Precision precision,glu::ShaderType shaderType)224 static std::string getIntegerFuncCaseName (glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
225 {
226 	return string(glu::getDataTypeName(baseType)) + getPrecisionPostfix(precision) + getShaderTypePostfix(shaderType);
227 }
228 
reverseBits(deUint32 v)229 static inline deUint32 reverseBits (deUint32 v)
230 {
231 	v = (((v & 0xaaaaaaaa) >> 1) | ((v & 0x55555555) << 1));
232 	v = (((v & 0xcccccccc) >> 2) | ((v & 0x33333333) << 2));
233 	v = (((v & 0xf0f0f0f0) >> 4) | ((v & 0x0f0f0f0f) << 4));
234 	v = (((v & 0xff00ff00) >> 8) | ((v & 0x00ff00ff) << 8));
235 	return((v >> 16) | (v << 16));
236 }
237 
findLSB(deUint32 value)238 static int findLSB (deUint32 value)
239 {
240 	for (int i = 0; i < 32; i++)
241 	{
242 		if (value & (1u<<i))
243 			return i;
244 	}
245 	return -1;
246 }
247 
findMSB(deInt32 value)248 static int findMSB (deInt32 value)
249 {
250 	if (value > 0)
251 		return 31 - deClz32((deUint32)value);
252 	else if (value < 0)
253 		return 31 - deClz32(~(deUint32)value);
254 	else
255 		return -1;
256 }
257 
findMSB(deUint32 value)258 static int findMSB (deUint32 value)
259 {
260 	if (value > 0)
261 		return 31 - deClz32(value);
262 	else
263 		return -1;
264 }
265 
toPrecision(deUint32 value,int numIntegerBits)266 static deUint32 toPrecision (deUint32 value, int numIntegerBits)
267 {
268 	return value & getLowBitMask(numIntegerBits);
269 }
270 
toPrecision(deInt32 value,int numIntegerBits)271 static deInt32 toPrecision (deInt32 value, int numIntegerBits)
272 {
273 	return (deInt32)extendSignTo32((deUint32)value & getLowBitMask(numIntegerBits), numIntegerBits);
274 }
275 
276 template<class TestClass>
addFunctionCases(tcu::TestCaseGroup * parent,const char * functionName,bool intTypes,bool uintTypes,bool allPrec,deUint32 shaderBits)277 static void addFunctionCases (tcu::TestCaseGroup* parent, const char* functionName, bool intTypes, bool uintTypes, bool allPrec, deUint32 shaderBits)
278 {
279 	tcu::TestCaseGroup* group = new tcu::TestCaseGroup(parent->getTestContext(), functionName, functionName);
280 
281 	parent->addChild(group);
282 	const glu::DataType scalarTypes[] =
283 	{
284 		glu::TYPE_INT,
285 		glu::TYPE_UINT
286 	};
287 
288 	for (int scalarTypeNdx = 0; scalarTypeNdx < DE_LENGTH_OF_ARRAY(scalarTypes); scalarTypeNdx++)
289 	{
290 		const glu::DataType scalarType = scalarTypes[scalarTypeNdx];
291 
292 		if ((!intTypes && scalarType == glu::TYPE_INT) || (!uintTypes && scalarType == glu::TYPE_UINT))
293 			continue;
294 
295 		for (int vecSize = 1; vecSize <= 4; vecSize++)
296 		{
297 			for (int prec = glu::PRECISION_MEDIUMP; prec <= glu::PRECISION_HIGHP; prec++)
298 			{
299 				if (prec != glu::PRECISION_HIGHP && !allPrec)
300 					continue;
301 
302 				for (int shaderTypeNdx = 0; shaderTypeNdx < glu::SHADERTYPE_LAST; shaderTypeNdx++)
303 				{
304 					if (shaderBits & (1<<shaderTypeNdx))
305 						group->addChild(new TestClass(parent->getTestContext(), glu::DataType(scalarType + vecSize - 1), glu::Precision(prec), glu::ShaderType(shaderTypeNdx)));
306 				}
307 			}
308 		}
309 	}
310 }
311 
312 } // anonymous
313 
314 // IntegerFunctionCase
315 
316 class IntegerFunctionCase : public TestCase
317 {
318 public:
319 										IntegerFunctionCase		(tcu::TestContext& testCtx, const char* name, const char* description, glu::ShaderType shaderType);
320 										~IntegerFunctionCase	(void);
321 
initPrograms(vk::SourceCollections & programCollection) const322 	virtual	void						initPrograms			(vk::SourceCollections& programCollection) const
323 										{
324 											m_executor->setShaderSources(programCollection);
325 										}
326 
327 	virtual TestInstance*				createInstance			(Context& context) const = 0;
328 	virtual void						init					(void);
329 
330 protected:
331 										IntegerFunctionCase		(const IntegerFunctionCase& other);
332 	IntegerFunctionCase&				operator=				(const IntegerFunctionCase& other);
333 
334 	const glu::ShaderType				m_shaderType;
335 
336 	ShaderSpec							m_spec;
337 
338 	de::MovePtr<ShaderExecutor>			m_executor;
339 
340 	const int							m_numValues;
341 };
342 
IntegerFunctionCase(tcu::TestContext & testCtx,const char * name,const char * description,glu::ShaderType shaderType)343 IntegerFunctionCase::IntegerFunctionCase (tcu::TestContext& testCtx, const char* name, const char* description, glu::ShaderType shaderType)
344 	: TestCase		(testCtx, name, description)
345 	, m_shaderType	(shaderType)
346 	, m_executor	(DE_NULL)
347 	, m_numValues	(100)
348 {
349 }
350 
~IntegerFunctionCase(void)351 IntegerFunctionCase::~IntegerFunctionCase (void)
352 {
353 }
354 
init(void)355 void IntegerFunctionCase::init (void)
356 {
357 	DE_ASSERT(!m_executor);
358 
359 	m_executor = de::MovePtr<ShaderExecutor>(createExecutor(m_shaderType, m_spec));
360 	m_testCtx.getLog() << *m_executor;
361 }
362 
363 // IntegerFunctionTestInstance
364 
365 class IntegerFunctionTestInstance : public TestInstance
366 {
367 public:
IntegerFunctionTestInstance(Context & context,glu::ShaderType shaderType,ShaderSpec spec,ShaderExecutor & executor,int numValues,const char * name)368 								IntegerFunctionTestInstance		(Context& context, glu::ShaderType shaderType, ShaderSpec spec, ShaderExecutor& executor, int numValues, const char* name)
369 									: TestInstance	(context)
370 									, m_shaderType	(shaderType)
371 									, m_spec		(spec)
372 									, m_numValues	(numValues)
373 									, m_name		(name)
374 									, m_executor	(executor)
375 								{
376 								}
377 	virtual tcu::TestStatus		iterate							(void);
378 protected:
379 	virtual bool						compare					(const void* const* inputs, const void* const* outputs) = 0;
380 
381 	virtual void						getInputValues			(int numValues, void* const* values) const = 0;
382 
383 	const glu::ShaderType				m_shaderType;
384 
385 	ShaderSpec							m_spec;
386 
387 	const int							m_numValues;
388 
389 	const char*							m_name;
390 
391 	std::ostringstream					m_failMsg;				//!< Comparison failure help message.
392 
393 	ShaderExecutor&						m_executor;
394 };
395 
iterate(void)396 tcu::TestStatus IntegerFunctionTestInstance::iterate (void)
397 {
398 	const int				numInputScalars			= computeTotalScalarSize(m_spec.inputs);
399 	const int				numOutputScalars		= computeTotalScalarSize(m_spec.outputs);
400 	vector<deUint32>		inputData				(numInputScalars * m_numValues);
401 	vector<deUint32>		outputData				(numOutputScalars * m_numValues);
402 	const vector<void*>		inputPointers			= getInputOutputPointers(m_spec.inputs, inputData, m_numValues);
403 	const vector<void*>		outputPointers			= getInputOutputPointers(m_spec.outputs, outputData, m_numValues);
404 
405 	// Initialize input data.
406 	getInputValues(m_numValues, &inputPointers[0]);
407 
408 	// Execute shader.
409 	m_executor.execute(m_context, m_numValues, &inputPointers[0], &outputPointers[0]);
410 
411 	// Compare results.
412 	{
413 		const vector<int>		inScalarSizes		= getScalarSizes(m_spec.inputs);
414 		const vector<int>		outScalarSizes		= getScalarSizes(m_spec.outputs);
415 		vector<void*>			curInputPtr			(inputPointers.size());
416 		vector<void*>			curOutputPtr		(outputPointers.size());
417 		int						numFailed			= 0;
418 		tcu::TestContext&		testCtx				= m_context.getTestContext();
419 		for (int valNdx = 0; valNdx < m_numValues; valNdx++)
420 		{
421 			// Set up pointers for comparison.
422 			for (int inNdx = 0; inNdx < (int)curInputPtr.size(); ++inNdx)
423 				curInputPtr[inNdx] = (deUint32*)inputPointers[inNdx] + inScalarSizes[inNdx]*valNdx;
424 
425 			for (int outNdx = 0; outNdx < (int)curOutputPtr.size(); ++outNdx)
426 				curOutputPtr[outNdx] = (deUint32*)outputPointers[outNdx] + outScalarSizes[outNdx]*valNdx;
427 
428 			if (!compare(&curInputPtr[0], &curOutputPtr[0]))
429 			{
430 				// \todo [2013-08-08 pyry] We probably want to log reference value as well?
431 
432 				testCtx.getLog() << TestLog::Message << "ERROR: comparison failed for value " << valNdx << ":\n  " << m_failMsg.str() << TestLog::EndMessage;
433 
434 				testCtx.getLog() << TestLog::Message << "  inputs:" << TestLog::EndMessage;
435 				for (int inNdx = 0; inNdx < (int)curInputPtr.size(); inNdx++)
436 					testCtx.getLog() << TestLog::Message << "    " << m_spec.inputs[inNdx].name << " = "
437 														   << VarValue(m_spec.inputs[inNdx].varType, curInputPtr[inNdx])
438 									   << TestLog::EndMessage;
439 
440 				testCtx.getLog() << TestLog::Message << "  outputs:" << TestLog::EndMessage;
441 				for (int outNdx = 0; outNdx < (int)curOutputPtr.size(); outNdx++)
442 					testCtx.getLog() << TestLog::Message << "    " << m_spec.outputs[outNdx].name << " = "
443 														   << VarValue(m_spec.outputs[outNdx].varType, curOutputPtr[outNdx])
444 									   << TestLog::EndMessage;
445 
446 				m_failMsg.str("");
447 				m_failMsg.clear();
448 				numFailed += 1;
449 			}
450 		}
451 
452 		testCtx.getLog() << TestLog::Message << (m_numValues - numFailed) << " / " << m_numValues << " values passed" << TestLog::EndMessage;
453 
454 		if (numFailed == 0)
455 			return tcu::TestStatus::pass("Pass");
456 		else
457 			return tcu::TestStatus::fail("Result comparison failed");
458 	}
459 }
460 
461 // Test cases
462 
463 class UaddCarryCaseInstance : public IntegerFunctionTestInstance
464 {
465 public:
UaddCarryCaseInstance(Context & context,glu::ShaderType shaderType,ShaderSpec spec,ShaderExecutor & executor,int numValues,const char * name)466 	UaddCarryCaseInstance (Context& context, glu::ShaderType shaderType, ShaderSpec spec, ShaderExecutor& executor, int numValues, const char* name)
467 		: IntegerFunctionTestInstance	(context, shaderType, spec, executor, numValues, name)
468 	{
469 	}
470 
getInputValues(int numValues,void * const * values) const471 	void getInputValues (int numValues, void* const* values) const
472 	{
473 		de::Random				rnd				(deStringHash(m_name) ^ 0x235facu);
474 		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
475 		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
476 		const int				scalarSize		= glu::getDataTypeScalarSize(type);
477 		const int				integerLength	= getShaderUintBitCount(m_shaderType, precision);
478 		const deUint32			integerMask		= getLowBitMask(integerLength);
479 		const bool				isSigned		= glu::isDataTypeIntOrIVec(type);
480 		deUint32*				in0				= (deUint32*)values[0];
481 		deUint32*				in1				= (deUint32*)values[1];
482 
483 		const struct
484 		{
485 			deUint32	x;
486 			deUint32	y;
487 		} easyCases[] =
488 		{
489 			{ 0x00000000u,	0x00000000u },
490 			{ 0xfffffffeu,	0x00000001u },
491 			{ 0x00000001u,	0xfffffffeu },
492 			{ 0xffffffffu,	0x00000001u },
493 			{ 0x00000001u,	0xffffffffu },
494 			{ 0xfffffffeu,	0x00000002u },
495 			{ 0x00000002u,	0xfffffffeu },
496 			{ 0xffffffffu,	0xffffffffu }
497 		};
498 
499 		// generate integers with proper bit count
500 		for (int easyCaseNdx = 0; easyCaseNdx < DE_LENGTH_OF_ARRAY(easyCases); easyCaseNdx++)
501 		{
502 			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
503 			{
504 				in0[easyCaseNdx*scalarSize + compNdx] = easyCases[easyCaseNdx].x & integerMask;
505 				in1[easyCaseNdx*scalarSize + compNdx] = easyCases[easyCaseNdx].y & integerMask;
506 			}
507 		}
508 
509 		// convert to signed
510 		if (isSigned)
511 		{
512 			for (int easyCaseNdx = 0; easyCaseNdx < DE_LENGTH_OF_ARRAY(easyCases); easyCaseNdx++)
513 			{
514 				for (int compNdx = 0; compNdx < scalarSize; compNdx++)
515 				{
516 					in0[easyCaseNdx*scalarSize + compNdx] = extendSignTo32(in0[easyCaseNdx*scalarSize + compNdx], integerLength);
517 					in1[easyCaseNdx*scalarSize + compNdx] = extendSignTo32(in1[easyCaseNdx*scalarSize + compNdx], integerLength);
518 				}
519 			}
520 		}
521 
522 		generateRandomInputData(rnd, m_shaderType, type, precision, in0, numValues - DE_LENGTH_OF_ARRAY(easyCases));
523 		generateRandomInputData(rnd, m_shaderType, type, precision, in1, numValues - DE_LENGTH_OF_ARRAY(easyCases));
524 	}
525 
compare(const void * const * inputs,const void * const * outputs)526 	bool compare (const void* const* inputs, const void* const* outputs)
527 	{
528 		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
529 		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
530 		const int				scalarSize		= glu::getDataTypeScalarSize(type);
531 		const int				integerLength	= getShaderUintBitCount(m_shaderType, precision);
532 		const deUint32			mask0			= getLowBitMask(integerLength);
533 
534 		for (int compNdx = 0; compNdx < scalarSize; compNdx++)
535 		{
536 			const deUint32	in0		= ((const deUint32*)inputs[0])[compNdx];
537 			const deUint32	in1		= ((const deUint32*)inputs[1])[compNdx];
538 			const deUint32	out0	= ((const deUint32*)outputs[0])[compNdx];
539 			const deUint32	out1	= ((const deUint32*)outputs[1])[compNdx];
540 			const deUint32	ref0	= in0+in1;
541 			const deUint32	ref1	= (deUint64(in0)+deUint64(in1)) > 0xffffffffu ? 1u : 0u;
542 
543 			if (((out0&mask0) != (ref0&mask0)) || out1 != ref1)
544 			{
545 				m_failMsg << "Expected [" << compNdx << "] = " << tcu::toHex(ref0) << ", " << tcu::toHex(ref1);
546 				return false;
547 			}
548 		}
549 
550 		return true;
551 	}
552 };
553 
554 class UaddCarryCase : public IntegerFunctionCase
555 {
556 public:
UaddCarryCase(tcu::TestContext & testCtx,glu::DataType baseType,glu::Precision precision,glu::ShaderType shaderType)557 	UaddCarryCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
558 		: IntegerFunctionCase	(testCtx, getIntegerFuncCaseName(baseType, precision, shaderType).c_str(), "uaddCarry", shaderType)
559 	{
560 		m_spec.inputs.push_back(Symbol("x", glu::VarType(baseType, precision)));
561 		m_spec.inputs.push_back(Symbol("y", glu::VarType(baseType, precision)));
562 		m_spec.outputs.push_back(Symbol("sum", glu::VarType(baseType, precision)));
563 		m_spec.outputs.push_back(Symbol("carry", glu::VarType(baseType, glu::PRECISION_LOWP)));
564 		m_spec.source = "sum = uaddCarry(x, y, carry);";
565 		init();
566 	}
567 
createInstance(Context & ctx) const568 	TestInstance* createInstance (Context& ctx) const
569 	{
570 		return new UaddCarryCaseInstance(ctx, m_shaderType, m_spec, *m_executor, m_numValues, getName());
571 	}
572 };
573 
574 class UsubBorrowCaseInstance : public IntegerFunctionTestInstance
575 {
576 public:
UsubBorrowCaseInstance(Context & context,glu::ShaderType shaderType,ShaderSpec spec,ShaderExecutor & executor,int numValues,const char * name)577 	UsubBorrowCaseInstance (Context& context, glu::ShaderType shaderType, ShaderSpec spec, ShaderExecutor& executor, int numValues, const char* name)
578 		: IntegerFunctionTestInstance	(context, shaderType, spec, executor, numValues, name)
579 	{
580 	}
581 
getInputValues(int numValues,void * const * values) const582 	void getInputValues (int numValues, void* const* values) const
583 	{
584 		de::Random				rnd				(deStringHash(m_name) ^ 0x235facu);
585 		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
586 		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
587 		const int				scalarSize		= glu::getDataTypeScalarSize(type);
588 		const int				integerLength	= getShaderUintBitCount(m_shaderType, precision);
589 		const deUint32			integerMask		= getLowBitMask(integerLength);
590 		const bool				isSigned		= glu::isDataTypeIntOrIVec(type);
591 		deUint32*				in0				= (deUint32*)values[0];
592 		deUint32*				in1				= (deUint32*)values[1];
593 
594 		const struct
595 		{
596 			deUint32	x;
597 			deUint32	y;
598 		} easyCases[] =
599 		{
600 			{ 0x00000000u,	0x00000000u },
601 			{ 0x00000001u,	0x00000001u },
602 			{ 0x00000001u,	0x00000002u },
603 			{ 0x00000001u,	0xffffffffu },
604 			{ 0xfffffffeu,	0xffffffffu },
605 			{ 0xffffffffu,	0xffffffffu },
606 		};
607 
608 		// generate integers with proper bit count
609 		for (int easyCaseNdx = 0; easyCaseNdx < DE_LENGTH_OF_ARRAY(easyCases); easyCaseNdx++)
610 		{
611 			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
612 			{
613 				in0[easyCaseNdx*scalarSize + compNdx] = easyCases[easyCaseNdx].x & integerMask;
614 				in1[easyCaseNdx*scalarSize + compNdx] = easyCases[easyCaseNdx].y & integerMask;
615 			}
616 		}
617 
618 		// convert to signed
619 		if (isSigned)
620 		{
621 			for (int easyCaseNdx = 0; easyCaseNdx < DE_LENGTH_OF_ARRAY(easyCases); easyCaseNdx++)
622 			{
623 				for (int compNdx = 0; compNdx < scalarSize; compNdx++)
624 				{
625 					in0[easyCaseNdx*scalarSize + compNdx] = extendSignTo32(in0[easyCaseNdx*scalarSize + compNdx], integerLength);
626 					in1[easyCaseNdx*scalarSize + compNdx] = extendSignTo32(in1[easyCaseNdx*scalarSize + compNdx], integerLength);
627 				}
628 			}
629 		}
630 
631 		generateRandomInputData(rnd, m_shaderType, type, precision, in0, numValues - DE_LENGTH_OF_ARRAY(easyCases));
632 		generateRandomInputData(rnd, m_shaderType, type, precision, in1, numValues - DE_LENGTH_OF_ARRAY(easyCases));
633 	}
634 
compare(const void * const * inputs,const void * const * outputs)635 	bool compare (const void* const* inputs, const void* const* outputs)
636 	{
637 		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
638 		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
639 		const int				scalarSize		= glu::getDataTypeScalarSize(type);
640 		const int				integerLength	= getShaderUintBitCount(m_shaderType, precision);
641 		const deUint32			mask0			= getLowBitMask(integerLength);
642 
643 		for (int compNdx = 0; compNdx < scalarSize; compNdx++)
644 		{
645 			const deUint32	in0		= ((const deUint32*)inputs[0])[compNdx];
646 			const deUint32	in1		= ((const deUint32*)inputs[1])[compNdx];
647 			const deUint32	out0	= ((const deUint32*)outputs[0])[compNdx];
648 			const deUint32	out1	= ((const deUint32*)outputs[1])[compNdx];
649 			const deUint32	ref0	= in0-in1;
650 			const deUint32	ref1	= in0 >= in1 ? 0u : 1u;
651 
652 			if (((out0&mask0) != (ref0&mask0)) || out1 != ref1)
653 			{
654 				m_failMsg << "Expected [" << compNdx << "] = " << tcu::toHex(ref0) << ", " << tcu::toHex(ref1);
655 				return false;
656 			}
657 		}
658 
659 		return true;
660 	}
661 };
662 
663 class UsubBorrowCase : public IntegerFunctionCase
664 {
665 public:
UsubBorrowCase(tcu::TestContext & testCtx,glu::DataType baseType,glu::Precision precision,glu::ShaderType shaderType)666 	UsubBorrowCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
667 		: IntegerFunctionCase	(testCtx, getIntegerFuncCaseName(baseType, precision, shaderType).c_str(), "usubBorrow", shaderType)
668 	{
669 		m_spec.inputs.push_back(Symbol("x", glu::VarType(baseType, precision)));
670 		m_spec.inputs.push_back(Symbol("y", glu::VarType(baseType, precision)));
671 		m_spec.outputs.push_back(Symbol("diff", glu::VarType(baseType, precision)));
672 		m_spec.outputs.push_back(Symbol("carry", glu::VarType(baseType, glu::PRECISION_LOWP)));
673 		m_spec.source = "diff = usubBorrow(x, y, carry);";
674 		init();
675 	}
676 
createInstance(Context & ctx) const677 	TestInstance* createInstance (Context& ctx) const
678 	{
679 		return new UsubBorrowCaseInstance(ctx, m_shaderType, m_spec, *m_executor, m_numValues, getName());
680 	}
681 };
682 
683 class UmulExtendedCaseInstance : public IntegerFunctionTestInstance
684 {
685 public:
UmulExtendedCaseInstance(Context & context,glu::ShaderType shaderType,ShaderSpec spec,ShaderExecutor & executor,int numValues,const char * name)686 	UmulExtendedCaseInstance (Context& context, glu::ShaderType shaderType, ShaderSpec spec, ShaderExecutor& executor, int numValues, const char* name)
687 		: IntegerFunctionTestInstance	(context, shaderType, spec, executor, numValues, name)
688 	{
689 	}
690 
getInputValues(int numValues,void * const * values) const691 	void getInputValues (int numValues, void* const* values) const
692 	{
693 		de::Random				rnd			(deStringHash(m_name) ^ 0x235facu);
694 		const glu::DataType		type		= m_spec.inputs[0].varType.getBasicType();
695 //		const glu::Precision	precision	= m_spec.inputs[0].varType.getPrecision();
696 		const int				scalarSize	= glu::getDataTypeScalarSize(type);
697 		deUint32*				in0			= (deUint32*)values[0];
698 		deUint32*				in1			= (deUint32*)values[1];
699 		int						valueNdx	= 0;
700 
701 		const struct
702 		{
703 			deUint32	x;
704 			deUint32	y;
705 		} easyCases[] =
706 		{
707 			{ 0x00000000u,	0x00000000u },
708 			{ 0xffffffffu,	0x00000001u },
709 			{ 0xffffffffu,	0x00000002u },
710 			{ 0x00000001u,	0xffffffffu },
711 			{ 0x00000002u,	0xffffffffu },
712 			{ 0xffffffffu,	0xffffffffu },
713 		};
714 
715 		for (int easyCaseNdx = 0; easyCaseNdx < DE_LENGTH_OF_ARRAY(easyCases); easyCaseNdx++)
716 		{
717 			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
718 			{
719 				in0[valueNdx*scalarSize + compNdx] = easyCases[easyCaseNdx].x;
720 				in1[valueNdx*scalarSize + compNdx] = easyCases[easyCaseNdx].y;
721 			}
722 
723 			valueNdx += 1;
724 		}
725 
726 		while (valueNdx < numValues)
727 		{
728 			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
729 			{
730 				const deUint32	base0	= rnd.getUint32();
731 				const deUint32	base1	= rnd.getUint32();
732 				const int		adj0	= rnd.getInt(0, 20);
733 				const int		adj1	= rnd.getInt(0, 20);
734 				in0[valueNdx*scalarSize + compNdx] = base0 >> adj0;
735 				in1[valueNdx*scalarSize + compNdx] = base1 >> adj1;
736 			}
737 
738 			valueNdx += 1;
739 		}
740 	}
741 
compare(const void * const * inputs,const void * const * outputs)742 	bool compare (const void* const* inputs, const void* const* outputs)
743 	{
744 		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
745 		const int				scalarSize		= glu::getDataTypeScalarSize(type);
746 
747 		for (int compNdx = 0; compNdx < scalarSize; compNdx++)
748 		{
749 			const deUint32	in0		= ((const deUint32*)inputs[0])[compNdx];
750 			const deUint32	in1		= ((const deUint32*)inputs[1])[compNdx];
751 			const deUint32	out0	= ((const deUint32*)outputs[0])[compNdx];
752 			const deUint32	out1	= ((const deUint32*)outputs[1])[compNdx];
753 			const deUint64	mul64	= deUint64(in0)*deUint64(in1);
754 			const deUint32	ref0	= deUint32(mul64 >> 32);
755 			const deUint32	ref1	= deUint32(mul64 & 0xffffffffu);
756 
757 			if (out0 != ref0 || out1 != ref1)
758 			{
759 				m_failMsg << "Expected [" << compNdx << "] = " << tcu::toHex(ref0) << ", " << tcu::toHex(ref1);
760 				return false;
761 			}
762 		}
763 
764 		return true;
765 	}
766 };
767 
768 class UmulExtendedCase : public IntegerFunctionCase
769 {
770 public:
UmulExtendedCase(tcu::TestContext & testCtx,glu::DataType baseType,glu::Precision precision,glu::ShaderType shaderType)771 	UmulExtendedCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
772 		: IntegerFunctionCase	(testCtx, getIntegerFuncCaseName(baseType, precision, shaderType).c_str(), "umulExtended", shaderType)
773 	{
774 		m_spec.inputs.push_back(Symbol("x", glu::VarType(baseType, precision)));
775 		m_spec.inputs.push_back(Symbol("y", glu::VarType(baseType, precision)));
776 		m_spec.outputs.push_back(Symbol("msb", glu::VarType(baseType, precision)));
777 		m_spec.outputs.push_back(Symbol("lsb", glu::VarType(baseType, precision)));
778 		m_spec.source = "umulExtended(x, y, msb, lsb);";
779 		init();
780 	}
781 
createInstance(Context & ctx) const782 	TestInstance* createInstance (Context& ctx) const
783 	{
784 		return new UmulExtendedCaseInstance(ctx, m_shaderType, m_spec, *m_executor, m_numValues, getName());
785 	}
786 };
787 
788 class ImulExtendedCaseInstance : public IntegerFunctionTestInstance
789 {
790 public:
ImulExtendedCaseInstance(Context & context,glu::ShaderType shaderType,ShaderSpec spec,ShaderExecutor & executor,int numValues,const char * name)791 	ImulExtendedCaseInstance (Context& context, glu::ShaderType shaderType, ShaderSpec spec, ShaderExecutor& executor, int numValues, const char* name)
792 		: IntegerFunctionTestInstance	(context, shaderType, spec, executor, numValues, name)
793 	{
794 	}
795 
getInputValues(int numValues,void * const * values) const796 	void getInputValues (int numValues, void* const* values) const
797 	{
798 		de::Random				rnd			(deStringHash(m_name) ^ 0x224fa1u);
799 		const glu::DataType		type		= m_spec.inputs[0].varType.getBasicType();
800 //		const glu::Precision	precision	= m_spec.inputs[0].varType.getPrecision();
801 		const int				scalarSize	= glu::getDataTypeScalarSize(type);
802 		deUint32*				in0			= (deUint32*)values[0];
803 		deUint32*				in1			= (deUint32*)values[1];
804 		int						valueNdx	= 0;
805 
806 		const struct
807 		{
808 			deUint32	x;
809 			deUint32	y;
810 		} easyCases[] =
811 		{
812 			{ 0x00000000u,	0x00000000u },
813 			{ 0xffffffffu,	0x00000002u },
814 			{ 0x7fffffffu,	0x00000001u },
815 			{ 0x7fffffffu,	0x00000002u },
816 			{ 0x7fffffffu,	0x7fffffffu },
817 			{ 0xffffffffu,	0xffffffffu },
818 			{ 0x7fffffffu,	0xfffffffeu },
819 		};
820 
821 		for (int easyCaseNdx = 0; easyCaseNdx < DE_LENGTH_OF_ARRAY(easyCases); easyCaseNdx++)
822 		{
823 			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
824 			{
825 				in0[valueNdx*scalarSize + compNdx] = (deInt32)easyCases[easyCaseNdx].x;
826 				in1[valueNdx*scalarSize + compNdx] = (deInt32)easyCases[easyCaseNdx].y;
827 			}
828 
829 			valueNdx += 1;
830 		}
831 
832 		while (valueNdx < numValues)
833 		{
834 			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
835 			{
836 				const deInt32	base0	= (deInt32)rnd.getUint32();
837 				const deInt32	base1	= (deInt32)rnd.getUint32();
838 				const int		adj0	= rnd.getInt(0, 20);
839 				const int		adj1	= rnd.getInt(0, 20);
840 				in0[valueNdx*scalarSize + compNdx] = base0 >> adj0;
841 				in1[valueNdx*scalarSize + compNdx] = base1 >> adj1;
842 			}
843 
844 			valueNdx += 1;
845 		}
846 	}
847 
compare(const void * const * inputs,const void * const * outputs)848 	bool compare (const void* const* inputs, const void* const* outputs)
849 	{
850 		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
851 		const int				scalarSize		= glu::getDataTypeScalarSize(type);
852 
853 		for (int compNdx = 0; compNdx < scalarSize; compNdx++)
854 		{
855 			const deInt32	in0		= ((const deInt32*)inputs[0])[compNdx];
856 			const deInt32	in1		= ((const deInt32*)inputs[1])[compNdx];
857 			const deInt32	out0	= ((const deInt32*)outputs[0])[compNdx];
858 			const deInt32	out1	= ((const deInt32*)outputs[1])[compNdx];
859 			const deInt64	mul64	= deInt64(in0)*deInt64(in1);
860 			const deInt32	ref0	= deInt32(mul64 >> 32);
861 			const deInt32	ref1	= deInt32(mul64 & 0xffffffffu);
862 
863 			if (out0 != ref0 || out1 != ref1)
864 			{
865 				m_failMsg << "Expected [" << compNdx << "] = " << tcu::toHex(ref0) << ", " << tcu::toHex(ref1);
866 				return false;
867 			}
868 		}
869 
870 		return true;
871 	}
872 };
873 
874 class ImulExtendedCase : public IntegerFunctionCase
875 {
876 public:
ImulExtendedCase(tcu::TestContext & testCtx,glu::DataType baseType,glu::Precision precision,glu::ShaderType shaderType)877 	ImulExtendedCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
878 		: IntegerFunctionCase	(testCtx, getIntegerFuncCaseName(baseType, precision, shaderType).c_str(), "imulExtended", shaderType)
879 	{
880 		m_spec.inputs.push_back(Symbol("x", glu::VarType(baseType, precision)));
881 		m_spec.inputs.push_back(Symbol("y", glu::VarType(baseType, precision)));
882 		m_spec.outputs.push_back(Symbol("msb", glu::VarType(baseType, precision)));
883 		m_spec.outputs.push_back(Symbol("lsb", glu::VarType(baseType, precision)));
884 		m_spec.source = "imulExtended(x, y, msb, lsb);";
885 		init();
886 	}
887 
createInstance(Context & ctx) const888 	TestInstance* createInstance (Context& ctx) const
889 	{
890 		return new ImulExtendedCaseInstance(ctx, m_shaderType, m_spec, *m_executor, m_numValues, getName());
891 	}
892 };
893 
894 class BitfieldExtractCaseInstance : public IntegerFunctionTestInstance
895 {
896 public:
BitfieldExtractCaseInstance(Context & context,glu::ShaderType shaderType,ShaderSpec spec,ShaderExecutor & executor,int numValues,const char * name)897 	BitfieldExtractCaseInstance (Context& context, glu::ShaderType shaderType, ShaderSpec spec, ShaderExecutor& executor, int numValues, const char* name)
898 		: IntegerFunctionTestInstance	(context, shaderType, spec, executor, numValues, name)
899 	{
900 	}
901 
getInputValues(int numValues,void * const * values) const902 	void getInputValues (int numValues, void* const* values) const
903 	{
904 		de::Random				rnd			(deStringHash(m_name) ^ 0xa113fca2u);
905 		const glu::DataType		type		= m_spec.inputs[0].varType.getBasicType();
906 		const glu::Precision	precision	= m_spec.inputs[0].varType.getPrecision();
907 		const bool				ignoreSign	= precision != glu::PRECISION_HIGHP && glu::isDataTypeIntOrIVec(type);
908 		const int				numBits		= getShaderUintBitCount(m_shaderType, precision) - (ignoreSign ? 1 : 0);
909 		deUint32*				inValue		= (deUint32*)values[0];
910 		int*					inOffset	= (int*)values[1];
911 		int*					inBits		= (int*)values[2];
912 
913 		for (int valueNdx = 0; valueNdx < numValues; ++valueNdx)
914 		{
915 			const int		bits	= rnd.getInt(0, numBits);
916 			const int		offset	= rnd.getInt(0, numBits-bits);
917 
918 			inOffset[valueNdx]	= offset;
919 			inBits[valueNdx]	= bits;
920 		}
921 
922 		generateRandomInputData(rnd, m_shaderType, type, precision, inValue, numValues);
923 	}
924 
compare(const void * const * inputs,const void * const * outputs)925 	bool compare (const void* const* inputs, const void* const* outputs)
926 	{
927 		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
928 		const bool				isSigned		= glu::isDataTypeIntOrIVec(type);
929 		const int				scalarSize		= glu::getDataTypeScalarSize(type);
930 		const int				offset			= *((const int*)inputs[1]);
931 		const int				bits			= *((const int*)inputs[2]);
932 
933 		for (int compNdx = 0; compNdx < scalarSize; compNdx++)
934 		{
935 			const deUint32	value	= ((const deUint32*)inputs[0])[compNdx];
936 			const deUint32	out		= ((const deUint32*)outputs[0])[compNdx];
937 			const deUint32	valMask	= (bits == 32 ? ~0u : ((1u<<bits)-1u));
938 			const deUint32	baseVal	= (offset == 32) ? (0) : ((value >> offset) & valMask);
939 			const deUint32	ref		= baseVal | ((isSigned && (baseVal & (1<<(bits-1)))) ? ~valMask : 0u);
940 
941 			if (out != ref)
942 			{
943 				m_failMsg << "Expected [" << compNdx << "] = " << tcu::toHex(ref);
944 				return false;
945 			}
946 		}
947 
948 		return true;
949 	}
950 };
951 
952 class BitfieldExtractCase : public IntegerFunctionCase
953 {
954 public:
BitfieldExtractCase(tcu::TestContext & testCtx,glu::DataType baseType,glu::Precision precision,glu::ShaderType shaderType)955 	BitfieldExtractCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
956 		: IntegerFunctionCase	(testCtx, getIntegerFuncCaseName(baseType, precision, shaderType).c_str(), "bitfieldExtract", shaderType)
957 	{
958 		m_spec.inputs.push_back(Symbol("value", glu::VarType(baseType, precision)));
959 		m_spec.inputs.push_back(Symbol("offset", glu::VarType(glu::TYPE_INT, precision)));
960 		m_spec.inputs.push_back(Symbol("bits", glu::VarType(glu::TYPE_INT, precision)));
961 		m_spec.outputs.push_back(Symbol("extracted", glu::VarType(baseType, precision)));
962 		m_spec.source = "extracted = bitfieldExtract(value, offset, bits);";
963 		init();
964 	}
965 
createInstance(Context & ctx) const966 	TestInstance* createInstance (Context& ctx) const
967 	{
968 		return new BitfieldExtractCaseInstance(ctx, m_shaderType, m_spec, *m_executor, m_numValues, getName());
969 	}
970 };
971 
972 class BitfieldInsertCaseInstance : public IntegerFunctionTestInstance
973 {
974 public:
BitfieldInsertCaseInstance(Context & context,glu::ShaderType shaderType,ShaderSpec spec,ShaderExecutor & executor,int numValues,const char * name)975 	BitfieldInsertCaseInstance (Context& context, glu::ShaderType shaderType, ShaderSpec spec, ShaderExecutor& executor, int numValues, const char* name)
976 		: IntegerFunctionTestInstance	(context, shaderType, spec, executor, numValues, name)
977 	{
978 	}
979 
getInputValues(int numValues,void * const * values) const980 	void getInputValues (int numValues, void* const* values) const
981 	{
982 		de::Random				rnd			(deStringHash(m_name) ^ 0x12c2acff);
983 		const glu::DataType		type		= m_spec.inputs[0].varType.getBasicType();
984 		const glu::Precision	precision	= m_spec.inputs[0].varType.getPrecision();
985 		const int				numBits		= getShaderUintBitCount(m_shaderType, precision);
986 		deUint32*				inBase		= (deUint32*)values[0];
987 		deUint32*				inInsert	= (deUint32*)values[1];
988 		int*					inOffset	= (int*)values[2];
989 		int*					inBits		= (int*)values[3];
990 
991 		for (int valueNdx = 0; valueNdx < numValues; ++valueNdx)
992 		{
993 			const int bits		= rnd.getInt(0, numBits);
994 			const int offset	= rnd.getInt(0, numBits-bits);
995 
996 			inOffset[valueNdx]	= offset;
997 			inBits[valueNdx]	= bits;
998 		}
999 
1000 		generateRandomInputData(rnd, m_shaderType, type, precision, inBase, numValues);
1001 		generateRandomInputData(rnd, m_shaderType, type, precision, inInsert, numValues);
1002 	}
1003 
compare(const void * const * inputs,const void * const * outputs)1004 	bool compare (const void* const* inputs, const void* const* outputs)
1005 	{
1006 		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
1007 		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
1008 		const int				scalarSize		= glu::getDataTypeScalarSize(type);
1009 		const int				integerLength	= getShaderUintBitCount(m_shaderType, precision);
1010 		const deUint32			cmpMask			= getLowBitMask(integerLength);
1011 		const int				offset			= *((const int*)inputs[2]);
1012 		const int				bits			= *((const int*)inputs[3]);
1013 
1014 		for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1015 		{
1016 			const deUint32	base	= ((const deUint32*)inputs[0])[compNdx];
1017 			const deUint32	insert	= ((const deUint32*)inputs[1])[compNdx];
1018 			const deInt32	out		= ((const deUint32*)outputs[0])[compNdx];
1019 
1020 			const deUint32	mask	= bits == 32 ? ~0u : (1u<<bits)-1;
1021 			const deUint32	ref		= (base & ~(mask<<offset)) | ((insert & mask)<<offset);
1022 
1023 			if ((out&cmpMask) != (ref&cmpMask))
1024 			{
1025 				m_failMsg << "Expected [" << compNdx << "] = " << tcu::toHex(ref);
1026 				return false;
1027 			}
1028 		}
1029 
1030 		return true;
1031 	}
1032 };
1033 
1034 class BitfieldInsertCase : public IntegerFunctionCase
1035 {
1036 public:
BitfieldInsertCase(tcu::TestContext & testCtx,glu::DataType baseType,glu::Precision precision,glu::ShaderType shaderType)1037 	BitfieldInsertCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
1038 		: IntegerFunctionCase	(testCtx, getIntegerFuncCaseName(baseType, precision, shaderType).c_str(), "bitfieldInsert", shaderType)
1039 	{
1040 		m_spec.inputs.push_back(Symbol("base", glu::VarType(baseType, precision)));
1041 		m_spec.inputs.push_back(Symbol("insert", glu::VarType(baseType, precision)));
1042 		m_spec.inputs.push_back(Symbol("offset", glu::VarType(glu::TYPE_INT, precision)));
1043 		m_spec.inputs.push_back(Symbol("bits", glu::VarType(glu::TYPE_INT, precision)));
1044 		m_spec.outputs.push_back(Symbol("result", glu::VarType(baseType, precision)));
1045 		m_spec.source = "result = bitfieldInsert(base, insert, offset, bits);";
1046 		init();
1047 	}
1048 
createInstance(Context & ctx) const1049 	TestInstance* createInstance (Context& ctx) const
1050 	{
1051 		return new BitfieldInsertCaseInstance(ctx, m_shaderType, m_spec, *m_executor, m_numValues, getName());
1052 	}
1053 };
1054 
1055 class BitfieldReverseCaseInstance : public IntegerFunctionTestInstance
1056 {
1057 public:
BitfieldReverseCaseInstance(Context & context,glu::ShaderType shaderType,ShaderSpec spec,ShaderExecutor & executor,int numValues,const char * name)1058 	BitfieldReverseCaseInstance (Context& context, glu::ShaderType shaderType, ShaderSpec spec, ShaderExecutor& executor, int numValues, const char* name)
1059 		: IntegerFunctionTestInstance	(context, shaderType, spec, executor, numValues, name)
1060 	{
1061 	}
1062 
getInputValues(int numValues,void * const * values) const1063 	void getInputValues (int numValues, void* const* values) const
1064 	{
1065 		de::Random				rnd			(deStringHash(m_name) ^ 0xff23a4);
1066 		const glu::DataType		type		= m_spec.inputs[0].varType.getBasicType();
1067 		const glu::Precision	precision	= m_spec.inputs[0].varType.getPrecision();
1068 		deUint32*				inValue		= (deUint32*)values[0];
1069 
1070 		generateRandomInputData(rnd, m_shaderType, type, precision, inValue, numValues);
1071 	}
1072 
compare(const void * const * inputs,const void * const * outputs)1073 	bool compare (const void* const* inputs, const void* const* outputs)
1074 	{
1075 		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
1076 		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
1077 		const int				integerLength	= getShaderUintBitCount(m_shaderType, precision);
1078 		const int				scalarSize		= glu::getDataTypeScalarSize(type);
1079 		const deUint32			cmpMask			= reverseBits(getLowBitMask(integerLength));
1080 
1081 		for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1082 		{
1083 			const deUint32	value	= ((const deUint32*)inputs[0])[compNdx];
1084 			const deInt32	out		= ((const deUint32*)outputs[0])[compNdx];
1085 			const deUint32	ref		= reverseBits(value);
1086 
1087 			if ((out&cmpMask) != (ref&cmpMask))
1088 			{
1089 				m_failMsg << "Expected [" << compNdx << "] = " << tcu::toHex(ref);
1090 				return false;
1091 			}
1092 		}
1093 
1094 		return true;
1095 	}
1096 };
1097 
1098 class BitfieldReverseCase : public IntegerFunctionCase
1099 {
1100 public:
BitfieldReverseCase(tcu::TestContext & testCtx,glu::DataType baseType,glu::Precision precision,glu::ShaderType shaderType)1101 	BitfieldReverseCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
1102 		: IntegerFunctionCase	(testCtx, getIntegerFuncCaseName(baseType, precision, shaderType).c_str(), "bitfieldReverse", shaderType)
1103 	{
1104 		m_spec.inputs.push_back(Symbol("value", glu::VarType(baseType, precision)));
1105 		m_spec.outputs.push_back(Symbol("result", glu::VarType(baseType, glu::PRECISION_HIGHP)));
1106 		m_spec.source = "result = bitfieldReverse(value);";
1107 		init();
1108 	}
1109 
createInstance(Context & ctx) const1110 	TestInstance* createInstance (Context& ctx) const
1111 	{
1112 		return new BitfieldReverseCaseInstance(ctx, m_shaderType, m_spec, *m_executor, m_numValues, getName());
1113 	}
1114 };
1115 
1116 class BitCountCaseInstance : public IntegerFunctionTestInstance
1117 {
1118 public:
BitCountCaseInstance(Context & context,glu::ShaderType shaderType,ShaderSpec spec,ShaderExecutor & executor,int numValues,const char * name)1119 	BitCountCaseInstance (Context& context, glu::ShaderType shaderType, ShaderSpec spec, ShaderExecutor& executor, int numValues, const char* name)
1120 		: IntegerFunctionTestInstance	(context, shaderType, spec, executor, numValues, name)
1121 	{
1122 	}
1123 
getInputValues(int numValues,void * const * values) const1124 	void getInputValues (int numValues, void* const* values) const
1125 	{
1126 		de::Random				rnd			(deStringHash(m_name) ^ 0xab2cca4);
1127 		const glu::DataType		type		= m_spec.inputs[0].varType.getBasicType();
1128 		const glu::Precision	precision	= m_spec.inputs[0].varType.getPrecision();
1129 		deUint32*				inValue		= (deUint32*)values[0];
1130 
1131 		generateRandomInputData(rnd, m_shaderType, type, precision, inValue, numValues);
1132 	}
1133 
compare(const void * const * inputs,const void * const * outputs)1134 	bool compare (const void* const* inputs, const void* const* outputs)
1135 	{
1136 		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
1137 		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
1138 		const int				integerLength	= getShaderUintBitCount(m_shaderType, precision);
1139 		const int				scalarSize		= glu::getDataTypeScalarSize(type);
1140 		const deUint32			countMask		= getLowBitMask(integerLength);
1141 
1142 		for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1143 		{
1144 			const deUint32	value	= ((const deUint32*)inputs[0])[compNdx];
1145 			const int		out		= ((const int*)outputs[0])[compNdx];
1146 			const int		minRef	= dePop32(value&countMask);
1147 			const int		maxRef	= dePop32(value);
1148 
1149 			if (!de::inRange(out, minRef, maxRef))
1150 			{
1151 				m_failMsg << "Expected [" << compNdx << "] in range [" << minRef << ", " << maxRef << "]";
1152 				return false;
1153 			}
1154 		}
1155 
1156 		return true;
1157 	}
1158 };
1159 
1160 class BitCountCase : public IntegerFunctionCase
1161 {
1162 public:
BitCountCase(tcu::TestContext & testCtx,glu::DataType baseType,glu::Precision precision,glu::ShaderType shaderType)1163 	BitCountCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
1164 		: IntegerFunctionCase	(testCtx, getIntegerFuncCaseName(baseType, precision, shaderType).c_str(), "bitCount", shaderType)
1165 	{
1166 		const int			vecSize		= glu::getDataTypeScalarSize(baseType);
1167 		const glu::DataType	intType		= vecSize == 1 ? glu::TYPE_INT : glu::getDataTypeIntVec(vecSize);
1168 
1169 		m_spec.inputs.push_back(Symbol("value", glu::VarType(baseType, precision)));
1170 		m_spec.outputs.push_back(Symbol("count", glu::VarType(intType, glu::PRECISION_MEDIUMP)));
1171 		m_spec.source = "count = bitCount(value);";
1172 		init();
1173 	}
1174 
createInstance(Context & ctx) const1175 	TestInstance* createInstance (Context& ctx) const
1176 	{
1177 		return new BitCountCaseInstance(ctx, m_shaderType, m_spec, *m_executor, m_numValues, getName());
1178 	}
1179 };
1180 
1181 class FindLSBCaseInstance : public IntegerFunctionTestInstance
1182 {
1183 public:
FindLSBCaseInstance(Context & context,glu::ShaderType shaderType,ShaderSpec spec,ShaderExecutor & executor,int numValues,const char * name)1184 	FindLSBCaseInstance (Context& context, glu::ShaderType shaderType, ShaderSpec spec, ShaderExecutor& executor, int numValues, const char* name)
1185 		: IntegerFunctionTestInstance	(context, shaderType, spec, executor, numValues, name)
1186 	{
1187 	}
1188 
getInputValues(int numValues,void * const * values) const1189 	void getInputValues (int numValues, void* const* values) const
1190 	{
1191 		de::Random				rnd			(deStringHash(m_name) ^ 0x9923c2af);
1192 		const glu::DataType		type		= m_spec.inputs[0].varType.getBasicType();
1193 		const glu::Precision	precision	= m_spec.inputs[0].varType.getPrecision();
1194 		deUint32*				inValue		= (deUint32*)values[0];
1195 
1196 		generateRandomInputData(rnd, m_shaderType, type, precision, inValue, numValues);
1197 	}
1198 
compare(const void * const * inputs,const void * const * outputs)1199 	bool compare (const void* const* inputs, const void* const* outputs)
1200 	{
1201 		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
1202 		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
1203 		const int				scalarSize		= glu::getDataTypeScalarSize(type);
1204 		const int				integerLength	= getShaderUintBitCount(m_shaderType, precision);
1205 		const deUint32			mask			= getLowBitMask(integerLength);
1206 
1207 		for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1208 		{
1209 			const deUint32	value	= ((const deUint32*)inputs[0])[compNdx];
1210 			const int		out		= ((const int*)outputs[0])[compNdx];
1211 			const int		minRef	= findLSB(value&mask);
1212 			const int		maxRef	= findLSB(value);
1213 
1214 			if (!de::inRange(out, minRef, maxRef))
1215 			{
1216 				m_failMsg << "Expected [" << compNdx << "] in range [" << minRef << ", " << maxRef << "]";
1217 				return false;
1218 			}
1219 		}
1220 
1221 		return true;
1222 	}
1223 };
1224 
1225 class FindLSBCase : public IntegerFunctionCase
1226 {
1227 public:
FindLSBCase(tcu::TestContext & testCtx,glu::DataType baseType,glu::Precision precision,glu::ShaderType shaderType)1228 	FindLSBCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
1229 		: IntegerFunctionCase	(testCtx, getIntegerFuncCaseName(baseType, precision, shaderType).c_str(), "findLSB", shaderType)
1230 	{
1231 		const int			vecSize		= glu::getDataTypeScalarSize(baseType);
1232 		const glu::DataType	intType		= vecSize == 1 ? glu::TYPE_INT : glu::getDataTypeIntVec(vecSize);
1233 
1234 		m_spec.inputs.push_back(Symbol("value", glu::VarType(baseType, precision)));
1235 		m_spec.outputs.push_back(Symbol("lsb", glu::VarType(intType, glu::PRECISION_LOWP)));
1236 		m_spec.source = "lsb = findLSB(value);";
1237 		init();
1238 	}
1239 
createInstance(Context & ctx) const1240 	TestInstance* createInstance (Context& ctx) const
1241 	{
1242 		return new FindLSBCaseInstance(ctx, m_shaderType, m_spec, *m_executor, m_numValues, getName());
1243 	}
1244 };
1245 
1246 class findMSBCaseInstance : public IntegerFunctionTestInstance
1247 {
1248 public:
findMSBCaseInstance(Context & context,glu::ShaderType shaderType,ShaderSpec spec,ShaderExecutor & executor,int numValues,const char * name)1249 	findMSBCaseInstance (Context& context, glu::ShaderType shaderType, ShaderSpec spec, ShaderExecutor& executor, int numValues, const char* name)
1250 		: IntegerFunctionTestInstance	(context, shaderType, spec, executor, numValues, name)
1251 	{
1252 	}
1253 
getInputValues(int numValues,void * const * values) const1254 	void getInputValues (int numValues, void* const* values) const
1255 	{
1256 		de::Random				rnd			(deStringHash(m_name) ^ 0x742ac4e);
1257 		const glu::DataType		type		= m_spec.inputs[0].varType.getBasicType();
1258 		const glu::Precision	precision	= m_spec.inputs[0].varType.getPrecision();
1259 		deUint32*				inValue		= (deUint32*)values[0];
1260 
1261 		generateRandomInputData(rnd, m_shaderType, type, precision, inValue, numValues);
1262 	}
1263 
compare(const void * const * inputs,const void * const * outputs)1264 	bool compare (const void* const* inputs, const void* const* outputs)
1265 	{
1266 		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
1267 		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
1268 		const bool				isSigned		= glu::isDataTypeIntOrIVec(type);
1269 		const int				scalarSize		= glu::getDataTypeScalarSize(type);
1270 		const int				integerLength	= getShaderUintBitCount(m_shaderType, precision);
1271 
1272 		for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1273 		{
1274 			const deUint32	value	= ((const deUint32*)inputs[0])[compNdx];
1275 			const int		out		= ((const deInt32*)outputs[0])[compNdx];
1276 			const int		minRef	= isSigned ? findMSB(toPrecision(deInt32(value), integerLength))	: findMSB(toPrecision(value, integerLength));
1277 			const int		maxRef	= isSigned ? findMSB(deInt32(value))								: findMSB(value);
1278 
1279 			if (!de::inRange(out, minRef, maxRef))
1280 			{
1281 				m_failMsg << "Expected [" << compNdx << "] in range [" << minRef << ", " << maxRef << "]";
1282 				return false;
1283 			}
1284 		}
1285 
1286 		return true;
1287 	}
1288 };
1289 
1290 class findMSBCase : public IntegerFunctionCase
1291 {
1292 public:
findMSBCase(tcu::TestContext & testCtx,glu::DataType baseType,glu::Precision precision,glu::ShaderType shaderType)1293 	findMSBCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
1294 		: IntegerFunctionCase	(testCtx, getIntegerFuncCaseName(baseType, precision, shaderType).c_str(), "findMSB", shaderType)
1295 	{
1296 		const int			vecSize		= glu::getDataTypeScalarSize(baseType);
1297 		const glu::DataType	intType		= vecSize == 1 ? glu::TYPE_INT : glu::getDataTypeIntVec(vecSize);
1298 
1299 		m_spec.inputs.push_back(Symbol("value", glu::VarType(baseType, precision)));
1300 		m_spec.outputs.push_back(Symbol("msb", glu::VarType(intType, glu::PRECISION_LOWP)));
1301 		m_spec.source = "msb = findMSB(value);";
1302 		init();
1303 	}
1304 
createInstance(Context & ctx) const1305 	TestInstance* createInstance (Context& ctx) const
1306 	{
1307 		return new findMSBCaseInstance(ctx, m_shaderType, m_spec, *m_executor, m_numValues, getName());
1308 	}
1309 };
1310 
ShaderIntegerFunctionTests(tcu::TestContext & testCtx)1311 ShaderIntegerFunctionTests::ShaderIntegerFunctionTests (tcu::TestContext& testCtx)
1312 	: tcu::TestCaseGroup	(testCtx, "integer", "Integer function tests")
1313 {
1314 }
1315 
~ShaderIntegerFunctionTests(void)1316 ShaderIntegerFunctionTests::~ShaderIntegerFunctionTests (void)
1317 {
1318 }
1319 
init(void)1320 void ShaderIntegerFunctionTests::init (void)
1321 {
1322 	enum
1323 	{
1324 		VS = (1<<glu::SHADERTYPE_VERTEX),
1325 		FS = (1<<glu::SHADERTYPE_FRAGMENT),
1326 		CS = (1<<glu::SHADERTYPE_COMPUTE),
1327 		GS = (1<<glu::SHADERTYPE_GEOMETRY),
1328 		TC = (1<<glu::SHADERTYPE_TESSELLATION_CONTROL),
1329 		TE = (1<<glu::SHADERTYPE_TESSELLATION_EVALUATION),
1330 
1331 		ALL_SHADERS = VS|TC|TE|GS|FS|CS
1332 	};
1333 
1334 	//																		Int?	Uint?	AllPrec?	Shaders
1335 	addFunctionCases<UaddCarryCase>				(this,	"uaddcarry",		false,	true,	true,		ALL_SHADERS);
1336 	addFunctionCases<UsubBorrowCase>			(this,	"usubborrow",		false,	true,	true,		ALL_SHADERS);
1337 	addFunctionCases<UmulExtendedCase>			(this,	"umulextended",		false,	true,	false,		ALL_SHADERS);
1338 	addFunctionCases<ImulExtendedCase>			(this,	"imulextended",		true,	false,	false,		ALL_SHADERS);
1339 	addFunctionCases<BitfieldExtractCase>		(this,	"bitfieldextract",	true,	true,	true,		ALL_SHADERS);
1340 	addFunctionCases<BitfieldInsertCase>		(this,	"bitfieldinsert",	true,	true,	true,		ALL_SHADERS);
1341 	addFunctionCases<BitfieldReverseCase>		(this,	"bitfieldreverse",	true,	true,	true,		ALL_SHADERS);
1342 	addFunctionCases<BitCountCase>				(this,	"bitcount",			true,	true,	true,		ALL_SHADERS);
1343 	addFunctionCases<FindLSBCase>				(this,	"findlsb",			true,	true,	true,		ALL_SHADERS);
1344 	addFunctionCases<findMSBCase>				(this,	"findMSB",			true,	true,	true,		ALL_SHADERS);
1345 }
1346 
1347 } // shaderexecutor
1348 } // vkt
1349