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::__anon1045e4440111::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::__anon1045e4440111::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::getContextTypeGLSLVersion(context.getRenderContext().getType());
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 
getIntegerFuncCaseName(glu::DataType baseType,glu::Precision precision,glu::ShaderType shaderType)322 static std::string getIntegerFuncCaseName (glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
323 {
324 	return string(glu::getDataTypeName(baseType)) + getPrecisionPostfix(precision) + getShaderTypePostfix(shaderType);
325 }
326 
327 class UaddCarryCase : public IntegerFunctionCase
328 {
329 public:
UaddCarryCase(Context & context,glu::DataType baseType,glu::Precision precision,glu::ShaderType shaderType)330 	UaddCarryCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
331 		: IntegerFunctionCase(context, getIntegerFuncCaseName(baseType, precision, shaderType).c_str(), "uaddCarry", shaderType)
332 	{
333 		m_spec.inputs.push_back(Symbol("x", glu::VarType(baseType, precision)));
334 		m_spec.inputs.push_back(Symbol("y", glu::VarType(baseType, precision)));
335 		m_spec.outputs.push_back(Symbol("sum", glu::VarType(baseType, precision)));
336 		m_spec.outputs.push_back(Symbol("carry", glu::VarType(baseType, glu::PRECISION_LOWP)));
337 		m_spec.source = "sum = uaddCarry(x, y, carry);";
338 	}
339 
getInputValues(int numValues,void * const * values) const340 	void getInputValues (int numValues, void* const* values) const
341 	{
342 		de::Random				rnd				(deStringHash(getName()) ^ 0x235facu);
343 		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
344 		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
345 		const int				scalarSize		= glu::getDataTypeScalarSize(type);
346 		const int				integerLength	= getShaderUintBitCount(m_shaderType, precision);
347 		const deUint32			integerMask		= getLowBitMask(integerLength);
348 		const bool				isSigned		= glu::isDataTypeIntOrIVec(type);
349 		deUint32*				in0				= (deUint32*)values[0];
350 		deUint32*				in1				= (deUint32*)values[1];
351 
352 		const struct
353 		{
354 			deUint32	x;
355 			deUint32	y;
356 		} easyCases[] =
357 		{
358 			{ 0x00000000u,	0x00000000u },
359 			{ 0xfffffffeu,	0x00000001u },
360 			{ 0x00000001u,	0xfffffffeu },
361 			{ 0xffffffffu,	0x00000001u },
362 			{ 0x00000001u,	0xffffffffu },
363 			{ 0xfffffffeu,	0x00000002u },
364 			{ 0x00000002u,	0xfffffffeu },
365 			{ 0xffffffffu,	0xffffffffu }
366 		};
367 
368 		// generate integers with proper bit count
369 		for (int easyCaseNdx = 0; easyCaseNdx < DE_LENGTH_OF_ARRAY(easyCases); easyCaseNdx++)
370 		{
371 			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
372 			{
373 				in0[easyCaseNdx*scalarSize + compNdx] = easyCases[easyCaseNdx].x & integerMask;
374 				in1[easyCaseNdx*scalarSize + compNdx] = easyCases[easyCaseNdx].y & integerMask;
375 			}
376 		}
377 
378 		// convert to signed
379 		if (isSigned)
380 		{
381 			for (int easyCaseNdx = 0; easyCaseNdx < DE_LENGTH_OF_ARRAY(easyCases); easyCaseNdx++)
382 			{
383 				for (int compNdx = 0; compNdx < scalarSize; compNdx++)
384 				{
385 					in0[easyCaseNdx*scalarSize + compNdx] = extendSignTo32(in0[easyCaseNdx*scalarSize + compNdx], integerLength);
386 					in1[easyCaseNdx*scalarSize + compNdx] = extendSignTo32(in1[easyCaseNdx*scalarSize + compNdx], integerLength);
387 				}
388 			}
389 		}
390 
391 		generateRandomInputData(rnd, m_shaderType, type, precision, in0, numValues - DE_LENGTH_OF_ARRAY(easyCases));
392 		generateRandomInputData(rnd, m_shaderType, type, precision, in1, numValues - DE_LENGTH_OF_ARRAY(easyCases));
393 	}
394 
compare(const void * const * inputs,const void * const * outputs)395 	bool compare (const void* const* inputs, const void* const* outputs)
396 	{
397 		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
398 		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
399 		const int				scalarSize		= glu::getDataTypeScalarSize(type);
400 		const int				integerLength	= getShaderUintBitCount(m_shaderType, precision);
401 		const deUint32			mask0			= getLowBitMask(integerLength);
402 
403 		for (int compNdx = 0; compNdx < scalarSize; compNdx++)
404 		{
405 			const deUint32	in0		= ((const deUint32*)inputs[0])[compNdx];
406 			const deUint32	in1		= ((const deUint32*)inputs[1])[compNdx];
407 			const deUint32	out0	= ((const deUint32*)outputs[0])[compNdx];
408 			const deUint32	out1	= ((const deUint32*)outputs[1])[compNdx];
409 			const deUint32	ref0	= in0+in1;
410 			const deUint32	ref1	= (deUint64(in0)+deUint64(in1)) > 0xffffffffu ? 1u : 0u;
411 
412 			if (((out0&mask0) != (ref0&mask0)) || out1 != ref1)
413 			{
414 				m_failMsg << "Expected [" << compNdx << "] = " << tcu::toHex(ref0) << ", " << tcu::toHex(ref1);
415 				return false;
416 			}
417 		}
418 
419 		return true;
420 	}
421 };
422 
423 class UsubBorrowCase : public IntegerFunctionCase
424 {
425 public:
UsubBorrowCase(Context & context,glu::DataType baseType,glu::Precision precision,glu::ShaderType shaderType)426 	UsubBorrowCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
427 		: IntegerFunctionCase(context, getIntegerFuncCaseName(baseType, precision, shaderType).c_str(), "usubBorrow", shaderType)
428 	{
429 		m_spec.inputs.push_back(Symbol("x", glu::VarType(baseType, precision)));
430 		m_spec.inputs.push_back(Symbol("y", glu::VarType(baseType, precision)));
431 		m_spec.outputs.push_back(Symbol("diff", glu::VarType(baseType, precision)));
432 		m_spec.outputs.push_back(Symbol("carry", glu::VarType(baseType, glu::PRECISION_LOWP)));
433 		m_spec.source = "diff = usubBorrow(x, y, carry);";
434 	}
435 
getInputValues(int numValues,void * const * values) const436 	void getInputValues (int numValues, void* const* values) const
437 	{
438 		de::Random				rnd				(deStringHash(getName()) ^ 0x235facu);
439 		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
440 		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
441 		const int				scalarSize		= glu::getDataTypeScalarSize(type);
442 		const int				integerLength	= getShaderUintBitCount(m_shaderType, precision);
443 		const deUint32			integerMask		= getLowBitMask(integerLength);
444 		const bool				isSigned		= glu::isDataTypeIntOrIVec(type);
445 		deUint32*				in0				= (deUint32*)values[0];
446 		deUint32*				in1				= (deUint32*)values[1];
447 
448 		const struct
449 		{
450 			deUint32	x;
451 			deUint32	y;
452 		} easyCases[] =
453 		{
454 			{ 0x00000000u,	0x00000000u },
455 			{ 0x00000001u,	0x00000001u },
456 			{ 0x00000001u,	0x00000002u },
457 			{ 0x00000001u,	0xffffffffu },
458 			{ 0xfffffffeu,	0xffffffffu },
459 			{ 0xffffffffu,	0xffffffffu },
460 		};
461 
462 		// generate integers with proper bit count
463 		for (int easyCaseNdx = 0; easyCaseNdx < DE_LENGTH_OF_ARRAY(easyCases); easyCaseNdx++)
464 		{
465 			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
466 			{
467 				in0[easyCaseNdx*scalarSize + compNdx] = easyCases[easyCaseNdx].x & integerMask;
468 				in1[easyCaseNdx*scalarSize + compNdx] = easyCases[easyCaseNdx].y & integerMask;
469 			}
470 		}
471 
472 		// convert to signed
473 		if (isSigned)
474 		{
475 			for (int easyCaseNdx = 0; easyCaseNdx < DE_LENGTH_OF_ARRAY(easyCases); easyCaseNdx++)
476 			{
477 				for (int compNdx = 0; compNdx < scalarSize; compNdx++)
478 				{
479 					in0[easyCaseNdx*scalarSize + compNdx] = extendSignTo32(in0[easyCaseNdx*scalarSize + compNdx], integerLength);
480 					in1[easyCaseNdx*scalarSize + compNdx] = extendSignTo32(in1[easyCaseNdx*scalarSize + compNdx], integerLength);
481 				}
482 			}
483 		}
484 
485 		generateRandomInputData(rnd, m_shaderType, type, precision, in0, numValues - DE_LENGTH_OF_ARRAY(easyCases));
486 		generateRandomInputData(rnd, m_shaderType, type, precision, in1, numValues - DE_LENGTH_OF_ARRAY(easyCases));
487 	}
488 
compare(const void * const * inputs,const void * const * outputs)489 	bool compare (const void* const* inputs, const void* const* outputs)
490 	{
491 		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
492 		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
493 		const int				scalarSize		= glu::getDataTypeScalarSize(type);
494 		const int				integerLength	= getShaderUintBitCount(m_shaderType, precision);
495 		const deUint32			mask0			= getLowBitMask(integerLength);
496 
497 		for (int compNdx = 0; compNdx < scalarSize; compNdx++)
498 		{
499 			const deUint32	in0		= ((const deUint32*)inputs[0])[compNdx];
500 			const deUint32	in1		= ((const deUint32*)inputs[1])[compNdx];
501 			const deUint32	out0	= ((const deUint32*)outputs[0])[compNdx];
502 			const deUint32	out1	= ((const deUint32*)outputs[1])[compNdx];
503 			const deUint32	ref0	= in0-in1;
504 			const deUint32	ref1	= in0 >= in1 ? 0u : 1u;
505 
506 			if (((out0&mask0) != (ref0&mask0)) || out1 != ref1)
507 			{
508 				m_failMsg << "Expected [" << compNdx << "] = " << tcu::toHex(ref0) << ", " << tcu::toHex(ref1);
509 				return false;
510 			}
511 		}
512 
513 		return true;
514 	}
515 };
516 
517 class UmulExtendedCase : public IntegerFunctionCase
518 {
519 public:
UmulExtendedCase(Context & context,glu::DataType baseType,glu::Precision precision,glu::ShaderType shaderType)520 	UmulExtendedCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
521 		: IntegerFunctionCase(context, getIntegerFuncCaseName(baseType, precision, shaderType).c_str(), "umulExtended", shaderType)
522 	{
523 		m_spec.inputs.push_back(Symbol("x", glu::VarType(baseType, precision)));
524 		m_spec.inputs.push_back(Symbol("y", glu::VarType(baseType, precision)));
525 		m_spec.outputs.push_back(Symbol("msb", glu::VarType(baseType, precision)));
526 		m_spec.outputs.push_back(Symbol("lsb", glu::VarType(baseType, precision)));
527 		m_spec.source = "umulExtended(x, y, msb, lsb);";
528 	}
529 
getInputValues(int numValues,void * const * values) const530 	void getInputValues (int numValues, void* const* values) const
531 	{
532 		de::Random				rnd			(deStringHash(getName()) ^ 0x235facu);
533 		const glu::DataType		type		= m_spec.inputs[0].varType.getBasicType();
534 //		const glu::Precision	precision	= m_spec.inputs[0].varType.getPrecision();
535 		const int				scalarSize	= glu::getDataTypeScalarSize(type);
536 		deUint32*				in0			= (deUint32*)values[0];
537 		deUint32*				in1			= (deUint32*)values[1];
538 		int						valueNdx	= 0;
539 
540 		const struct
541 		{
542 			deUint32	x;
543 			deUint32	y;
544 		} easyCases[] =
545 		{
546 			{ 0x00000000u,	0x00000000u },
547 			{ 0xffffffffu,	0x00000001u },
548 			{ 0xffffffffu,	0x00000002u },
549 			{ 0x00000001u,	0xffffffffu },
550 			{ 0x00000002u,	0xffffffffu },
551 			{ 0xffffffffu,	0xffffffffu },
552 		};
553 
554 		for (int easyCaseNdx = 0; easyCaseNdx < DE_LENGTH_OF_ARRAY(easyCases); easyCaseNdx++)
555 		{
556 			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
557 			{
558 				in0[valueNdx*scalarSize + compNdx] = easyCases[easyCaseNdx].x;
559 				in1[valueNdx*scalarSize + compNdx] = easyCases[easyCaseNdx].y;
560 			}
561 
562 			valueNdx += 1;
563 		}
564 
565 		while (valueNdx < numValues)
566 		{
567 			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
568 			{
569 				const deUint32	base0	= rnd.getUint32();
570 				const deUint32	base1	= rnd.getUint32();
571 				const int		adj0	= rnd.getInt(0, 20);
572 				const int		adj1	= rnd.getInt(0, 20);
573 				in0[valueNdx*scalarSize + compNdx] = base0 >> adj0;
574 				in1[valueNdx*scalarSize + compNdx] = base1 >> adj1;
575 			}
576 
577 			valueNdx += 1;
578 		}
579 	}
580 
compare(const void * const * inputs,const void * const * outputs)581 	bool compare (const void* const* inputs, const void* const* outputs)
582 	{
583 		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
584 		const int				scalarSize		= glu::getDataTypeScalarSize(type);
585 
586 		for (int compNdx = 0; compNdx < scalarSize; compNdx++)
587 		{
588 			const deUint32	in0		= ((const deUint32*)inputs[0])[compNdx];
589 			const deUint32	in1		= ((const deUint32*)inputs[1])[compNdx];
590 			const deUint32	out0	= ((const deUint32*)outputs[0])[compNdx];
591 			const deUint32	out1	= ((const deUint32*)outputs[1])[compNdx];
592 			const deUint64	mul64	= deUint64(in0)*deUint64(in1);
593 			const deUint32	ref0	= deUint32(mul64 >> 32);
594 			const deUint32	ref1	= deUint32(mul64 & 0xffffffffu);
595 
596 			if (out0 != ref0 || out1 != ref1)
597 			{
598 				m_failMsg << "Expected [" << compNdx << "] = " << tcu::toHex(ref0) << ", " << tcu::toHex(ref1);
599 				return false;
600 			}
601 		}
602 
603 		return true;
604 	}
605 };
606 
607 class ImulExtendedCase : public IntegerFunctionCase
608 {
609 public:
ImulExtendedCase(Context & context,glu::DataType baseType,glu::Precision precision,glu::ShaderType shaderType)610 	ImulExtendedCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
611 		: IntegerFunctionCase(context, getIntegerFuncCaseName(baseType, precision, shaderType).c_str(), "imulExtended", shaderType)
612 	{
613 		m_spec.inputs.push_back(Symbol("x", glu::VarType(baseType, precision)));
614 		m_spec.inputs.push_back(Symbol("y", glu::VarType(baseType, precision)));
615 		m_spec.outputs.push_back(Symbol("msb", glu::VarType(baseType, precision)));
616 		m_spec.outputs.push_back(Symbol("lsb", glu::VarType(baseType, precision)));
617 		m_spec.source = "imulExtended(x, y, msb, lsb);";
618 	}
619 
getInputValues(int numValues,void * const * values) const620 	void getInputValues (int numValues, void* const* values) const
621 	{
622 		de::Random				rnd			(deStringHash(getName()) ^ 0x224fa1u);
623 		const glu::DataType		type		= m_spec.inputs[0].varType.getBasicType();
624 //		const glu::Precision	precision	= m_spec.inputs[0].varType.getPrecision();
625 		const int				scalarSize	= glu::getDataTypeScalarSize(type);
626 		deUint32*				in0			= (deUint32*)values[0];
627 		deUint32*				in1			= (deUint32*)values[1];
628 		int						valueNdx	= 0;
629 
630 		const struct
631 		{
632 			deUint32	x;
633 			deUint32	y;
634 		} easyCases[] =
635 		{
636 			{ 0x00000000u,	0x00000000u },
637 			{ 0xffffffffu,	0x00000002u },
638 			{ 0x7fffffffu,	0x00000001u },
639 			{ 0x7fffffffu,	0x00000002u },
640 			{ 0x7fffffffu,	0x7fffffffu },
641 			{ 0xffffffffu,	0xffffffffu },
642 			{ 0x7fffffffu,	0xfffffffeu },
643 		};
644 
645 		for (int easyCaseNdx = 0; easyCaseNdx < DE_LENGTH_OF_ARRAY(easyCases); easyCaseNdx++)
646 		{
647 			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
648 			{
649 				in0[valueNdx*scalarSize + compNdx] = (deInt32)easyCases[easyCaseNdx].x;
650 				in1[valueNdx*scalarSize + compNdx] = (deInt32)easyCases[easyCaseNdx].y;
651 			}
652 
653 			valueNdx += 1;
654 		}
655 
656 		while (valueNdx < numValues)
657 		{
658 			for (int compNdx = 0; compNdx < scalarSize; compNdx++)
659 			{
660 				const deInt32	base0	= (deInt32)rnd.getUint32();
661 				const deInt32	base1	= (deInt32)rnd.getUint32();
662 				const int		adj0	= rnd.getInt(0, 20);
663 				const int		adj1	= rnd.getInt(0, 20);
664 				in0[valueNdx*scalarSize + compNdx] = base0 >> adj0;
665 				in1[valueNdx*scalarSize + compNdx] = base1 >> adj1;
666 			}
667 
668 			valueNdx += 1;
669 		}
670 	}
671 
compare(const void * const * inputs,const void * const * outputs)672 	bool compare (const void* const* inputs, const void* const* outputs)
673 	{
674 		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
675 		const int				scalarSize		= glu::getDataTypeScalarSize(type);
676 
677 		for (int compNdx = 0; compNdx < scalarSize; compNdx++)
678 		{
679 			const deInt32	in0		= ((const deInt32*)inputs[0])[compNdx];
680 			const deInt32	in1		= ((const deInt32*)inputs[1])[compNdx];
681 			const deInt32	out0	= ((const deInt32*)outputs[0])[compNdx];
682 			const deInt32	out1	= ((const deInt32*)outputs[1])[compNdx];
683 			const deInt64	mul64	= deInt64(in0)*deInt64(in1);
684 			const deInt32	ref0	= deInt32(mul64 >> 32);
685 			const deInt32	ref1	= deInt32(mul64 & 0xffffffffu);
686 
687 			if (out0 != ref0 || out1 != ref1)
688 			{
689 				m_failMsg << "Expected [" << compNdx << "] = " << tcu::toHex(ref0) << ", " << tcu::toHex(ref1);
690 				return false;
691 			}
692 		}
693 
694 		return true;
695 	}
696 };
697 
698 class BitfieldExtractCase : public IntegerFunctionCase
699 {
700 public:
BitfieldExtractCase(Context & context,glu::DataType baseType,glu::Precision precision,glu::ShaderType shaderType)701 	BitfieldExtractCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
702 		: IntegerFunctionCase(context, getIntegerFuncCaseName(baseType, precision, shaderType).c_str(), "bitfieldExtract", shaderType)
703 	{
704 		m_spec.inputs.push_back(Symbol("value", glu::VarType(baseType, precision)));
705 		m_spec.inputs.push_back(Symbol("offset", glu::VarType(glu::TYPE_INT, precision)));
706 		m_spec.inputs.push_back(Symbol("bits", glu::VarType(glu::TYPE_INT, precision)));
707 		m_spec.outputs.push_back(Symbol("extracted", glu::VarType(baseType, precision)));
708 		m_spec.source = "extracted = bitfieldExtract(value, offset, bits);";
709 	}
710 
getInputValues(int numValues,void * const * values) const711 	void getInputValues (int numValues, void* const* values) const
712 	{
713 		de::Random				rnd			(deStringHash(getName()) ^ 0xa113fca2u);
714 		const glu::DataType		type		= m_spec.inputs[0].varType.getBasicType();
715 		const glu::Precision	precision	= m_spec.inputs[0].varType.getPrecision();
716 		const bool				ignoreSign	= precision != glu::PRECISION_HIGHP && glu::isDataTypeIntOrIVec(type);
717 		const int				numBits		= getShaderUintBitCount(m_shaderType, precision) - (ignoreSign ? 1 : 0);
718 		deUint32*				inValue		= (deUint32*)values[0];
719 		int*					inOffset	= (int*)values[1];
720 		int*					inBits		= (int*)values[2];
721 
722 		for (int valueNdx = 0; valueNdx < numValues; ++valueNdx)
723 		{
724 			const int		bits	= rnd.getInt(0, numBits);
725 			const int		offset	= rnd.getInt(0, numBits-bits);
726 
727 			inOffset[valueNdx]	= offset;
728 			inBits[valueNdx]	= bits;
729 		}
730 
731 		generateRandomInputData(rnd, m_shaderType, type, precision, inValue, numValues);
732 	}
733 
compare(const void * const * inputs,const void * const * outputs)734 	bool compare (const void* const* inputs, const void* const* outputs)
735 	{
736 		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
737 		const bool				isSigned		= glu::isDataTypeIntOrIVec(type);
738 		const int				scalarSize		= glu::getDataTypeScalarSize(type);
739 		const int				offset			= *((const int*)inputs[1]);
740 		const int				bits			= *((const int*)inputs[2]);
741 
742 		for (int compNdx = 0; compNdx < scalarSize; compNdx++)
743 		{
744 			const deUint32	value	= ((const deUint32*)inputs[0])[compNdx];
745 			const deUint32	out		= ((const deUint32*)outputs[0])[compNdx];
746 			const deUint32	valMask	= (bits == 32 ? ~0u : ((1u<<bits)-1u));
747 			const deUint32	baseVal	= (offset == 32) ? (0) : ((value >> offset) & valMask);
748 			const deUint32	ref		= baseVal | ((isSigned && (baseVal & (1<<(bits-1)))) ? ~valMask : 0u);
749 
750 			if (out != ref)
751 			{
752 				m_failMsg << "Expected [" << compNdx << "] = " << tcu::toHex(ref);
753 				return false;
754 			}
755 		}
756 
757 		return true;
758 	}
759 };
760 
761 class BitfieldInsertCase : public IntegerFunctionCase
762 {
763 public:
BitfieldInsertCase(Context & context,glu::DataType baseType,glu::Precision precision,glu::ShaderType shaderType)764 	BitfieldInsertCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
765 		: IntegerFunctionCase(context, getIntegerFuncCaseName(baseType, precision, shaderType).c_str(), "bitfieldInsert", shaderType)
766 	{
767 		m_spec.inputs.push_back(Symbol("base", glu::VarType(baseType, precision)));
768 		m_spec.inputs.push_back(Symbol("insert", glu::VarType(baseType, precision)));
769 		m_spec.inputs.push_back(Symbol("offset", glu::VarType(glu::TYPE_INT, precision)));
770 		m_spec.inputs.push_back(Symbol("bits", glu::VarType(glu::TYPE_INT, precision)));
771 		m_spec.outputs.push_back(Symbol("result", glu::VarType(baseType, precision)));
772 		m_spec.source = "result = bitfieldInsert(base, insert, offset, bits);";
773 	}
774 
getInputValues(int numValues,void * const * values) const775 	void getInputValues (int numValues, void* const* values) const
776 	{
777 		de::Random				rnd			(deStringHash(getName()) ^ 0x12c2acff);
778 		const glu::DataType		type		= m_spec.inputs[0].varType.getBasicType();
779 		const glu::Precision	precision	= m_spec.inputs[0].varType.getPrecision();
780 		const int				numBits		= getShaderUintBitCount(m_shaderType, precision);
781 		deUint32*				inBase		= (deUint32*)values[0];
782 		deUint32*				inInsert	= (deUint32*)values[1];
783 		int*					inOffset	= (int*)values[2];
784 		int*					inBits		= (int*)values[3];
785 
786 		for (int valueNdx = 0; valueNdx < numValues; ++valueNdx)
787 		{
788 			const int bits		= rnd.getInt(0, numBits);
789 			const int offset	= rnd.getInt(0, numBits-bits);
790 
791 			inOffset[valueNdx]	= offset;
792 			inBits[valueNdx]	= bits;
793 		}
794 
795 		generateRandomInputData(rnd, m_shaderType, type, precision, inBase, numValues);
796 		generateRandomInputData(rnd, m_shaderType, type, precision, inInsert, numValues);
797 	}
798 
compare(const void * const * inputs,const void * const * outputs)799 	bool compare (const void* const* inputs, const void* const* outputs)
800 	{
801 		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
802 		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
803 		const int				scalarSize		= glu::getDataTypeScalarSize(type);
804 		const int				integerLength	= getShaderUintBitCount(m_shaderType, precision);
805 		const deUint32			cmpMask			= getLowBitMask(integerLength);
806 		const int				offset			= *((const int*)inputs[2]);
807 		const int				bits			= *((const int*)inputs[3]);
808 
809 		for (int compNdx = 0; compNdx < scalarSize; compNdx++)
810 		{
811 			const deUint32	base	= ((const deUint32*)inputs[0])[compNdx];
812 			const deUint32	insert	= ((const deUint32*)inputs[1])[compNdx];
813 			const deInt32	out		= ((const deUint32*)outputs[0])[compNdx];
814 
815 			const deUint32	mask	= bits == 32 ? ~0u : (1u<<bits)-1;
816 			const deUint32	ref		= (base & ~(mask<<offset)) | ((insert & mask)<<offset);
817 
818 			if ((out&cmpMask) != (ref&cmpMask))
819 			{
820 				m_failMsg << "Expected [" << compNdx << "] = " << tcu::toHex(ref);
821 				return false;
822 			}
823 		}
824 
825 		return true;
826 	}
827 };
828 
reverseBits(deUint32 v)829 static inline deUint32 reverseBits (deUint32 v)
830 {
831 	v = (((v & 0xaaaaaaaa) >> 1) | ((v & 0x55555555) << 1));
832 	v = (((v & 0xcccccccc) >> 2) | ((v & 0x33333333) << 2));
833 	v = (((v & 0xf0f0f0f0) >> 4) | ((v & 0x0f0f0f0f) << 4));
834 	v = (((v & 0xff00ff00) >> 8) | ((v & 0x00ff00ff) << 8));
835 	return((v >> 16) | (v << 16));
836 }
837 
838 class BitfieldReverseCase : public IntegerFunctionCase
839 {
840 public:
BitfieldReverseCase(Context & context,glu::DataType baseType,glu::Precision precision,glu::ShaderType shaderType)841 	BitfieldReverseCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
842 		: IntegerFunctionCase(context, getIntegerFuncCaseName(baseType, precision, shaderType).c_str(), "bitfieldReverse", shaderType)
843 	{
844 		m_spec.inputs.push_back(Symbol("value", glu::VarType(baseType, precision)));
845 		m_spec.outputs.push_back(Symbol("result", glu::VarType(baseType, glu::PRECISION_HIGHP)));
846 		m_spec.source = "result = bitfieldReverse(value);";
847 	}
848 
getInputValues(int numValues,void * const * values) const849 	void getInputValues (int numValues, void* const* values) const
850 	{
851 		de::Random				rnd			(deStringHash(getName()) ^ 0xff23a4);
852 		const glu::DataType		type		= m_spec.inputs[0].varType.getBasicType();
853 		const glu::Precision	precision	= m_spec.inputs[0].varType.getPrecision();
854 		deUint32*				inValue		= (deUint32*)values[0];
855 
856 		generateRandomInputData(rnd, m_shaderType, type, precision, inValue, numValues);
857 	}
858 
compare(const void * const * inputs,const void * const * outputs)859 	bool compare (const void* const* inputs, const void* const* outputs)
860 	{
861 		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
862 		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
863 		const int				integerLength	= getShaderUintBitCount(m_shaderType, precision);
864 		const int				scalarSize		= glu::getDataTypeScalarSize(type);
865 		const deUint32			cmpMask			= reverseBits(getLowBitMask(integerLength));
866 
867 		for (int compNdx = 0; compNdx < scalarSize; compNdx++)
868 		{
869 			const deUint32	value	= ((const deUint32*)inputs[0])[compNdx];
870 			const deInt32	out		= ((const deUint32*)outputs[0])[compNdx];
871 			const deUint32	ref		= reverseBits(value);
872 
873 			if ((out&cmpMask) != (ref&cmpMask))
874 			{
875 				m_failMsg << "Expected [" << compNdx << "] = " << tcu::toHex(ref);
876 				return false;
877 			}
878 		}
879 
880 		return true;
881 	}
882 };
883 
884 class BitCountCase : public IntegerFunctionCase
885 {
886 public:
BitCountCase(Context & context,glu::DataType baseType,glu::Precision precision,glu::ShaderType shaderType)887 	BitCountCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
888 		: IntegerFunctionCase(context, getIntegerFuncCaseName(baseType, precision, shaderType).c_str(), "bitCount", shaderType)
889 	{
890 		const int			vecSize		= glu::getDataTypeScalarSize(baseType);
891 		const glu::DataType	intType		= vecSize == 1 ? glu::TYPE_INT : glu::getDataTypeIntVec(vecSize);
892 
893 		m_spec.inputs.push_back(Symbol("value", glu::VarType(baseType, precision)));
894 		m_spec.outputs.push_back(Symbol("count", glu::VarType(intType, glu::PRECISION_LOWP)));
895 		m_spec.source = "count = bitCount(value);";
896 	}
897 
getInputValues(int numValues,void * const * values) const898 	void getInputValues (int numValues, void* const* values) const
899 	{
900 		de::Random				rnd			(deStringHash(getName()) ^ 0xab2cca4);
901 		const glu::DataType		type		= m_spec.inputs[0].varType.getBasicType();
902 		const glu::Precision	precision	= m_spec.inputs[0].varType.getPrecision();
903 		deUint32*				inValue		= (deUint32*)values[0];
904 
905 		generateRandomInputData(rnd, m_shaderType, type, precision, inValue, numValues);
906 	}
907 
compare(const void * const * inputs,const void * const * outputs)908 	bool compare (const void* const* inputs, const void* const* outputs)
909 	{
910 		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
911 		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
912 		const int				integerLength	= getShaderUintBitCount(m_shaderType, precision);
913 		const int				scalarSize		= glu::getDataTypeScalarSize(type);
914 		const deUint32			countMask		= getLowBitMask(integerLength);
915 
916 		for (int compNdx = 0; compNdx < scalarSize; compNdx++)
917 		{
918 			const deUint32	value	= ((const deUint32*)inputs[0])[compNdx];
919 			const int		out		= ((const int*)outputs[0])[compNdx];
920 			const int		minRef	= dePop32(value&countMask);
921 			const int		maxRef	= dePop32(value);
922 
923 			if (!de::inRange(out, minRef, maxRef))
924 			{
925 				m_failMsg << "Expected [" << compNdx << "] in range [" << minRef << ", " << maxRef << "]";
926 				return false;
927 			}
928 		}
929 
930 		return true;
931 	}
932 };
933 
findLSB(deUint32 value)934 static int findLSB (deUint32 value)
935 {
936 	for (int i = 0; i < 32; i++)
937 	{
938 		if (value & (1u<<i))
939 			return i;
940 	}
941 	return -1;
942 }
943 
944 class FindLSBCase : public IntegerFunctionCase
945 {
946 public:
FindLSBCase(Context & context,glu::DataType baseType,glu::Precision precision,glu::ShaderType shaderType)947 	FindLSBCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
948 		: IntegerFunctionCase(context, getIntegerFuncCaseName(baseType, precision, shaderType).c_str(), "findLSB", shaderType)
949 	{
950 		const int			vecSize		= glu::getDataTypeScalarSize(baseType);
951 		const glu::DataType	intType		= vecSize == 1 ? glu::TYPE_INT : glu::getDataTypeIntVec(vecSize);
952 
953 		m_spec.inputs.push_back(Symbol("value", glu::VarType(baseType, precision)));
954 		m_spec.outputs.push_back(Symbol("lsb", glu::VarType(intType, glu::PRECISION_LOWP)));
955 		m_spec.source = "lsb = findLSB(value);";
956 	}
957 
getInputValues(int numValues,void * const * values) const958 	void getInputValues (int numValues, void* const* values) const
959 	{
960 		de::Random				rnd			(deStringHash(getName()) ^ 0x9923c2af);
961 		const glu::DataType		type		= m_spec.inputs[0].varType.getBasicType();
962 		const glu::Precision	precision	= m_spec.inputs[0].varType.getPrecision();
963 		deUint32*				inValue		= (deUint32*)values[0];
964 
965 		generateRandomInputData(rnd, m_shaderType, type, precision, inValue, numValues);
966 	}
967 
compare(const void * const * inputs,const void * const * outputs)968 	bool compare (const void* const* inputs, const void* const* outputs)
969 	{
970 		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
971 		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
972 		const int				scalarSize		= glu::getDataTypeScalarSize(type);
973 		const int				integerLength	= getShaderUintBitCount(m_shaderType, precision);
974 		const deUint32			mask			= getLowBitMask(integerLength);
975 
976 		for (int compNdx = 0; compNdx < scalarSize; compNdx++)
977 		{
978 			const deUint32	value	= ((const deUint32*)inputs[0])[compNdx];
979 			const int		out		= ((const int*)outputs[0])[compNdx];
980 			const int		minRef	= findLSB(value&mask);
981 			const int		maxRef	= findLSB(value);
982 
983 			if (!de::inRange(out, minRef, maxRef))
984 			{
985 				m_failMsg << "Expected [" << compNdx << "] in range [" << minRef << ", " << maxRef << "]";
986 				return false;
987 			}
988 		}
989 
990 		return true;
991 	}
992 };
993 
findMSB(deInt32 value)994 static int findMSB (deInt32 value)
995 {
996 	if (value > 0)
997 		return 31 - deClz32((deUint32)value);
998 	else if (value < 0)
999 		return 31 - deClz32(~(deUint32)value);
1000 	else
1001 		return -1;
1002 }
1003 
findMSB(deUint32 value)1004 static int findMSB (deUint32 value)
1005 {
1006 	if (value > 0)
1007 		return 31 - deClz32(value);
1008 	else
1009 		return -1;
1010 }
1011 
toPrecision(deUint32 value,int numIntegerBits)1012 static deUint32 toPrecision (deUint32 value, int numIntegerBits)
1013 {
1014 	return value & getLowBitMask(numIntegerBits);
1015 }
1016 
toPrecision(deInt32 value,int numIntegerBits)1017 static deInt32 toPrecision (deInt32 value, int numIntegerBits)
1018 {
1019 	return (deInt32)extendSignTo32((deUint32)value & getLowBitMask(numIntegerBits), numIntegerBits);
1020 }
1021 
1022 class FindMSBCase : public IntegerFunctionCase
1023 {
1024 public:
FindMSBCase(Context & context,glu::DataType baseType,glu::Precision precision,glu::ShaderType shaderType)1025 	FindMSBCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
1026 		: IntegerFunctionCase(context, getIntegerFuncCaseName(baseType, precision, shaderType).c_str(), "findMSB", shaderType)
1027 	{
1028 		const int			vecSize		= glu::getDataTypeScalarSize(baseType);
1029 		const glu::DataType	intType		= vecSize == 1 ? glu::TYPE_INT : glu::getDataTypeIntVec(vecSize);
1030 
1031 		m_spec.inputs.push_back(Symbol("value", glu::VarType(baseType, precision)));
1032 		m_spec.outputs.push_back(Symbol("msb", glu::VarType(intType, glu::PRECISION_LOWP)));
1033 		m_spec.source = "msb = findMSB(value);";
1034 	}
1035 
getInputValues(int numValues,void * const * values) const1036 	void getInputValues (int numValues, void* const* values) const
1037 	{
1038 		de::Random				rnd			(deStringHash(getName()) ^ 0x742ac4e);
1039 		const glu::DataType		type		= m_spec.inputs[0].varType.getBasicType();
1040 		const glu::Precision	precision	= m_spec.inputs[0].varType.getPrecision();
1041 		deUint32*				inValue		= (deUint32*)values[0];
1042 
1043 		generateRandomInputData(rnd, m_shaderType, type, precision, inValue, numValues);
1044 	}
1045 
compare(const void * const * inputs,const void * const * outputs)1046 	bool compare (const void* const* inputs, const void* const* outputs)
1047 	{
1048 		const glu::DataType		type			= m_spec.inputs[0].varType.getBasicType();
1049 		const glu::Precision	precision		= m_spec.inputs[0].varType.getPrecision();
1050 		const bool				isSigned		= glu::isDataTypeIntOrIVec(type);
1051 		const int				scalarSize		= glu::getDataTypeScalarSize(type);
1052 		const int				integerLength	= getShaderUintBitCount(m_shaderType, precision);
1053 
1054 		for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1055 		{
1056 			const deUint32	value	= ((const deUint32*)inputs[0])[compNdx];
1057 			const int		out		= ((const deInt32*)outputs[0])[compNdx];
1058 			const int		minRef	= isSigned ? findMSB(toPrecision(deInt32(value), integerLength))	: findMSB(toPrecision(value, integerLength));
1059 			const int		maxRef	= isSigned ? findMSB(deInt32(value))								: findMSB(value);
1060 
1061 			if (!de::inRange(out, minRef, maxRef))
1062 			{
1063 				m_failMsg << "Expected [" << compNdx << "] in range [" << minRef << ", " << maxRef << "]";
1064 				return false;
1065 			}
1066 		}
1067 
1068 		return true;
1069 	}
1070 };
1071 
ShaderIntegerFunctionTests(Context & context)1072 ShaderIntegerFunctionTests::ShaderIntegerFunctionTests (Context& context)
1073 	: TestCaseGroup(context, "integer", "Integer function tests")
1074 {
1075 }
1076 
~ShaderIntegerFunctionTests(void)1077 ShaderIntegerFunctionTests::~ShaderIntegerFunctionTests (void)
1078 {
1079 }
1080 
1081 template<class TestClass>
addFunctionCases(TestCaseGroup * parent,const char * functionName,bool intTypes,bool uintTypes,bool allPrec,deUint32 shaderBits)1082 static void addFunctionCases (TestCaseGroup* parent, const char* functionName, bool intTypes, bool uintTypes, bool allPrec, deUint32 shaderBits)
1083 {
1084 	tcu::TestCaseGroup* group = new tcu::TestCaseGroup(parent->getTestContext(), functionName, functionName);
1085 	parent->addChild(group);
1086 
1087 	const glu::DataType scalarTypes[] =
1088 	{
1089 		glu::TYPE_INT,
1090 		glu::TYPE_UINT
1091 	};
1092 
1093 	for (int scalarTypeNdx = 0; scalarTypeNdx < DE_LENGTH_OF_ARRAY(scalarTypes); scalarTypeNdx++)
1094 	{
1095 		const glu::DataType scalarType = scalarTypes[scalarTypeNdx];
1096 
1097 		if ((!intTypes && scalarType == glu::TYPE_INT) || (!uintTypes && scalarType == glu::TYPE_UINT))
1098 			continue;
1099 
1100 		for (int vecSize = 1; vecSize <= 4; vecSize++)
1101 		{
1102 			for (int prec = glu::PRECISION_LOWP; prec <= glu::PRECISION_HIGHP; prec++)
1103 			{
1104 				if (prec != glu::PRECISION_HIGHP && !allPrec)
1105 					continue;
1106 
1107 				for (int shaderTypeNdx = 0; shaderTypeNdx < glu::SHADERTYPE_LAST; shaderTypeNdx++)
1108 				{
1109 					if (shaderBits & (1<<shaderTypeNdx))
1110 						group->addChild(new TestClass(parent->getContext(), glu::DataType(scalarType + vecSize - 1), glu::Precision(prec), glu::ShaderType(shaderTypeNdx)));
1111 				}
1112 			}
1113 		}
1114 	}
1115 }
1116 
init(void)1117 void ShaderIntegerFunctionTests::init (void)
1118 {
1119 	enum
1120 	{
1121 		VS = (1<<glu::SHADERTYPE_VERTEX),
1122 		FS = (1<<glu::SHADERTYPE_FRAGMENT),
1123 		CS = (1<<glu::SHADERTYPE_COMPUTE),
1124 		GS = (1<<glu::SHADERTYPE_GEOMETRY),
1125 		TC = (1<<glu::SHADERTYPE_TESSELLATION_CONTROL),
1126 		TE = (1<<glu::SHADERTYPE_TESSELLATION_EVALUATION),
1127 
1128 		ALL_SHADERS = VS|TC|TE|GS|FS|CS
1129 	};
1130 
1131 	//																		Int?	Uint?	AllPrec?	Shaders
1132 	addFunctionCases<UaddCarryCase>				(this,	"uaddcarry",		false,	true,	true,		ALL_SHADERS);
1133 	addFunctionCases<UsubBorrowCase>			(this,	"usubborrow",		false,	true,	true,		ALL_SHADERS);
1134 	addFunctionCases<UmulExtendedCase>			(this,	"umulextended",		false,	true,	false,		ALL_SHADERS);
1135 	addFunctionCases<ImulExtendedCase>			(this,	"imulextended",		true,	false,	false,		ALL_SHADERS);
1136 	addFunctionCases<BitfieldExtractCase>		(this,	"bitfieldextract",	true,	true,	true,		ALL_SHADERS);
1137 	addFunctionCases<BitfieldInsertCase>		(this,	"bitfieldinsert",	true,	true,	true,		ALL_SHADERS);
1138 	addFunctionCases<BitfieldReverseCase>		(this,	"bitfieldreverse",	true,	true,	true,		ALL_SHADERS);
1139 	addFunctionCases<BitCountCase>				(this,	"bitcount",			true,	true,	true,		ALL_SHADERS);
1140 	addFunctionCases<FindLSBCase>				(this,	"findlsb",			true,	true,	true,		ALL_SHADERS);
1141 	addFunctionCases<FindMSBCase>				(this,	"findmsb",			true,	true,	true,		ALL_SHADERS);
1142 }
1143 
1144 } // Functional
1145 } // gles31
1146 } // deqp
1147