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