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