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