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