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