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