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 											generateSources(m_shaderType, m_spec, programCollection);
325 										}
326 
327 	virtual TestInstance*				createInstance			(Context& context) const = 0;
328 
329 protected:
330 										IntegerFunctionCase		(const IntegerFunctionCase& other);
331 	IntegerFunctionCase&				operator=				(const IntegerFunctionCase& other);
332 
333 	const glu::ShaderType				m_shaderType;
334 
335 	ShaderSpec							m_spec;
336 
337 	const int							m_numValues;
338 };
339 
IntegerFunctionCase(tcu::TestContext & testCtx,const char * name,const char * description,glu::ShaderType shaderType)340 IntegerFunctionCase::IntegerFunctionCase (tcu::TestContext& testCtx, const char* name, const char* description, glu::ShaderType shaderType)
341 	: TestCase		(testCtx, name, description)
342 	, m_shaderType	(shaderType)
343 	, m_numValues	(100)
344 {
345 }
346 
~IntegerFunctionCase(void)347 IntegerFunctionCase::~IntegerFunctionCase (void)
348 {
349 }
350 
351 // IntegerFunctionTestInstance
352 
353 class IntegerFunctionTestInstance : public TestInstance
354 {
355 public:
IntegerFunctionTestInstance(Context & context,glu::ShaderType shaderType,const ShaderSpec & spec,int numValues,const char * name)356 								IntegerFunctionTestInstance		(Context& context, glu::ShaderType shaderType, const ShaderSpec& spec, int numValues, const char* name)
357 									: TestInstance	(context)
358 									, m_shaderType	(shaderType)
359 									, m_spec		(spec)
360 									, m_numValues	(numValues)
361 									, m_name		(name)
362 									, m_executor	(createExecutor(context, m_shaderType, m_spec))
363 								{
364 								}
365 	virtual tcu::TestStatus		iterate							(void);
366 protected:
367 	virtual bool						compare					(const void* const* inputs, const void* const* outputs) = 0;
368 
369 	virtual void						getInputValues			(int numValues, void* const* values) const = 0;
370 
371 	const glu::ShaderType				m_shaderType;
372 
373 	ShaderSpec							m_spec;
374 
375 	const int							m_numValues;
376 
377 	const char*							m_name;
378 
379 	std::ostringstream					m_failMsg;				//!< Comparison failure help message.
380 
381 	de::UniquePtr<ShaderExecutor>		m_executor;
382 };
383 
iterate(void)384 tcu::TestStatus IntegerFunctionTestInstance::iterate (void)
385 {
386 	const int				numInputScalars			= computeTotalScalarSize(m_spec.inputs);
387 	const int				numOutputScalars		= computeTotalScalarSize(m_spec.outputs);
388 	vector<deUint32>		inputData				(numInputScalars * m_numValues);
389 	vector<deUint32>		outputData				(numOutputScalars * m_numValues);
390 	const vector<void*>		inputPointers			= getInputOutputPointers(m_spec.inputs, inputData, m_numValues);
391 	const vector<void*>		outputPointers			= getInputOutputPointers(m_spec.outputs, outputData, m_numValues);
392 
393 	// Initialize input data.
394 	getInputValues(m_numValues, &inputPointers[0]);
395 
396 	// Execute shader.
397 	m_executor->execute(m_numValues, &inputPointers[0], &outputPointers[0]);
398 
399 	// Compare results.
400 	{
401 		const vector<int>		inScalarSizes		= getScalarSizes(m_spec.inputs);
402 		const vector<int>		outScalarSizes		= getScalarSizes(m_spec.outputs);
403 		vector<void*>			curInputPtr			(inputPointers.size());
404 		vector<void*>			curOutputPtr		(outputPointers.size());
405 		int						numFailed			= 0;
406 		tcu::TestContext&		testCtx				= m_context.getTestContext();
407 		for (int valNdx = 0; valNdx < m_numValues; valNdx++)
408 		{
409 			// Set up pointers for comparison.
410 			for (int inNdx = 0; inNdx < (int)curInputPtr.size(); ++inNdx)
411 				curInputPtr[inNdx] = (deUint32*)inputPointers[inNdx] + inScalarSizes[inNdx]*valNdx;
412 
413 			for (int outNdx = 0; outNdx < (int)curOutputPtr.size(); ++outNdx)
414 				curOutputPtr[outNdx] = (deUint32*)outputPointers[outNdx] + outScalarSizes[outNdx]*valNdx;
415 
416 			if (!compare(&curInputPtr[0], &curOutputPtr[0]))
417 			{
418 				// \todo [2013-08-08 pyry] We probably want to log reference value as well?
419 
420 				testCtx.getLog() << TestLog::Message << "ERROR: comparison failed for value " << valNdx << ":\n  " << m_failMsg.str() << TestLog::EndMessage;
421 
422 				testCtx.getLog() << TestLog::Message << "  inputs:" << TestLog::EndMessage;
423 				for (int inNdx = 0; inNdx < (int)curInputPtr.size(); inNdx++)
424 					testCtx.getLog() << TestLog::Message << "    " << m_spec.inputs[inNdx].name << " = "
425 														   << VarValue(m_spec.inputs[inNdx].varType, curInputPtr[inNdx])
426 									   << TestLog::EndMessage;
427 
428 				testCtx.getLog() << TestLog::Message << "  outputs:" << TestLog::EndMessage;
429 				for (int outNdx = 0; outNdx < (int)curOutputPtr.size(); outNdx++)
430 					testCtx.getLog() << TestLog::Message << "    " << m_spec.outputs[outNdx].name << " = "
431 														   << VarValue(m_spec.outputs[outNdx].varType, curOutputPtr[outNdx])
432 									   << TestLog::EndMessage;
433 
434 				m_failMsg.str("");
435 				m_failMsg.clear();
436 				numFailed += 1;
437 			}
438 		}
439 
440 		testCtx.getLog() << TestLog::Message << (m_numValues - numFailed) << " / " << m_numValues << " values passed" << TestLog::EndMessage;
441 
442 		if (numFailed == 0)
443 			return tcu::TestStatus::pass("Pass");
444 		else
445 			return tcu::TestStatus::fail("Result comparison failed");
446 	}
447 }
448 
449 // Test cases
450 
451 class UaddCarryCaseInstance : public IntegerFunctionTestInstance
452 {
453 public:
UaddCarryCaseInstance(Context & context,glu::ShaderType shaderType,const ShaderSpec & spec,int numValues,const char * name)454 	UaddCarryCaseInstance (Context& context, glu::ShaderType shaderType, const ShaderSpec& spec, int numValues, const char* name)
455 		: IntegerFunctionTestInstance	(context, shaderType, spec, numValues, name)
456 	{
457 	}
458 
getInputValues(int numValues,void * const * values) const459 	void getInputValues (int numValues, void* const* values) const
460 	{
461 		de::Random				rnd				(deStringHash(m_name) ^ 0x235facu);
462 		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
463 		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
464 		const int				scalarSize		= glu::getDataTypeScalarSize(type);
465 		const int				integerLength	= getShaderUintBitCount(m_shaderType, precision);
466 		const deUint32			integerMask		= getLowBitMask(integerLength);
467 		const bool				isSigned		= glu::isDataTypeIntOrIVec(type);
468 		deUint32*				in0				= (deUint32*)values[0];
469 		deUint32*				in1				= (deUint32*)values[1];
470 
471 		const struct
472 		{
473 			deUint32	x;
474 			deUint32	y;
475 		} easyCases[] =
476 		{
477 			{ 0x00000000u,	0x00000000u },
478 			{ 0xfffffffeu,	0x00000001u },
479 			{ 0x00000001u,	0xfffffffeu },
480 			{ 0xffffffffu,	0x00000001u },
481 			{ 0x00000001u,	0xffffffffu },
482 			{ 0xfffffffeu,	0x00000002u },
483 			{ 0x00000002u,	0xfffffffeu },
484 			{ 0xffffffffu,	0xffffffffu }
485 		};
486 
487 		// generate integers with proper bit count
488 		for (int easyCaseNdx = 0; easyCaseNdx < DE_LENGTH_OF_ARRAY(easyCases); easyCaseNdx++)
489 		{
490 			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
491 			{
492 				in0[easyCaseNdx*scalarSize + compNdx] = easyCases[easyCaseNdx].x & integerMask;
493 				in1[easyCaseNdx*scalarSize + compNdx] = easyCases[easyCaseNdx].y & integerMask;
494 			}
495 		}
496 
497 		// convert to signed
498 		if (isSigned)
499 		{
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] = extendSignTo32(in0[easyCaseNdx*scalarSize + compNdx], integerLength);
505 					in1[easyCaseNdx*scalarSize + compNdx] = extendSignTo32(in1[easyCaseNdx*scalarSize + compNdx], integerLength);
506 				}
507 			}
508 		}
509 
510 		generateRandomInputData(rnd, m_shaderType, type, precision, in0, numValues - DE_LENGTH_OF_ARRAY(easyCases));
511 		generateRandomInputData(rnd, m_shaderType, type, precision, in1, numValues - DE_LENGTH_OF_ARRAY(easyCases));
512 	}
513 
compare(const void * const * inputs,const void * const * outputs)514 	bool compare (const void* const* inputs, const void* const* outputs)
515 	{
516 		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
517 		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
518 		const int				scalarSize		= glu::getDataTypeScalarSize(type);
519 		const int				integerLength	= getShaderUintBitCount(m_shaderType, precision);
520 		const deUint32			mask0			= getLowBitMask(integerLength);
521 
522 		for (int compNdx = 0; compNdx < scalarSize; compNdx++)
523 		{
524 			const deUint32	in0		= ((const deUint32*)inputs[0])[compNdx];
525 			const deUint32	in1		= ((const deUint32*)inputs[1])[compNdx];
526 			const deUint32	out0	= ((const deUint32*)outputs[0])[compNdx];
527 			const deUint32	out1	= ((const deUint32*)outputs[1])[compNdx];
528 			const deUint32	ref0	= in0+in1;
529 			const deUint32	ref1	= (deUint64(in0)+deUint64(in1)) > 0xffffffffu ? 1u : 0u;
530 
531 			if (((out0&mask0) != (ref0&mask0)) || out1 != ref1)
532 			{
533 				m_failMsg << "Expected [" << compNdx << "] = " << tcu::toHex(ref0) << ", " << tcu::toHex(ref1);
534 				return false;
535 			}
536 		}
537 
538 		return true;
539 	}
540 };
541 
542 class UaddCarryCase : public IntegerFunctionCase
543 {
544 public:
UaddCarryCase(tcu::TestContext & testCtx,glu::DataType baseType,glu::Precision precision,glu::ShaderType shaderType)545 	UaddCarryCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
546 		: IntegerFunctionCase	(testCtx, getIntegerFuncCaseName(baseType, precision, shaderType).c_str(), "uaddCarry", shaderType)
547 	{
548 		m_spec.inputs.push_back(Symbol("x", glu::VarType(baseType, precision)));
549 		m_spec.inputs.push_back(Symbol("y", glu::VarType(baseType, precision)));
550 		m_spec.outputs.push_back(Symbol("sum", glu::VarType(baseType, precision)));
551 		m_spec.outputs.push_back(Symbol("carry", glu::VarType(baseType, glu::PRECISION_LOWP)));
552 		m_spec.source = "sum = uaddCarry(x, y, carry);";
553 	}
554 
createInstance(Context & ctx) const555 	TestInstance* createInstance (Context& ctx) const
556 	{
557 		return new UaddCarryCaseInstance(ctx, m_shaderType, m_spec, m_numValues, getName());
558 	}
559 };
560 
561 class UsubBorrowCaseInstance : public IntegerFunctionTestInstance
562 {
563 public:
UsubBorrowCaseInstance(Context & context,glu::ShaderType shaderType,const ShaderSpec & spec,int numValues,const char * name)564 	UsubBorrowCaseInstance (Context& context, glu::ShaderType shaderType, const ShaderSpec& spec, int numValues, const char* name)
565 		: IntegerFunctionTestInstance	(context, shaderType, spec, numValues, name)
566 	{
567 	}
568 
getInputValues(int numValues,void * const * values) const569 	void getInputValues (int numValues, void* const* values) const
570 	{
571 		de::Random				rnd				(deStringHash(m_name) ^ 0x235facu);
572 		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
573 		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
574 		const int				scalarSize		= glu::getDataTypeScalarSize(type);
575 		const int				integerLength	= getShaderUintBitCount(m_shaderType, precision);
576 		const deUint32			integerMask		= getLowBitMask(integerLength);
577 		const bool				isSigned		= glu::isDataTypeIntOrIVec(type);
578 		deUint32*				in0				= (deUint32*)values[0];
579 		deUint32*				in1				= (deUint32*)values[1];
580 
581 		const struct
582 		{
583 			deUint32	x;
584 			deUint32	y;
585 		} easyCases[] =
586 		{
587 			{ 0x00000000u,	0x00000000u },
588 			{ 0x00000001u,	0x00000001u },
589 			{ 0x00000001u,	0x00000002u },
590 			{ 0x00000001u,	0xffffffffu },
591 			{ 0xfffffffeu,	0xffffffffu },
592 			{ 0xffffffffu,	0xffffffffu },
593 		};
594 
595 		// generate integers with proper bit count
596 		for (int easyCaseNdx = 0; easyCaseNdx < DE_LENGTH_OF_ARRAY(easyCases); easyCaseNdx++)
597 		{
598 			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
599 			{
600 				in0[easyCaseNdx*scalarSize + compNdx] = easyCases[easyCaseNdx].x & integerMask;
601 				in1[easyCaseNdx*scalarSize + compNdx] = easyCases[easyCaseNdx].y & integerMask;
602 			}
603 		}
604 
605 		// convert to signed
606 		if (isSigned)
607 		{
608 			for (int easyCaseNdx = 0; easyCaseNdx < DE_LENGTH_OF_ARRAY(easyCases); easyCaseNdx++)
609 			{
610 				for (int compNdx = 0; compNdx < scalarSize; compNdx++)
611 				{
612 					in0[easyCaseNdx*scalarSize + compNdx] = extendSignTo32(in0[easyCaseNdx*scalarSize + compNdx], integerLength);
613 					in1[easyCaseNdx*scalarSize + compNdx] = extendSignTo32(in1[easyCaseNdx*scalarSize + compNdx], integerLength);
614 				}
615 			}
616 		}
617 
618 		generateRandomInputData(rnd, m_shaderType, type, precision, in0, numValues - DE_LENGTH_OF_ARRAY(easyCases));
619 		generateRandomInputData(rnd, m_shaderType, type, precision, in1, numValues - DE_LENGTH_OF_ARRAY(easyCases));
620 	}
621 
compare(const void * const * inputs,const void * const * outputs)622 	bool compare (const void* const* inputs, const void* const* outputs)
623 	{
624 		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
625 		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
626 		const int				scalarSize		= glu::getDataTypeScalarSize(type);
627 		const int				integerLength	= getShaderUintBitCount(m_shaderType, precision);
628 		const deUint32			mask0			= getLowBitMask(integerLength);
629 
630 		for (int compNdx = 0; compNdx < scalarSize; compNdx++)
631 		{
632 			const deUint32	in0		= ((const deUint32*)inputs[0])[compNdx];
633 			const deUint32	in1		= ((const deUint32*)inputs[1])[compNdx];
634 			const deUint32	out0	= ((const deUint32*)outputs[0])[compNdx];
635 			const deUint32	out1	= ((const deUint32*)outputs[1])[compNdx];
636 			const deUint32	ref0	= in0-in1;
637 			const deUint32	ref1	= in0 >= in1 ? 0u : 1u;
638 
639 			if (((out0&mask0) != (ref0&mask0)) || out1 != ref1)
640 			{
641 				m_failMsg << "Expected [" << compNdx << "] = " << tcu::toHex(ref0) << ", " << tcu::toHex(ref1);
642 				return false;
643 			}
644 		}
645 
646 		return true;
647 	}
648 };
649 
650 class UsubBorrowCase : public IntegerFunctionCase
651 {
652 public:
UsubBorrowCase(tcu::TestContext & testCtx,glu::DataType baseType,glu::Precision precision,glu::ShaderType shaderType)653 	UsubBorrowCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
654 		: IntegerFunctionCase	(testCtx, getIntegerFuncCaseName(baseType, precision, shaderType).c_str(), "usubBorrow", shaderType)
655 	{
656 		m_spec.inputs.push_back(Symbol("x", glu::VarType(baseType, precision)));
657 		m_spec.inputs.push_back(Symbol("y", glu::VarType(baseType, precision)));
658 		m_spec.outputs.push_back(Symbol("diff", glu::VarType(baseType, precision)));
659 		m_spec.outputs.push_back(Symbol("carry", glu::VarType(baseType, glu::PRECISION_LOWP)));
660 		m_spec.source = "diff = usubBorrow(x, y, carry);";
661 	}
662 
createInstance(Context & ctx) const663 	TestInstance* createInstance (Context& ctx) const
664 	{
665 		return new UsubBorrowCaseInstance(ctx, m_shaderType, m_spec, m_numValues, getName());
666 	}
667 };
668 
669 class UmulExtendedCaseInstance : public IntegerFunctionTestInstance
670 {
671 public:
UmulExtendedCaseInstance(Context & context,glu::ShaderType shaderType,const ShaderSpec & spec,int numValues,const char * name)672 	UmulExtendedCaseInstance (Context& context, glu::ShaderType shaderType, const ShaderSpec& spec, int numValues, const char* name)
673 		: IntegerFunctionTestInstance	(context, shaderType, spec, numValues, name)
674 	{
675 	}
676 
getInputValues(int numValues,void * const * values) const677 	void getInputValues (int numValues, void* const* values) const
678 	{
679 		de::Random				rnd			(deStringHash(m_name) ^ 0x235facu);
680 		const glu::DataType		type		= m_spec.inputs[0].varType.getBasicType();
681 //		const glu::Precision	precision	= m_spec.inputs[0].varType.getPrecision();
682 		const int				scalarSize	= glu::getDataTypeScalarSize(type);
683 		deUint32*				in0			= (deUint32*)values[0];
684 		deUint32*				in1			= (deUint32*)values[1];
685 		int						valueNdx	= 0;
686 
687 		const struct
688 		{
689 			deUint32	x;
690 			deUint32	y;
691 		} easyCases[] =
692 		{
693 			{ 0x00000000u,	0x00000000u },
694 			{ 0xffffffffu,	0x00000001u },
695 			{ 0xffffffffu,	0x00000002u },
696 			{ 0x00000001u,	0xffffffffu },
697 			{ 0x00000002u,	0xffffffffu },
698 			{ 0xffffffffu,	0xffffffffu },
699 		};
700 
701 		for (int easyCaseNdx = 0; easyCaseNdx < DE_LENGTH_OF_ARRAY(easyCases); easyCaseNdx++)
702 		{
703 			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
704 			{
705 				in0[valueNdx*scalarSize + compNdx] = easyCases[easyCaseNdx].x;
706 				in1[valueNdx*scalarSize + compNdx] = easyCases[easyCaseNdx].y;
707 			}
708 
709 			valueNdx += 1;
710 		}
711 
712 		while (valueNdx < numValues)
713 		{
714 			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
715 			{
716 				const deUint32	base0	= rnd.getUint32();
717 				const deUint32	base1	= rnd.getUint32();
718 				const int		adj0	= rnd.getInt(0, 20);
719 				const int		adj1	= rnd.getInt(0, 20);
720 				in0[valueNdx*scalarSize + compNdx] = base0 >> adj0;
721 				in1[valueNdx*scalarSize + compNdx] = base1 >> adj1;
722 			}
723 
724 			valueNdx += 1;
725 		}
726 	}
727 
compare(const void * const * inputs,const void * const * outputs)728 	bool compare (const void* const* inputs, const void* const* outputs)
729 	{
730 		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
731 		const int				scalarSize		= glu::getDataTypeScalarSize(type);
732 
733 		for (int compNdx = 0; compNdx < scalarSize; compNdx++)
734 		{
735 			const deUint32	in0		= ((const deUint32*)inputs[0])[compNdx];
736 			const deUint32	in1		= ((const deUint32*)inputs[1])[compNdx];
737 			const deUint32	out0	= ((const deUint32*)outputs[0])[compNdx];
738 			const deUint32	out1	= ((const deUint32*)outputs[1])[compNdx];
739 			const deUint64	mul64	= deUint64(in0)*deUint64(in1);
740 			const deUint32	ref0	= deUint32(mul64 >> 32);
741 			const deUint32	ref1	= deUint32(mul64 & 0xffffffffu);
742 
743 			if (out0 != ref0 || out1 != ref1)
744 			{
745 				m_failMsg << "Expected [" << compNdx << "] = " << tcu::toHex(ref0) << ", " << tcu::toHex(ref1);
746 				return false;
747 			}
748 		}
749 
750 		return true;
751 	}
752 };
753 
754 class UmulExtendedCase : public IntegerFunctionCase
755 {
756 public:
UmulExtendedCase(tcu::TestContext & testCtx,glu::DataType baseType,glu::Precision precision,glu::ShaderType shaderType)757 	UmulExtendedCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
758 		: IntegerFunctionCase	(testCtx, getIntegerFuncCaseName(baseType, precision, shaderType).c_str(), "umulExtended", shaderType)
759 	{
760 		m_spec.inputs.push_back(Symbol("x", glu::VarType(baseType, precision)));
761 		m_spec.inputs.push_back(Symbol("y", glu::VarType(baseType, precision)));
762 		m_spec.outputs.push_back(Symbol("msb", glu::VarType(baseType, precision)));
763 		m_spec.outputs.push_back(Symbol("lsb", glu::VarType(baseType, precision)));
764 		m_spec.source = "umulExtended(x, y, msb, lsb);";
765 	}
766 
createInstance(Context & ctx) const767 	TestInstance* createInstance (Context& ctx) const
768 	{
769 		return new UmulExtendedCaseInstance(ctx, m_shaderType, m_spec, m_numValues, getName());
770 	}
771 };
772 
773 class ImulExtendedCaseInstance : public IntegerFunctionTestInstance
774 {
775 public:
ImulExtendedCaseInstance(Context & context,glu::ShaderType shaderType,const ShaderSpec & spec,int numValues,const char * name)776 	ImulExtendedCaseInstance (Context& context, glu::ShaderType shaderType, const ShaderSpec& spec, int numValues, const char* name)
777 		: IntegerFunctionTestInstance	(context, shaderType, spec, numValues, name)
778 	{
779 	}
780 
getInputValues(int numValues,void * const * values) const781 	void getInputValues (int numValues, void* const* values) const
782 	{
783 		de::Random				rnd			(deStringHash(m_name) ^ 0x224fa1u);
784 		const glu::DataType		type		= m_spec.inputs[0].varType.getBasicType();
785 //		const glu::Precision	precision	= m_spec.inputs[0].varType.getPrecision();
786 		const int				scalarSize	= glu::getDataTypeScalarSize(type);
787 		deUint32*				in0			= (deUint32*)values[0];
788 		deUint32*				in1			= (deUint32*)values[1];
789 		int						valueNdx	= 0;
790 
791 		const struct
792 		{
793 			deUint32	x;
794 			deUint32	y;
795 		} easyCases[] =
796 		{
797 			{ 0x00000000u,	0x00000000u },
798 			{ 0xffffffffu,	0x00000002u },
799 			{ 0x7fffffffu,	0x00000001u },
800 			{ 0x7fffffffu,	0x00000002u },
801 			{ 0x7fffffffu,	0x7fffffffu },
802 			{ 0xffffffffu,	0xffffffffu },
803 			{ 0x7fffffffu,	0xfffffffeu },
804 		};
805 
806 		for (int easyCaseNdx = 0; easyCaseNdx < DE_LENGTH_OF_ARRAY(easyCases); easyCaseNdx++)
807 		{
808 			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
809 			{
810 				in0[valueNdx*scalarSize + compNdx] = (deInt32)easyCases[easyCaseNdx].x;
811 				in1[valueNdx*scalarSize + compNdx] = (deInt32)easyCases[easyCaseNdx].y;
812 			}
813 
814 			valueNdx += 1;
815 		}
816 
817 		while (valueNdx < numValues)
818 		{
819 			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
820 			{
821 				const deInt32	base0	= (deInt32)rnd.getUint32();
822 				const deInt32	base1	= (deInt32)rnd.getUint32();
823 				const int		adj0	= rnd.getInt(0, 20);
824 				const int		adj1	= rnd.getInt(0, 20);
825 				in0[valueNdx*scalarSize + compNdx] = base0 >> adj0;
826 				in1[valueNdx*scalarSize + compNdx] = base1 >> adj1;
827 			}
828 
829 			valueNdx += 1;
830 		}
831 	}
832 
compare(const void * const * inputs,const void * const * outputs)833 	bool compare (const void* const* inputs, const void* const* outputs)
834 	{
835 		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
836 		const int				scalarSize		= glu::getDataTypeScalarSize(type);
837 
838 		for (int compNdx = 0; compNdx < scalarSize; compNdx++)
839 		{
840 			const deInt32	in0		= ((const deInt32*)inputs[0])[compNdx];
841 			const deInt32	in1		= ((const deInt32*)inputs[1])[compNdx];
842 			const deInt32	out0	= ((const deInt32*)outputs[0])[compNdx];
843 			const deInt32	out1	= ((const deInt32*)outputs[1])[compNdx];
844 			const deInt64	mul64	= deInt64(in0)*deInt64(in1);
845 			const deInt32	ref0	= deInt32(mul64 >> 32);
846 			const deInt32	ref1	= deInt32(mul64 & 0xffffffffu);
847 
848 			if (out0 != ref0 || out1 != ref1)
849 			{
850 				m_failMsg << "Expected [" << compNdx << "] = " << tcu::toHex(ref0) << ", " << tcu::toHex(ref1);
851 				return false;
852 			}
853 		}
854 
855 		return true;
856 	}
857 };
858 
859 class ImulExtendedCase : public IntegerFunctionCase
860 {
861 public:
ImulExtendedCase(tcu::TestContext & testCtx,glu::DataType baseType,glu::Precision precision,glu::ShaderType shaderType)862 	ImulExtendedCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
863 		: IntegerFunctionCase	(testCtx, getIntegerFuncCaseName(baseType, precision, shaderType).c_str(), "imulExtended", shaderType)
864 	{
865 		m_spec.inputs.push_back(Symbol("x", glu::VarType(baseType, precision)));
866 		m_spec.inputs.push_back(Symbol("y", glu::VarType(baseType, precision)));
867 		m_spec.outputs.push_back(Symbol("msb", glu::VarType(baseType, precision)));
868 		m_spec.outputs.push_back(Symbol("lsb", glu::VarType(baseType, precision)));
869 		m_spec.source = "imulExtended(x, y, msb, lsb);";
870 	}
871 
createInstance(Context & ctx) const872 	TestInstance* createInstance (Context& ctx) const
873 	{
874 		return new ImulExtendedCaseInstance(ctx, m_shaderType, m_spec, m_numValues, getName());
875 	}
876 };
877 
878 class BitfieldExtractCaseInstance : public IntegerFunctionTestInstance
879 {
880 public:
BitfieldExtractCaseInstance(Context & context,glu::ShaderType shaderType,const ShaderSpec & spec,int numValues,const char * name)881 	BitfieldExtractCaseInstance (Context& context, glu::ShaderType shaderType, const ShaderSpec& spec, int numValues, const char* name)
882 		: IntegerFunctionTestInstance	(context, shaderType, spec, numValues, name)
883 	{
884 	}
885 
getInputValues(int numValues,void * const * values) const886 	void getInputValues (int numValues, void* const* values) const
887 	{
888 		de::Random				rnd			(deStringHash(m_name) ^ 0xa113fca2u);
889 		const glu::DataType		type		= m_spec.inputs[0].varType.getBasicType();
890 		const glu::Precision	precision	= m_spec.inputs[0].varType.getPrecision();
891 		const bool				ignoreSign	= precision != glu::PRECISION_HIGHP && glu::isDataTypeIntOrIVec(type);
892 		const int				numBits		= getShaderUintBitCount(m_shaderType, precision) - (ignoreSign ? 1 : 0);
893 		deUint32*				inValue		= (deUint32*)values[0];
894 		int*					inOffset	= (int*)values[1];
895 		int*					inBits		= (int*)values[2];
896 
897 		for (int valueNdx = 0; valueNdx < numValues; ++valueNdx)
898 		{
899 			const int		bits	= rnd.getInt(0, numBits);
900 			const int		offset	= rnd.getInt(0, numBits-bits);
901 
902 			inOffset[valueNdx]	= offset;
903 			inBits[valueNdx]	= bits;
904 		}
905 
906 		generateRandomInputData(rnd, m_shaderType, type, precision, inValue, numValues);
907 	}
908 
compare(const void * const * inputs,const void * const * outputs)909 	bool compare (const void* const* inputs, const void* const* outputs)
910 	{
911 		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
912 		const bool				isSigned		= glu::isDataTypeIntOrIVec(type);
913 		const int				scalarSize		= glu::getDataTypeScalarSize(type);
914 		const int				offset			= *((const int*)inputs[1]);
915 		const int				bits			= *((const int*)inputs[2]);
916 
917 		for (int compNdx = 0; compNdx < scalarSize; compNdx++)
918 		{
919 			const deUint32	value	= ((const deUint32*)inputs[0])[compNdx];
920 			const deUint32	out		= ((const deUint32*)outputs[0])[compNdx];
921 			const deUint32	valMask	= (bits == 32 ? ~0u : ((1u<<bits)-1u));
922 			const deUint32	baseVal	= (offset == 32) ? (0) : ((value >> offset) & valMask);
923 			const deUint32	ref		= baseVal | ((isSigned && (baseVal & (1<<(bits-1)))) ? ~valMask : 0u);
924 
925 			if (out != ref)
926 			{
927 				m_failMsg << "Expected [" << compNdx << "] = " << tcu::toHex(ref);
928 				return false;
929 			}
930 		}
931 
932 		return true;
933 	}
934 };
935 
936 class BitfieldExtractCase : public IntegerFunctionCase
937 {
938 public:
BitfieldExtractCase(tcu::TestContext & testCtx,glu::DataType baseType,glu::Precision precision,glu::ShaderType shaderType)939 	BitfieldExtractCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
940 		: IntegerFunctionCase	(testCtx, getIntegerFuncCaseName(baseType, precision, shaderType).c_str(), "bitfieldExtract", shaderType)
941 	{
942 		m_spec.inputs.push_back(Symbol("value", glu::VarType(baseType, precision)));
943 		m_spec.inputs.push_back(Symbol("offset", glu::VarType(glu::TYPE_INT, precision)));
944 		m_spec.inputs.push_back(Symbol("bits", glu::VarType(glu::TYPE_INT, precision)));
945 		m_spec.outputs.push_back(Symbol("extracted", glu::VarType(baseType, precision)));
946 		m_spec.source = "extracted = bitfieldExtract(value, offset, bits);";
947 	}
948 
createInstance(Context & ctx) const949 	TestInstance* createInstance (Context& ctx) const
950 	{
951 		return new BitfieldExtractCaseInstance(ctx, m_shaderType, m_spec, m_numValues, getName());
952 	}
953 };
954 
955 class BitfieldInsertCaseInstance : public IntegerFunctionTestInstance
956 {
957 public:
BitfieldInsertCaseInstance(Context & context,glu::ShaderType shaderType,const ShaderSpec & spec,int numValues,const char * name)958 	BitfieldInsertCaseInstance (Context& context, glu::ShaderType shaderType, const ShaderSpec& spec, int numValues, const char* name)
959 		: IntegerFunctionTestInstance	(context, shaderType, spec, numValues, name)
960 	{
961 	}
962 
getInputValues(int numValues,void * const * values) const963 	void getInputValues (int numValues, void* const* values) const
964 	{
965 		de::Random				rnd			(deStringHash(m_name) ^ 0x12c2acff);
966 		const glu::DataType		type		= m_spec.inputs[0].varType.getBasicType();
967 		const glu::Precision	precision	= m_spec.inputs[0].varType.getPrecision();
968 		const int				numBits		= getShaderUintBitCount(m_shaderType, precision);
969 		deUint32*				inBase		= (deUint32*)values[0];
970 		deUint32*				inInsert	= (deUint32*)values[1];
971 		int*					inOffset	= (int*)values[2];
972 		int*					inBits		= (int*)values[3];
973 
974 		for (int valueNdx = 0; valueNdx < numValues; ++valueNdx)
975 		{
976 			const int bits		= rnd.getInt(0, numBits);
977 			const int offset	= rnd.getInt(0, numBits-bits);
978 
979 			inOffset[valueNdx]	= offset;
980 			inBits[valueNdx]	= bits;
981 		}
982 
983 		generateRandomInputData(rnd, m_shaderType, type, precision, inBase, numValues);
984 		generateRandomInputData(rnd, m_shaderType, type, precision, inInsert, numValues);
985 	}
986 
compare(const void * const * inputs,const void * const * outputs)987 	bool compare (const void* const* inputs, const void* const* outputs)
988 	{
989 		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
990 		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
991 		const int				scalarSize		= glu::getDataTypeScalarSize(type);
992 		const int				integerLength	= getShaderUintBitCount(m_shaderType, precision);
993 		const deUint32			cmpMask			= getLowBitMask(integerLength);
994 		const int				offset			= *((const int*)inputs[2]);
995 		const int				bits			= *((const int*)inputs[3]);
996 
997 		for (int compNdx = 0; compNdx < scalarSize; compNdx++)
998 		{
999 			const deUint32	base	= ((const deUint32*)inputs[0])[compNdx];
1000 			const deUint32	insert	= ((const deUint32*)inputs[1])[compNdx];
1001 			const deInt32	out		= ((const deUint32*)outputs[0])[compNdx];
1002 
1003 			const deUint32	mask	= bits == 32 ? ~0u : (1u<<bits)-1;
1004 			const deUint32	ref		= (base & ~(mask<<offset)) | ((insert & mask)<<offset);
1005 
1006 			if ((out&cmpMask) != (ref&cmpMask))
1007 			{
1008 				m_failMsg << "Expected [" << compNdx << "] = " << tcu::toHex(ref);
1009 				return false;
1010 			}
1011 		}
1012 
1013 		return true;
1014 	}
1015 };
1016 
1017 class BitfieldInsertCase : public IntegerFunctionCase
1018 {
1019 public:
BitfieldInsertCase(tcu::TestContext & testCtx,glu::DataType baseType,glu::Precision precision,glu::ShaderType shaderType)1020 	BitfieldInsertCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
1021 		: IntegerFunctionCase	(testCtx, getIntegerFuncCaseName(baseType, precision, shaderType).c_str(), "bitfieldInsert", shaderType)
1022 	{
1023 		m_spec.inputs.push_back(Symbol("base", glu::VarType(baseType, precision)));
1024 		m_spec.inputs.push_back(Symbol("insert", glu::VarType(baseType, precision)));
1025 		m_spec.inputs.push_back(Symbol("offset", glu::VarType(glu::TYPE_INT, precision)));
1026 		m_spec.inputs.push_back(Symbol("bits", glu::VarType(glu::TYPE_INT, precision)));
1027 		m_spec.outputs.push_back(Symbol("result", glu::VarType(baseType, precision)));
1028 		m_spec.source = "result = bitfieldInsert(base, insert, offset, bits);";
1029 	}
1030 
createInstance(Context & ctx) const1031 	TestInstance* createInstance (Context& ctx) const
1032 	{
1033 		return new BitfieldInsertCaseInstance(ctx, m_shaderType, m_spec, m_numValues, getName());
1034 	}
1035 };
1036 
1037 class BitfieldReverseCaseInstance : public IntegerFunctionTestInstance
1038 {
1039 public:
BitfieldReverseCaseInstance(Context & context,glu::ShaderType shaderType,const ShaderSpec & spec,int numValues,const char * name)1040 	BitfieldReverseCaseInstance (Context& context, glu::ShaderType shaderType, const ShaderSpec& spec, int numValues, const char* name)
1041 		: IntegerFunctionTestInstance	(context, shaderType, spec, numValues, name)
1042 	{
1043 	}
1044 
getInputValues(int numValues,void * const * values) const1045 	void getInputValues (int numValues, void* const* values) const
1046 	{
1047 		de::Random				rnd			(deStringHash(m_name) ^ 0xff23a4);
1048 		const glu::DataType		type		= m_spec.inputs[0].varType.getBasicType();
1049 		const glu::Precision	precision	= m_spec.inputs[0].varType.getPrecision();
1050 		deUint32*				inValue		= (deUint32*)values[0];
1051 
1052 		generateRandomInputData(rnd, m_shaderType, type, precision, inValue, numValues);
1053 	}
1054 
compare(const void * const * inputs,const void * const * outputs)1055 	bool compare (const void* const* inputs, const void* const* outputs)
1056 	{
1057 		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
1058 		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
1059 		const int				integerLength	= getShaderUintBitCount(m_shaderType, precision);
1060 		const int				scalarSize		= glu::getDataTypeScalarSize(type);
1061 		const deUint32			cmpMask			= reverseBits(getLowBitMask(integerLength));
1062 
1063 		for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1064 		{
1065 			const deUint32	value	= ((const deUint32*)inputs[0])[compNdx];
1066 			const deInt32	out		= ((const deUint32*)outputs[0])[compNdx];
1067 			const deUint32	ref		= reverseBits(value);
1068 
1069 			if ((out&cmpMask) != (ref&cmpMask))
1070 			{
1071 				m_failMsg << "Expected [" << compNdx << "] = " << tcu::toHex(ref);
1072 				return false;
1073 			}
1074 		}
1075 
1076 		return true;
1077 	}
1078 };
1079 
1080 class BitfieldReverseCase : public IntegerFunctionCase
1081 {
1082 public:
BitfieldReverseCase(tcu::TestContext & testCtx,glu::DataType baseType,glu::Precision precision,glu::ShaderType shaderType)1083 	BitfieldReverseCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
1084 		: IntegerFunctionCase	(testCtx, getIntegerFuncCaseName(baseType, precision, shaderType).c_str(), "bitfieldReverse", shaderType)
1085 	{
1086 		m_spec.inputs.push_back(Symbol("value", glu::VarType(baseType, precision)));
1087 		m_spec.outputs.push_back(Symbol("result", glu::VarType(baseType, glu::PRECISION_HIGHP)));
1088 		m_spec.source = "result = bitfieldReverse(value);";
1089 	}
1090 
createInstance(Context & ctx) const1091 	TestInstance* createInstance (Context& ctx) const
1092 	{
1093 		return new BitfieldReverseCaseInstance(ctx, m_shaderType, m_spec, m_numValues, getName());
1094 	}
1095 };
1096 
1097 class BitCountCaseInstance : public IntegerFunctionTestInstance
1098 {
1099 public:
BitCountCaseInstance(Context & context,glu::ShaderType shaderType,const ShaderSpec & spec,int numValues,const char * name)1100 	BitCountCaseInstance (Context& context, glu::ShaderType shaderType, const ShaderSpec& spec, int numValues, const char* name)
1101 		: IntegerFunctionTestInstance	(context, shaderType, spec, numValues, name)
1102 	{
1103 	}
1104 
getInputValues(int numValues,void * const * values) const1105 	void getInputValues (int numValues, void* const* values) const
1106 	{
1107 		de::Random				rnd			(deStringHash(m_name) ^ 0xab2cca4);
1108 		const glu::DataType		type		= m_spec.inputs[0].varType.getBasicType();
1109 		const glu::Precision	precision	= m_spec.inputs[0].varType.getPrecision();
1110 		deUint32*				inValue		= (deUint32*)values[0];
1111 
1112 		generateRandomInputData(rnd, m_shaderType, type, precision, inValue, numValues);
1113 	}
1114 
compare(const void * const * inputs,const void * const * outputs)1115 	bool compare (const void* const* inputs, const void* const* outputs)
1116 	{
1117 		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
1118 		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
1119 		const int				integerLength	= getShaderUintBitCount(m_shaderType, precision);
1120 		const int				scalarSize		= glu::getDataTypeScalarSize(type);
1121 		const deUint32			countMask		= getLowBitMask(integerLength);
1122 
1123 		for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1124 		{
1125 			const deUint32	value	= ((const deUint32*)inputs[0])[compNdx];
1126 			const int		out		= ((const int*)outputs[0])[compNdx];
1127 			const int		minRef	= dePop32(value&countMask);
1128 			const int		maxRef	= dePop32(value);
1129 
1130 			if (!de::inRange(out, minRef, maxRef))
1131 			{
1132 				m_failMsg << "Expected [" << compNdx << "] in range [" << minRef << ", " << maxRef << "]";
1133 				return false;
1134 			}
1135 		}
1136 
1137 		return true;
1138 	}
1139 };
1140 
1141 class BitCountCase : public IntegerFunctionCase
1142 {
1143 public:
BitCountCase(tcu::TestContext & testCtx,glu::DataType baseType,glu::Precision precision,glu::ShaderType shaderType)1144 	BitCountCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
1145 		: IntegerFunctionCase	(testCtx, getIntegerFuncCaseName(baseType, precision, shaderType).c_str(), "bitCount", shaderType)
1146 	{
1147 		const int			vecSize		= glu::getDataTypeScalarSize(baseType);
1148 		const glu::DataType	intType		= vecSize == 1 ? glu::TYPE_INT : glu::getDataTypeIntVec(vecSize);
1149 
1150 		m_spec.inputs.push_back(Symbol("value", glu::VarType(baseType, precision)));
1151 		m_spec.outputs.push_back(Symbol("count", glu::VarType(intType, glu::PRECISION_MEDIUMP)));
1152 		m_spec.source = "count = bitCount(value);";
1153 	}
1154 
createInstance(Context & ctx) const1155 	TestInstance* createInstance (Context& ctx) const
1156 	{
1157 		return new BitCountCaseInstance(ctx, m_shaderType, m_spec, m_numValues, getName());
1158 	}
1159 };
1160 
1161 class FindLSBCaseInstance : public IntegerFunctionTestInstance
1162 {
1163 public:
FindLSBCaseInstance(Context & context,glu::ShaderType shaderType,const ShaderSpec & spec,int numValues,const char * name)1164 	FindLSBCaseInstance (Context& context, glu::ShaderType shaderType, const ShaderSpec& spec, int numValues, const char* name)
1165 		: IntegerFunctionTestInstance	(context, shaderType, spec, numValues, name)
1166 	{
1167 	}
1168 
getInputValues(int numValues,void * const * values) const1169 	void getInputValues (int numValues, void* const* values) const
1170 	{
1171 		de::Random				rnd			(deStringHash(m_name) ^ 0x9923c2af);
1172 		const glu::DataType		type		= m_spec.inputs[0].varType.getBasicType();
1173 		const glu::Precision	precision	= m_spec.inputs[0].varType.getPrecision();
1174 		deUint32*				inValue		= (deUint32*)values[0];
1175 
1176 		generateRandomInputData(rnd, m_shaderType, type, precision, inValue, numValues);
1177 	}
1178 
compare(const void * const * inputs,const void * const * outputs)1179 	bool compare (const void* const* inputs, const void* const* outputs)
1180 	{
1181 		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
1182 		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
1183 		const int				scalarSize		= glu::getDataTypeScalarSize(type);
1184 		const int				integerLength	= getShaderUintBitCount(m_shaderType, precision);
1185 		const deUint32			mask			= getLowBitMask(integerLength);
1186 
1187 		for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1188 		{
1189 			const deUint32	value	= ((const deUint32*)inputs[0])[compNdx];
1190 			const int		out		= ((const int*)outputs[0])[compNdx];
1191 			const int		minRef	= findLSB(value&mask);
1192 			const int		maxRef	= findLSB(value);
1193 
1194 			if (!de::inRange(out, minRef, maxRef))
1195 			{
1196 				m_failMsg << "Expected [" << compNdx << "] in range [" << minRef << ", " << maxRef << "]";
1197 				return false;
1198 			}
1199 		}
1200 
1201 		return true;
1202 	}
1203 };
1204 
1205 class FindLSBCase : public IntegerFunctionCase
1206 {
1207 public:
FindLSBCase(tcu::TestContext & testCtx,glu::DataType baseType,glu::Precision precision,glu::ShaderType shaderType)1208 	FindLSBCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
1209 		: IntegerFunctionCase	(testCtx, getIntegerFuncCaseName(baseType, precision, shaderType).c_str(), "findLSB", shaderType)
1210 	{
1211 		const int			vecSize		= glu::getDataTypeScalarSize(baseType);
1212 		const glu::DataType	intType		= vecSize == 1 ? glu::TYPE_INT : glu::getDataTypeIntVec(vecSize);
1213 
1214 		m_spec.inputs.push_back(Symbol("value", glu::VarType(baseType, precision)));
1215 		m_spec.outputs.push_back(Symbol("lsb", glu::VarType(intType, glu::PRECISION_LOWP)));
1216 		m_spec.source = "lsb = findLSB(value);";
1217 	}
1218 
createInstance(Context & ctx) const1219 	TestInstance* createInstance (Context& ctx) const
1220 	{
1221 		return new FindLSBCaseInstance(ctx, m_shaderType, m_spec, m_numValues, getName());
1222 	}
1223 };
1224 
1225 class findMSBCaseInstance : public IntegerFunctionTestInstance
1226 {
1227 public:
findMSBCaseInstance(Context & context,glu::ShaderType shaderType,const ShaderSpec & spec,int numValues,const char * name)1228 	findMSBCaseInstance (Context& context, glu::ShaderType shaderType, const ShaderSpec& spec, int numValues, const char* name)
1229 		: IntegerFunctionTestInstance	(context, shaderType, spec, numValues, name)
1230 	{
1231 	}
1232 
getInputValues(int numValues,void * const * values) const1233 	void getInputValues (int numValues, void* const* values) const
1234 	{
1235 		de::Random				rnd			(deStringHash(m_name) ^ 0x742ac4e);
1236 		const glu::DataType		type		= m_spec.inputs[0].varType.getBasicType();
1237 		const glu::Precision	precision	= m_spec.inputs[0].varType.getPrecision();
1238 		deUint32*				inValue		= (deUint32*)values[0];
1239 
1240 		generateRandomInputData(rnd, m_shaderType, type, precision, inValue, numValues);
1241 	}
1242 
compare(const void * const * inputs,const void * const * outputs)1243 	bool compare (const void* const* inputs, const void* const* outputs)
1244 	{
1245 		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
1246 		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
1247 		const bool				isSigned		= glu::isDataTypeIntOrIVec(type);
1248 		const int				scalarSize		= glu::getDataTypeScalarSize(type);
1249 		const int				integerLength	= getShaderUintBitCount(m_shaderType, precision);
1250 
1251 		for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1252 		{
1253 			const deUint32	value	= ((const deUint32*)inputs[0])[compNdx];
1254 			const int		out		= ((const deInt32*)outputs[0])[compNdx];
1255 			const int		minRef	= isSigned ? findMSB(toPrecision(deInt32(value), integerLength))	: findMSB(toPrecision(value, integerLength));
1256 			const int		maxRef	= isSigned ? findMSB(deInt32(value))								: findMSB(value);
1257 
1258 			if (!de::inRange(out, minRef, maxRef))
1259 			{
1260 				m_failMsg << "Expected [" << compNdx << "] in range [" << minRef << ", " << maxRef << "]";
1261 				return false;
1262 			}
1263 		}
1264 
1265 		return true;
1266 	}
1267 };
1268 
1269 class findMSBCase : public IntegerFunctionCase
1270 {
1271 public:
findMSBCase(tcu::TestContext & testCtx,glu::DataType baseType,glu::Precision precision,glu::ShaderType shaderType)1272 	findMSBCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
1273 		: IntegerFunctionCase	(testCtx, getIntegerFuncCaseName(baseType, precision, shaderType).c_str(), "findMSB", shaderType)
1274 	{
1275 		const int			vecSize		= glu::getDataTypeScalarSize(baseType);
1276 		const glu::DataType	intType		= vecSize == 1 ? glu::TYPE_INT : glu::getDataTypeIntVec(vecSize);
1277 
1278 		m_spec.inputs.push_back(Symbol("value", glu::VarType(baseType, precision)));
1279 		m_spec.outputs.push_back(Symbol("msb", glu::VarType(intType, glu::PRECISION_LOWP)));
1280 		m_spec.source = "msb = findMSB(value);";
1281 	}
1282 
createInstance(Context & ctx) const1283 	TestInstance* createInstance (Context& ctx) const
1284 	{
1285 		return new findMSBCaseInstance(ctx, m_shaderType, m_spec, m_numValues, getName());
1286 	}
1287 };
1288 
ShaderIntegerFunctionTests(tcu::TestContext & testCtx)1289 ShaderIntegerFunctionTests::ShaderIntegerFunctionTests (tcu::TestContext& testCtx)
1290 	: tcu::TestCaseGroup	(testCtx, "integer", "Integer function tests")
1291 {
1292 }
1293 
~ShaderIntegerFunctionTests(void)1294 ShaderIntegerFunctionTests::~ShaderIntegerFunctionTests (void)
1295 {
1296 }
1297 
init(void)1298 void ShaderIntegerFunctionTests::init (void)
1299 {
1300 	enum
1301 	{
1302 		VS = (1<<glu::SHADERTYPE_VERTEX),
1303 		FS = (1<<glu::SHADERTYPE_FRAGMENT),
1304 		CS = (1<<glu::SHADERTYPE_COMPUTE),
1305 		GS = (1<<glu::SHADERTYPE_GEOMETRY),
1306 		TC = (1<<glu::SHADERTYPE_TESSELLATION_CONTROL),
1307 		TE = (1<<glu::SHADERTYPE_TESSELLATION_EVALUATION),
1308 
1309 		ALL_SHADERS = VS|TC|TE|GS|FS|CS
1310 	};
1311 
1312 	//																		Int?	Uint?	AllPrec?	Shaders
1313 	addFunctionCases<UaddCarryCase>				(this,	"uaddcarry",		false,	true,	true,		ALL_SHADERS);
1314 	addFunctionCases<UsubBorrowCase>			(this,	"usubborrow",		false,	true,	true,		ALL_SHADERS);
1315 	addFunctionCases<UmulExtendedCase>			(this,	"umulextended",		false,	true,	false,		ALL_SHADERS);
1316 	addFunctionCases<ImulExtendedCase>			(this,	"imulextended",		true,	false,	false,		ALL_SHADERS);
1317 	addFunctionCases<BitfieldExtractCase>		(this,	"bitfieldextract",	true,	true,	true,		ALL_SHADERS);
1318 	addFunctionCases<BitfieldInsertCase>		(this,	"bitfieldinsert",	true,	true,	true,		ALL_SHADERS);
1319 	addFunctionCases<BitfieldReverseCase>		(this,	"bitfieldreverse",	true,	true,	true,		ALL_SHADERS);
1320 	addFunctionCases<BitCountCase>				(this,	"bitcount",			true,	true,	true,		ALL_SHADERS);
1321 	addFunctionCases<FindLSBCase>				(this,	"findlsb",			true,	true,	true,		ALL_SHADERS);
1322 	addFunctionCases<findMSBCase>				(this,	"findMSB",			true,	true,	true,		ALL_SHADERS);
1323 }
1324 
1325 } // shaderexecutor
1326 } // vkt
1327