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
34namespace deqp
35{
36namespace gles31
37{
38namespace Functional
39{
40
41using std::vector;
42using std::string;
43using tcu::TestLog;
44using namespace gls::ShaderExecUtil;
45
46using tcu::IVec2;
47using tcu::IVec3;
48using tcu::IVec4;
49using tcu::UVec2;
50using tcu::UVec3;
51using tcu::UVec4;
52
53// Utilities
54
55namespace
56{
57
58struct HexFloat
59{
60	const float value;
61	HexFloat (const float value_) : value(value_) {}
62};
63
64std::ostream& operator<< (std::ostream& str, const HexFloat& v)
65{
66	return str << v.value << " / " << tcu::toHex(tcu::Float32(v.value).bits());
67}
68
69struct VarValue
70{
71	const glu::VarType&	type;
72	const void*			value;
73
74	VarValue (const glu::VarType& type_, const void* value_) : type(type_), value(value_) {}
75};
76
77std::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
111inline 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
120static 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
127static 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
137static 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
162class IntegerFunctionCase : public TestCase
163{
164public:
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
172protected:
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
185private:
186	ShaderExecutor*			m_executor;
187};
188
189IntegerFunctionCase::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
198IntegerFunctionCase::~IntegerFunctionCase (void)
199{
200	IntegerFunctionCase::deinit();
201}
202
203void 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
214void IntegerFunctionCase::deinit (void)
215{
216	delete m_executor;
217	m_executor = DE_NULL;
218}
219
220static 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
228static 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
236static 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
256IntegerFunctionCase::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
322static 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
335static 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
350static 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
355class UaddCarryCase : public IntegerFunctionCase
356{
357public:
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
368	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
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
451class UsubBorrowCase : public IntegerFunctionCase
452{
453public:
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
464	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
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
545class UmulExtendedCase : public IntegerFunctionCase
546{
547public:
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
558	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
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
635class ImulExtendedCase : public IntegerFunctionCase
636{
637public:
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
648	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
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
726class BitfieldExtractCase : public IntegerFunctionCase
727{
728public:
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
739	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
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
789class BitfieldInsertCase : public IntegerFunctionCase
790{
791public:
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
803	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
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
857static 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
866class BitfieldReverseCase : public IntegerFunctionCase
867{
868public:
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
877	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
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
912class BitCountCase : public IntegerFunctionCase
913{
914public:
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
926	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
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
962static 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
972class FindLSBCase : public IntegerFunctionCase
973{
974public:
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
986	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
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
1022static 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
1032static int findMSB (deUint32 value)
1033{
1034	if (value > 0)
1035		return 31 - deClz32(value);
1036	else
1037		return -1;
1038}
1039
1040static deUint32 toPrecision (deUint32 value, int numIntegerBits)
1041{
1042	return value & getLowBitMask(numIntegerBits);
1043}
1044
1045static deInt32 toPrecision (deInt32 value, int numIntegerBits)
1046{
1047	return (deInt32)extendSignTo32((deUint32)value & getLowBitMask(numIntegerBits), numIntegerBits);
1048}
1049
1050class FindMSBCase : public IntegerFunctionCase
1051{
1052public:
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
1064	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
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
1100ShaderIntegerFunctionTests::ShaderIntegerFunctionTests (Context& context)
1101	: TestCaseGroup(context, "integer", "Integer function tests")
1102{
1103}
1104
1105ShaderIntegerFunctionTests::~ShaderIntegerFunctionTests (void)
1106{
1107}
1108
1109template<class TestClass>
1110static 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
1145void 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