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