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