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::__anon6871bb470111::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::__anon6871bb470111::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
getPrecisionPostfix(glu::Precision precision)196 static const char* getPrecisionPostfix (glu::Precision precision)
197 {
198 static const char* s_postfix[] =
199 {
200 "_lowp",
201 "_mediump",
202 "_highp"
203 };
204 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_postfix) == glu::PRECISION_LAST);
205 DE_ASSERT(de::inBounds<int>(precision, 0, DE_LENGTH_OF_ARRAY(s_postfix)));
206 return s_postfix[precision];
207 }
208
getShaderTypePostfix(glu::ShaderType shaderType)209 static const char* getShaderTypePostfix (glu::ShaderType shaderType)
210 {
211 static const char* s_postfix[] =
212 {
213 "_vertex",
214 "_fragment",
215 "_geometry",
216 "_tess_control",
217 "_tess_eval",
218 "_compute"
219 };
220 DE_ASSERT(de::inBounds<int>(shaderType, 0, DE_LENGTH_OF_ARRAY(s_postfix)));
221 return s_postfix[shaderType];
222 }
223
getIntegerFuncCaseName(glu::DataType baseType,glu::Precision precision,glu::ShaderType shaderType)224 static std::string getIntegerFuncCaseName (glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
225 {
226 return string(glu::getDataTypeName(baseType)) + getPrecisionPostfix(precision) + getShaderTypePostfix(shaderType);
227 }
228
reverseBits(deUint32 v)229 static inline deUint32 reverseBits (deUint32 v)
230 {
231 v = (((v & 0xaaaaaaaa) >> 1) | ((v & 0x55555555) << 1));
232 v = (((v & 0xcccccccc) >> 2) | ((v & 0x33333333) << 2));
233 v = (((v & 0xf0f0f0f0) >> 4) | ((v & 0x0f0f0f0f) << 4));
234 v = (((v & 0xff00ff00) >> 8) | ((v & 0x00ff00ff) << 8));
235 return((v >> 16) | (v << 16));
236 }
237
findLSB(deUint32 value)238 static int findLSB (deUint32 value)
239 {
240 for (int i = 0; i < 32; i++)
241 {
242 if (value & (1u<<i))
243 return i;
244 }
245 return -1;
246 }
247
findMSB(deInt32 value)248 static int findMSB (deInt32 value)
249 {
250 if (value > 0)
251 return 31 - deClz32((deUint32)value);
252 else if (value < 0)
253 return 31 - deClz32(~(deUint32)value);
254 else
255 return -1;
256 }
257
findMSB(deUint32 value)258 static int findMSB (deUint32 value)
259 {
260 if (value > 0)
261 return 31 - deClz32(value);
262 else
263 return -1;
264 }
265
toPrecision(deUint32 value,int numIntegerBits)266 static deUint32 toPrecision (deUint32 value, int numIntegerBits)
267 {
268 return value & getLowBitMask(numIntegerBits);
269 }
270
toPrecision(deInt32 value,int numIntegerBits)271 static deInt32 toPrecision (deInt32 value, int numIntegerBits)
272 {
273 return (deInt32)extendSignTo32((deUint32)value & getLowBitMask(numIntegerBits), numIntegerBits);
274 }
275
276 template<class TestClass>
addFunctionCases(tcu::TestCaseGroup * parent,const char * functionName,bool intTypes,bool uintTypes,bool allPrec,deUint32 shaderBits)277 static void addFunctionCases (tcu::TestCaseGroup* parent, const char* functionName, bool intTypes, bool uintTypes, bool allPrec, deUint32 shaderBits)
278 {
279 tcu::TestCaseGroup* group = new tcu::TestCaseGroup(parent->getTestContext(), functionName, functionName);
280
281 parent->addChild(group);
282 const glu::DataType scalarTypes[] =
283 {
284 glu::TYPE_INT,
285 glu::TYPE_UINT
286 };
287
288 for (int scalarTypeNdx = 0; scalarTypeNdx < DE_LENGTH_OF_ARRAY(scalarTypes); scalarTypeNdx++)
289 {
290 const glu::DataType scalarType = scalarTypes[scalarTypeNdx];
291
292 if ((!intTypes && scalarType == glu::TYPE_INT) || (!uintTypes && scalarType == glu::TYPE_UINT))
293 continue;
294
295 for (int vecSize = 1; vecSize <= 4; vecSize++)
296 {
297 for (int prec = glu::PRECISION_MEDIUMP; prec <= glu::PRECISION_HIGHP; prec++)
298 {
299 if (prec != glu::PRECISION_HIGHP && !allPrec)
300 continue;
301
302 for (int shaderTypeNdx = 0; shaderTypeNdx < glu::SHADERTYPE_LAST; shaderTypeNdx++)
303 {
304 if (shaderBits & (1<<shaderTypeNdx))
305 group->addChild(new TestClass(parent->getTestContext(), glu::DataType(scalarType + vecSize - 1), glu::Precision(prec), glu::ShaderType(shaderTypeNdx)));
306 }
307 }
308 }
309 }
310 }
311
312 } // anonymous
313
314 // IntegerFunctionCase
315
316 class IntegerFunctionCase : public TestCase
317 {
318 public:
319 IntegerFunctionCase (tcu::TestContext& testCtx, const char* name, const char* description, glu::ShaderType shaderType);
320 ~IntegerFunctionCase (void);
321
initPrograms(vk::SourceCollections & programCollection) const322 virtual void initPrograms (vk::SourceCollections& programCollection) const
323 {
324 generateSources(m_shaderType, m_spec, programCollection);
325 }
326
327 virtual TestInstance* createInstance (Context& context) const = 0;
328
329 protected:
330 IntegerFunctionCase (const IntegerFunctionCase& other);
331 IntegerFunctionCase& operator= (const IntegerFunctionCase& other);
332
333 const glu::ShaderType m_shaderType;
334
335 ShaderSpec m_spec;
336
337 const int m_numValues;
338 };
339
IntegerFunctionCase(tcu::TestContext & testCtx,const char * name,const char * description,glu::ShaderType shaderType)340 IntegerFunctionCase::IntegerFunctionCase (tcu::TestContext& testCtx, const char* name, const char* description, glu::ShaderType shaderType)
341 : TestCase (testCtx, name, description)
342 , m_shaderType (shaderType)
343 , m_numValues (100)
344 {
345 }
346
~IntegerFunctionCase(void)347 IntegerFunctionCase::~IntegerFunctionCase (void)
348 {
349 }
350
351 // IntegerFunctionTestInstance
352
353 class IntegerFunctionTestInstance : public TestInstance
354 {
355 public:
IntegerFunctionTestInstance(Context & context,glu::ShaderType shaderType,const ShaderSpec & spec,int numValues,const char * name)356 IntegerFunctionTestInstance (Context& context, glu::ShaderType shaderType, const ShaderSpec& spec, int numValues, const char* name)
357 : TestInstance (context)
358 , m_shaderType (shaderType)
359 , m_spec (spec)
360 , m_numValues (numValues)
361 , m_name (name)
362 , m_executor (createExecutor(context, m_shaderType, m_spec))
363 {
364 }
365 virtual tcu::TestStatus iterate (void);
366 protected:
367 virtual bool compare (const void* const* inputs, const void* const* outputs) = 0;
368
369 virtual void getInputValues (int numValues, void* const* values) const = 0;
370
371 const glu::ShaderType m_shaderType;
372
373 ShaderSpec m_spec;
374
375 const int m_numValues;
376
377 const char* m_name;
378
379 std::ostringstream m_failMsg; //!< Comparison failure help message.
380
381 de::UniquePtr<ShaderExecutor> m_executor;
382 };
383
iterate(void)384 tcu::TestStatus IntegerFunctionTestInstance::iterate (void)
385 {
386 const int numInputScalars = computeTotalScalarSize(m_spec.inputs);
387 const int numOutputScalars = computeTotalScalarSize(m_spec.outputs);
388 vector<deUint32> inputData (numInputScalars * m_numValues);
389 vector<deUint32> outputData (numOutputScalars * m_numValues);
390 const vector<void*> inputPointers = getInputOutputPointers(m_spec.inputs, inputData, m_numValues);
391 const vector<void*> outputPointers = getInputOutputPointers(m_spec.outputs, outputData, m_numValues);
392
393 // Initialize input data.
394 getInputValues(m_numValues, &inputPointers[0]);
395
396 // Execute shader.
397 m_executor->execute(m_numValues, &inputPointers[0], &outputPointers[0]);
398
399 // Compare results.
400 {
401 const vector<int> inScalarSizes = getScalarSizes(m_spec.inputs);
402 const vector<int> outScalarSizes = getScalarSizes(m_spec.outputs);
403 vector<void*> curInputPtr (inputPointers.size());
404 vector<void*> curOutputPtr (outputPointers.size());
405 int numFailed = 0;
406 tcu::TestContext& testCtx = m_context.getTestContext();
407 for (int valNdx = 0; valNdx < m_numValues; valNdx++)
408 {
409 // Set up pointers for comparison.
410 for (int inNdx = 0; inNdx < (int)curInputPtr.size(); ++inNdx)
411 curInputPtr[inNdx] = (deUint32*)inputPointers[inNdx] + inScalarSizes[inNdx]*valNdx;
412
413 for (int outNdx = 0; outNdx < (int)curOutputPtr.size(); ++outNdx)
414 curOutputPtr[outNdx] = (deUint32*)outputPointers[outNdx] + outScalarSizes[outNdx]*valNdx;
415
416 if (!compare(&curInputPtr[0], &curOutputPtr[0]))
417 {
418 // \todo [2013-08-08 pyry] We probably want to log reference value as well?
419
420 testCtx.getLog() << TestLog::Message << "ERROR: comparison failed for value " << valNdx << ":\n " << m_failMsg.str() << TestLog::EndMessage;
421
422 testCtx.getLog() << TestLog::Message << " inputs:" << TestLog::EndMessage;
423 for (int inNdx = 0; inNdx < (int)curInputPtr.size(); inNdx++)
424 testCtx.getLog() << TestLog::Message << " " << m_spec.inputs[inNdx].name << " = "
425 << VarValue(m_spec.inputs[inNdx].varType, curInputPtr[inNdx])
426 << TestLog::EndMessage;
427
428 testCtx.getLog() << TestLog::Message << " outputs:" << TestLog::EndMessage;
429 for (int outNdx = 0; outNdx < (int)curOutputPtr.size(); outNdx++)
430 testCtx.getLog() << TestLog::Message << " " << m_spec.outputs[outNdx].name << " = "
431 << VarValue(m_spec.outputs[outNdx].varType, curOutputPtr[outNdx])
432 << TestLog::EndMessage;
433
434 m_failMsg.str("");
435 m_failMsg.clear();
436 numFailed += 1;
437 }
438 }
439
440 testCtx.getLog() << TestLog::Message << (m_numValues - numFailed) << " / " << m_numValues << " values passed" << TestLog::EndMessage;
441
442 if (numFailed == 0)
443 return tcu::TestStatus::pass("Pass");
444 else
445 return tcu::TestStatus::fail("Result comparison failed");
446 }
447 }
448
449 // Test cases
450
451 class UaddCarryCaseInstance : public IntegerFunctionTestInstance
452 {
453 public:
UaddCarryCaseInstance(Context & context,glu::ShaderType shaderType,const ShaderSpec & spec,int numValues,const char * name)454 UaddCarryCaseInstance (Context& context, glu::ShaderType shaderType, const ShaderSpec& spec, int numValues, const char* name)
455 : IntegerFunctionTestInstance (context, shaderType, spec, numValues, name)
456 {
457 }
458
getInputValues(int numValues,void * const * values) const459 void getInputValues (int numValues, void* const* values) const
460 {
461 de::Random rnd (deStringHash(m_name) ^ 0x235facu);
462 const glu::DataType type = m_spec.inputs[0].varType.getBasicType();
463 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision();
464 const int scalarSize = glu::getDataTypeScalarSize(type);
465 const int integerLength = getShaderUintBitCount(m_shaderType, precision);
466 const deUint32 integerMask = getLowBitMask(integerLength);
467 const bool isSigned = glu::isDataTypeIntOrIVec(type);
468 deUint32* in0 = (deUint32*)values[0];
469 deUint32* in1 = (deUint32*)values[1];
470
471 const struct
472 {
473 deUint32 x;
474 deUint32 y;
475 } easyCases[] =
476 {
477 { 0x00000000u, 0x00000000u },
478 { 0xfffffffeu, 0x00000001u },
479 { 0x00000001u, 0xfffffffeu },
480 { 0xffffffffu, 0x00000001u },
481 { 0x00000001u, 0xffffffffu },
482 { 0xfffffffeu, 0x00000002u },
483 { 0x00000002u, 0xfffffffeu },
484 { 0xffffffffu, 0xffffffffu }
485 };
486
487 // generate integers with proper bit count
488 for (int easyCaseNdx = 0; easyCaseNdx < DE_LENGTH_OF_ARRAY(easyCases); easyCaseNdx++)
489 {
490 for (int compNdx = 0; compNdx < scalarSize; compNdx++)
491 {
492 in0[easyCaseNdx*scalarSize + compNdx] = easyCases[easyCaseNdx].x & integerMask;
493 in1[easyCaseNdx*scalarSize + compNdx] = easyCases[easyCaseNdx].y & integerMask;
494 }
495 }
496
497 // convert to signed
498 if (isSigned)
499 {
500 for (int easyCaseNdx = 0; easyCaseNdx < DE_LENGTH_OF_ARRAY(easyCases); easyCaseNdx++)
501 {
502 for (int compNdx = 0; compNdx < scalarSize; compNdx++)
503 {
504 in0[easyCaseNdx*scalarSize + compNdx] = extendSignTo32(in0[easyCaseNdx*scalarSize + compNdx], integerLength);
505 in1[easyCaseNdx*scalarSize + compNdx] = extendSignTo32(in1[easyCaseNdx*scalarSize + compNdx], integerLength);
506 }
507 }
508 }
509
510 generateRandomInputData(rnd, m_shaderType, type, precision, in0, numValues - DE_LENGTH_OF_ARRAY(easyCases));
511 generateRandomInputData(rnd, m_shaderType, type, precision, in1, numValues - DE_LENGTH_OF_ARRAY(easyCases));
512 }
513
compare(const void * const * inputs,const void * const * outputs)514 bool compare (const void* const* inputs, const void* const* outputs)
515 {
516 const glu::DataType type = m_spec.inputs[0].varType.getBasicType();
517 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision();
518 const int scalarSize = glu::getDataTypeScalarSize(type);
519 const int integerLength = getShaderUintBitCount(m_shaderType, precision);
520 const deUint32 mask0 = getLowBitMask(integerLength);
521
522 for (int compNdx = 0; compNdx < scalarSize; compNdx++)
523 {
524 const deUint32 in0 = ((const deUint32*)inputs[0])[compNdx];
525 const deUint32 in1 = ((const deUint32*)inputs[1])[compNdx];
526 const deUint32 out0 = ((const deUint32*)outputs[0])[compNdx];
527 const deUint32 out1 = ((const deUint32*)outputs[1])[compNdx];
528 const deUint32 ref0 = in0+in1;
529 const deUint32 ref1 = (deUint64(in0)+deUint64(in1)) > 0xffffffffu ? 1u : 0u;
530
531 if (((out0&mask0) != (ref0&mask0)) || out1 != ref1)
532 {
533 m_failMsg << "Expected [" << compNdx << "] = " << tcu::toHex(ref0) << ", " << tcu::toHex(ref1);
534 return false;
535 }
536 }
537
538 return true;
539 }
540 };
541
542 class UaddCarryCase : public IntegerFunctionCase
543 {
544 public:
UaddCarryCase(tcu::TestContext & testCtx,glu::DataType baseType,glu::Precision precision,glu::ShaderType shaderType)545 UaddCarryCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
546 : IntegerFunctionCase (testCtx, getIntegerFuncCaseName(baseType, precision, shaderType).c_str(), "uaddCarry", shaderType)
547 {
548 m_spec.inputs.push_back(Symbol("x", glu::VarType(baseType, precision)));
549 m_spec.inputs.push_back(Symbol("y", glu::VarType(baseType, precision)));
550 m_spec.outputs.push_back(Symbol("sum", glu::VarType(baseType, precision)));
551 m_spec.outputs.push_back(Symbol("carry", glu::VarType(baseType, glu::PRECISION_LOWP)));
552 m_spec.source = "sum = uaddCarry(x, y, carry);";
553 }
554
createInstance(Context & ctx) const555 TestInstance* createInstance (Context& ctx) const
556 {
557 return new UaddCarryCaseInstance(ctx, m_shaderType, m_spec, m_numValues, getName());
558 }
559 };
560
561 class UsubBorrowCaseInstance : public IntegerFunctionTestInstance
562 {
563 public:
UsubBorrowCaseInstance(Context & context,glu::ShaderType shaderType,const ShaderSpec & spec,int numValues,const char * name)564 UsubBorrowCaseInstance (Context& context, glu::ShaderType shaderType, const ShaderSpec& spec, int numValues, const char* name)
565 : IntegerFunctionTestInstance (context, shaderType, spec, numValues, name)
566 {
567 }
568
getInputValues(int numValues,void * const * values) const569 void getInputValues (int numValues, void* const* values) const
570 {
571 de::Random rnd (deStringHash(m_name) ^ 0x235facu);
572 const glu::DataType type = m_spec.inputs[0].varType.getBasicType();
573 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision();
574 const int scalarSize = glu::getDataTypeScalarSize(type);
575 const int integerLength = getShaderUintBitCount(m_shaderType, precision);
576 const deUint32 integerMask = getLowBitMask(integerLength);
577 const bool isSigned = glu::isDataTypeIntOrIVec(type);
578 deUint32* in0 = (deUint32*)values[0];
579 deUint32* in1 = (deUint32*)values[1];
580
581 const struct
582 {
583 deUint32 x;
584 deUint32 y;
585 } easyCases[] =
586 {
587 { 0x00000000u, 0x00000000u },
588 { 0x00000001u, 0x00000001u },
589 { 0x00000001u, 0x00000002u },
590 { 0x00000001u, 0xffffffffu },
591 { 0xfffffffeu, 0xffffffffu },
592 { 0xffffffffu, 0xffffffffu },
593 };
594
595 // generate integers with proper bit count
596 for (int easyCaseNdx = 0; easyCaseNdx < DE_LENGTH_OF_ARRAY(easyCases); easyCaseNdx++)
597 {
598 for (int compNdx = 0; compNdx < scalarSize; compNdx++)
599 {
600 in0[easyCaseNdx*scalarSize + compNdx] = easyCases[easyCaseNdx].x & integerMask;
601 in1[easyCaseNdx*scalarSize + compNdx] = easyCases[easyCaseNdx].y & integerMask;
602 }
603 }
604
605 // convert to signed
606 if (isSigned)
607 {
608 for (int easyCaseNdx = 0; easyCaseNdx < DE_LENGTH_OF_ARRAY(easyCases); easyCaseNdx++)
609 {
610 for (int compNdx = 0; compNdx < scalarSize; compNdx++)
611 {
612 in0[easyCaseNdx*scalarSize + compNdx] = extendSignTo32(in0[easyCaseNdx*scalarSize + compNdx], integerLength);
613 in1[easyCaseNdx*scalarSize + compNdx] = extendSignTo32(in1[easyCaseNdx*scalarSize + compNdx], integerLength);
614 }
615 }
616 }
617
618 generateRandomInputData(rnd, m_shaderType, type, precision, in0, numValues - DE_LENGTH_OF_ARRAY(easyCases));
619 generateRandomInputData(rnd, m_shaderType, type, precision, in1, numValues - DE_LENGTH_OF_ARRAY(easyCases));
620 }
621
compare(const void * const * inputs,const void * const * outputs)622 bool compare (const void* const* inputs, const void* const* outputs)
623 {
624 const glu::DataType type = m_spec.inputs[0].varType.getBasicType();
625 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision();
626 const int scalarSize = glu::getDataTypeScalarSize(type);
627 const int integerLength = getShaderUintBitCount(m_shaderType, precision);
628 const deUint32 mask0 = getLowBitMask(integerLength);
629
630 for (int compNdx = 0; compNdx < scalarSize; compNdx++)
631 {
632 const deUint32 in0 = ((const deUint32*)inputs[0])[compNdx];
633 const deUint32 in1 = ((const deUint32*)inputs[1])[compNdx];
634 const deUint32 out0 = ((const deUint32*)outputs[0])[compNdx];
635 const deUint32 out1 = ((const deUint32*)outputs[1])[compNdx];
636 const deUint32 ref0 = in0-in1;
637 const deUint32 ref1 = in0 >= in1 ? 0u : 1u;
638
639 if (((out0&mask0) != (ref0&mask0)) || out1 != ref1)
640 {
641 m_failMsg << "Expected [" << compNdx << "] = " << tcu::toHex(ref0) << ", " << tcu::toHex(ref1);
642 return false;
643 }
644 }
645
646 return true;
647 }
648 };
649
650 class UsubBorrowCase : public IntegerFunctionCase
651 {
652 public:
UsubBorrowCase(tcu::TestContext & testCtx,glu::DataType baseType,glu::Precision precision,glu::ShaderType shaderType)653 UsubBorrowCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
654 : IntegerFunctionCase (testCtx, getIntegerFuncCaseName(baseType, precision, shaderType).c_str(), "usubBorrow", shaderType)
655 {
656 m_spec.inputs.push_back(Symbol("x", glu::VarType(baseType, precision)));
657 m_spec.inputs.push_back(Symbol("y", glu::VarType(baseType, precision)));
658 m_spec.outputs.push_back(Symbol("diff", glu::VarType(baseType, precision)));
659 m_spec.outputs.push_back(Symbol("carry", glu::VarType(baseType, glu::PRECISION_LOWP)));
660 m_spec.source = "diff = usubBorrow(x, y, carry);";
661 }
662
createInstance(Context & ctx) const663 TestInstance* createInstance (Context& ctx) const
664 {
665 return new UsubBorrowCaseInstance(ctx, m_shaderType, m_spec, m_numValues, getName());
666 }
667 };
668
669 class UmulExtendedCaseInstance : public IntegerFunctionTestInstance
670 {
671 public:
UmulExtendedCaseInstance(Context & context,glu::ShaderType shaderType,const ShaderSpec & spec,int numValues,const char * name)672 UmulExtendedCaseInstance (Context& context, glu::ShaderType shaderType, const ShaderSpec& spec, int numValues, const char* name)
673 : IntegerFunctionTestInstance (context, shaderType, spec, numValues, name)
674 {
675 }
676
getInputValues(int numValues,void * const * values) const677 void getInputValues (int numValues, void* const* values) const
678 {
679 de::Random rnd (deStringHash(m_name) ^ 0x235facu);
680 const glu::DataType type = m_spec.inputs[0].varType.getBasicType();
681 // const glu::Precision precision = m_spec.inputs[0].varType.getPrecision();
682 const int scalarSize = glu::getDataTypeScalarSize(type);
683 deUint32* in0 = (deUint32*)values[0];
684 deUint32* in1 = (deUint32*)values[1];
685 int valueNdx = 0;
686
687 const struct
688 {
689 deUint32 x;
690 deUint32 y;
691 } easyCases[] =
692 {
693 { 0x00000000u, 0x00000000u },
694 { 0xffffffffu, 0x00000001u },
695 { 0xffffffffu, 0x00000002u },
696 { 0x00000001u, 0xffffffffu },
697 { 0x00000002u, 0xffffffffu },
698 { 0xffffffffu, 0xffffffffu },
699 };
700
701 for (int easyCaseNdx = 0; easyCaseNdx < DE_LENGTH_OF_ARRAY(easyCases); easyCaseNdx++)
702 {
703 for (int compNdx = 0; compNdx < scalarSize; compNdx++)
704 {
705 in0[valueNdx*scalarSize + compNdx] = easyCases[easyCaseNdx].x;
706 in1[valueNdx*scalarSize + compNdx] = easyCases[easyCaseNdx].y;
707 }
708
709 valueNdx += 1;
710 }
711
712 while (valueNdx < numValues)
713 {
714 for (int compNdx = 0; compNdx < scalarSize; compNdx++)
715 {
716 const deUint32 base0 = rnd.getUint32();
717 const deUint32 base1 = rnd.getUint32();
718 const int adj0 = rnd.getInt(0, 20);
719 const int adj1 = rnd.getInt(0, 20);
720 in0[valueNdx*scalarSize + compNdx] = base0 >> adj0;
721 in1[valueNdx*scalarSize + compNdx] = base1 >> adj1;
722 }
723
724 valueNdx += 1;
725 }
726 }
727
compare(const void * const * inputs,const void * const * outputs)728 bool compare (const void* const* inputs, const void* const* outputs)
729 {
730 const glu::DataType type = m_spec.inputs[0].varType.getBasicType();
731 const int scalarSize = glu::getDataTypeScalarSize(type);
732
733 for (int compNdx = 0; compNdx < scalarSize; compNdx++)
734 {
735 const deUint32 in0 = ((const deUint32*)inputs[0])[compNdx];
736 const deUint32 in1 = ((const deUint32*)inputs[1])[compNdx];
737 const deUint32 out0 = ((const deUint32*)outputs[0])[compNdx];
738 const deUint32 out1 = ((const deUint32*)outputs[1])[compNdx];
739 const deUint64 mul64 = deUint64(in0)*deUint64(in1);
740 const deUint32 ref0 = deUint32(mul64 >> 32);
741 const deUint32 ref1 = deUint32(mul64 & 0xffffffffu);
742
743 if (out0 != ref0 || out1 != ref1)
744 {
745 m_failMsg << "Expected [" << compNdx << "] = " << tcu::toHex(ref0) << ", " << tcu::toHex(ref1);
746 return false;
747 }
748 }
749
750 return true;
751 }
752 };
753
754 class UmulExtendedCase : public IntegerFunctionCase
755 {
756 public:
UmulExtendedCase(tcu::TestContext & testCtx,glu::DataType baseType,glu::Precision precision,glu::ShaderType shaderType)757 UmulExtendedCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
758 : IntegerFunctionCase (testCtx, getIntegerFuncCaseName(baseType, precision, shaderType).c_str(), "umulExtended", shaderType)
759 {
760 m_spec.inputs.push_back(Symbol("x", glu::VarType(baseType, precision)));
761 m_spec.inputs.push_back(Symbol("y", glu::VarType(baseType, precision)));
762 m_spec.outputs.push_back(Symbol("msb", glu::VarType(baseType, precision)));
763 m_spec.outputs.push_back(Symbol("lsb", glu::VarType(baseType, precision)));
764 m_spec.source = "umulExtended(x, y, msb, lsb);";
765 }
766
createInstance(Context & ctx) const767 TestInstance* createInstance (Context& ctx) const
768 {
769 return new UmulExtendedCaseInstance(ctx, m_shaderType, m_spec, m_numValues, getName());
770 }
771 };
772
773 class ImulExtendedCaseInstance : public IntegerFunctionTestInstance
774 {
775 public:
ImulExtendedCaseInstance(Context & context,glu::ShaderType shaderType,const ShaderSpec & spec,int numValues,const char * name)776 ImulExtendedCaseInstance (Context& context, glu::ShaderType shaderType, const ShaderSpec& spec, int numValues, const char* name)
777 : IntegerFunctionTestInstance (context, shaderType, spec, numValues, name)
778 {
779 }
780
getInputValues(int numValues,void * const * values) const781 void getInputValues (int numValues, void* const* values) const
782 {
783 de::Random rnd (deStringHash(m_name) ^ 0x224fa1u);
784 const glu::DataType type = m_spec.inputs[0].varType.getBasicType();
785 // const glu::Precision precision = m_spec.inputs[0].varType.getPrecision();
786 const int scalarSize = glu::getDataTypeScalarSize(type);
787 deUint32* in0 = (deUint32*)values[0];
788 deUint32* in1 = (deUint32*)values[1];
789 int valueNdx = 0;
790
791 const struct
792 {
793 deUint32 x;
794 deUint32 y;
795 } easyCases[] =
796 {
797 { 0x00000000u, 0x00000000u },
798 { 0xffffffffu, 0x00000002u },
799 { 0x7fffffffu, 0x00000001u },
800 { 0x7fffffffu, 0x00000002u },
801 { 0x7fffffffu, 0x7fffffffu },
802 { 0xffffffffu, 0xffffffffu },
803 { 0x7fffffffu, 0xfffffffeu },
804 };
805
806 for (int easyCaseNdx = 0; easyCaseNdx < DE_LENGTH_OF_ARRAY(easyCases); easyCaseNdx++)
807 {
808 for (int compNdx = 0; compNdx < scalarSize; compNdx++)
809 {
810 in0[valueNdx*scalarSize + compNdx] = (deInt32)easyCases[easyCaseNdx].x;
811 in1[valueNdx*scalarSize + compNdx] = (deInt32)easyCases[easyCaseNdx].y;
812 }
813
814 valueNdx += 1;
815 }
816
817 while (valueNdx < numValues)
818 {
819 for (int compNdx = 0; compNdx < scalarSize; compNdx++)
820 {
821 const deInt32 base0 = (deInt32)rnd.getUint32();
822 const deInt32 base1 = (deInt32)rnd.getUint32();
823 const int adj0 = rnd.getInt(0, 20);
824 const int adj1 = rnd.getInt(0, 20);
825 in0[valueNdx*scalarSize + compNdx] = base0 >> adj0;
826 in1[valueNdx*scalarSize + compNdx] = base1 >> adj1;
827 }
828
829 valueNdx += 1;
830 }
831 }
832
compare(const void * const * inputs,const void * const * outputs)833 bool compare (const void* const* inputs, const void* const* outputs)
834 {
835 const glu::DataType type = m_spec.inputs[0].varType.getBasicType();
836 const int scalarSize = glu::getDataTypeScalarSize(type);
837
838 for (int compNdx = 0; compNdx < scalarSize; compNdx++)
839 {
840 const deInt32 in0 = ((const deInt32*)inputs[0])[compNdx];
841 const deInt32 in1 = ((const deInt32*)inputs[1])[compNdx];
842 const deInt32 out0 = ((const deInt32*)outputs[0])[compNdx];
843 const deInt32 out1 = ((const deInt32*)outputs[1])[compNdx];
844 const deInt64 mul64 = deInt64(in0)*deInt64(in1);
845 const deInt32 ref0 = deInt32(mul64 >> 32);
846 const deInt32 ref1 = deInt32(mul64 & 0xffffffffu);
847
848 if (out0 != ref0 || out1 != ref1)
849 {
850 m_failMsg << "Expected [" << compNdx << "] = " << tcu::toHex(ref0) << ", " << tcu::toHex(ref1);
851 return false;
852 }
853 }
854
855 return true;
856 }
857 };
858
859 class ImulExtendedCase : public IntegerFunctionCase
860 {
861 public:
ImulExtendedCase(tcu::TestContext & testCtx,glu::DataType baseType,glu::Precision precision,glu::ShaderType shaderType)862 ImulExtendedCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
863 : IntegerFunctionCase (testCtx, getIntegerFuncCaseName(baseType, precision, shaderType).c_str(), "imulExtended", shaderType)
864 {
865 m_spec.inputs.push_back(Symbol("x", glu::VarType(baseType, precision)));
866 m_spec.inputs.push_back(Symbol("y", glu::VarType(baseType, precision)));
867 m_spec.outputs.push_back(Symbol("msb", glu::VarType(baseType, precision)));
868 m_spec.outputs.push_back(Symbol("lsb", glu::VarType(baseType, precision)));
869 m_spec.source = "imulExtended(x, y, msb, lsb);";
870 }
871
createInstance(Context & ctx) const872 TestInstance* createInstance (Context& ctx) const
873 {
874 return new ImulExtendedCaseInstance(ctx, m_shaderType, m_spec, m_numValues, getName());
875 }
876 };
877
878 class BitfieldExtractCaseInstance : public IntegerFunctionTestInstance
879 {
880 public:
BitfieldExtractCaseInstance(Context & context,glu::ShaderType shaderType,const ShaderSpec & spec,int numValues,const char * name)881 BitfieldExtractCaseInstance (Context& context, glu::ShaderType shaderType, const ShaderSpec& spec, int numValues, const char* name)
882 : IntegerFunctionTestInstance (context, shaderType, spec, numValues, name)
883 {
884 }
885
getInputValues(int numValues,void * const * values) const886 void getInputValues (int numValues, void* const* values) const
887 {
888 de::Random rnd (deStringHash(m_name) ^ 0xa113fca2u);
889 const glu::DataType type = m_spec.inputs[0].varType.getBasicType();
890 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision();
891 const bool ignoreSign = precision != glu::PRECISION_HIGHP && glu::isDataTypeIntOrIVec(type);
892 const int numBits = getShaderUintBitCount(m_shaderType, precision) - (ignoreSign ? 1 : 0);
893 deUint32* inValue = (deUint32*)values[0];
894 int* inOffset = (int*)values[1];
895 int* inBits = (int*)values[2];
896
897 for (int valueNdx = 0; valueNdx < numValues; ++valueNdx)
898 {
899 const int bits = rnd.getInt(0, numBits);
900 const int offset = rnd.getInt(0, numBits-bits);
901
902 inOffset[valueNdx] = offset;
903 inBits[valueNdx] = bits;
904 }
905
906 generateRandomInputData(rnd, m_shaderType, type, precision, inValue, numValues);
907 }
908
compare(const void * const * inputs,const void * const * outputs)909 bool compare (const void* const* inputs, const void* const* outputs)
910 {
911 const glu::DataType type = m_spec.inputs[0].varType.getBasicType();
912 const bool isSigned = glu::isDataTypeIntOrIVec(type);
913 const int scalarSize = glu::getDataTypeScalarSize(type);
914 const int offset = *((const int*)inputs[1]);
915 const int bits = *((const int*)inputs[2]);
916
917 for (int compNdx = 0; compNdx < scalarSize; compNdx++)
918 {
919 const deUint32 value = ((const deUint32*)inputs[0])[compNdx];
920 const deUint32 out = ((const deUint32*)outputs[0])[compNdx];
921 const deUint32 valMask = (bits == 32 ? ~0u : ((1u<<bits)-1u));
922 const deUint32 baseVal = (offset == 32) ? (0) : ((value >> offset) & valMask);
923 const deUint32 ref = baseVal | ((isSigned && (baseVal & (1<<(bits-1)))) ? ~valMask : 0u);
924
925 if (out != ref)
926 {
927 m_failMsg << "Expected [" << compNdx << "] = " << tcu::toHex(ref);
928 return false;
929 }
930 }
931
932 return true;
933 }
934 };
935
936 class BitfieldExtractCase : public IntegerFunctionCase
937 {
938 public:
BitfieldExtractCase(tcu::TestContext & testCtx,glu::DataType baseType,glu::Precision precision,glu::ShaderType shaderType)939 BitfieldExtractCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
940 : IntegerFunctionCase (testCtx, getIntegerFuncCaseName(baseType, precision, shaderType).c_str(), "bitfieldExtract", shaderType)
941 {
942 m_spec.inputs.push_back(Symbol("value", glu::VarType(baseType, precision)));
943 m_spec.inputs.push_back(Symbol("offset", glu::VarType(glu::TYPE_INT, precision)));
944 m_spec.inputs.push_back(Symbol("bits", glu::VarType(glu::TYPE_INT, precision)));
945 m_spec.outputs.push_back(Symbol("extracted", glu::VarType(baseType, precision)));
946 m_spec.source = "extracted = bitfieldExtract(value, offset, bits);";
947 }
948
createInstance(Context & ctx) const949 TestInstance* createInstance (Context& ctx) const
950 {
951 return new BitfieldExtractCaseInstance(ctx, m_shaderType, m_spec, m_numValues, getName());
952 }
953 };
954
955 class BitfieldInsertCaseInstance : public IntegerFunctionTestInstance
956 {
957 public:
BitfieldInsertCaseInstance(Context & context,glu::ShaderType shaderType,const ShaderSpec & spec,int numValues,const char * name)958 BitfieldInsertCaseInstance (Context& context, glu::ShaderType shaderType, const ShaderSpec& spec, int numValues, const char* name)
959 : IntegerFunctionTestInstance (context, shaderType, spec, numValues, name)
960 {
961 }
962
getInputValues(int numValues,void * const * values) const963 void getInputValues (int numValues, void* const* values) const
964 {
965 de::Random rnd (deStringHash(m_name) ^ 0x12c2acff);
966 const glu::DataType type = m_spec.inputs[0].varType.getBasicType();
967 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision();
968 const int numBits = getShaderUintBitCount(m_shaderType, precision);
969 deUint32* inBase = (deUint32*)values[0];
970 deUint32* inInsert = (deUint32*)values[1];
971 int* inOffset = (int*)values[2];
972 int* inBits = (int*)values[3];
973
974 for (int valueNdx = 0; valueNdx < numValues; ++valueNdx)
975 {
976 const int bits = rnd.getInt(0, numBits);
977 const int offset = rnd.getInt(0, numBits-bits);
978
979 inOffset[valueNdx] = offset;
980 inBits[valueNdx] = bits;
981 }
982
983 generateRandomInputData(rnd, m_shaderType, type, precision, inBase, numValues);
984 generateRandomInputData(rnd, m_shaderType, type, precision, inInsert, numValues);
985 }
986
compare(const void * const * inputs,const void * const * outputs)987 bool compare (const void* const* inputs, const void* const* outputs)
988 {
989 const glu::DataType type = m_spec.inputs[0].varType.getBasicType();
990 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision();
991 const int scalarSize = glu::getDataTypeScalarSize(type);
992 const int integerLength = getShaderUintBitCount(m_shaderType, precision);
993 const deUint32 cmpMask = getLowBitMask(integerLength);
994 const int offset = *((const int*)inputs[2]);
995 const int bits = *((const int*)inputs[3]);
996
997 for (int compNdx = 0; compNdx < scalarSize; compNdx++)
998 {
999 const deUint32 base = ((const deUint32*)inputs[0])[compNdx];
1000 const deUint32 insert = ((const deUint32*)inputs[1])[compNdx];
1001 const deInt32 out = ((const deUint32*)outputs[0])[compNdx];
1002
1003 const deUint32 mask = bits == 32 ? ~0u : (1u<<bits)-1;
1004 const deUint32 ref = (base & ~(mask<<offset)) | ((insert & mask)<<offset);
1005
1006 if ((out&cmpMask) != (ref&cmpMask))
1007 {
1008 m_failMsg << "Expected [" << compNdx << "] = " << tcu::toHex(ref);
1009 return false;
1010 }
1011 }
1012
1013 return true;
1014 }
1015 };
1016
1017 class BitfieldInsertCase : public IntegerFunctionCase
1018 {
1019 public:
BitfieldInsertCase(tcu::TestContext & testCtx,glu::DataType baseType,glu::Precision precision,glu::ShaderType shaderType)1020 BitfieldInsertCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
1021 : IntegerFunctionCase (testCtx, getIntegerFuncCaseName(baseType, precision, shaderType).c_str(), "bitfieldInsert", shaderType)
1022 {
1023 m_spec.inputs.push_back(Symbol("base", glu::VarType(baseType, precision)));
1024 m_spec.inputs.push_back(Symbol("insert", glu::VarType(baseType, precision)));
1025 m_spec.inputs.push_back(Symbol("offset", glu::VarType(glu::TYPE_INT, precision)));
1026 m_spec.inputs.push_back(Symbol("bits", glu::VarType(glu::TYPE_INT, precision)));
1027 m_spec.outputs.push_back(Symbol("result", glu::VarType(baseType, precision)));
1028 m_spec.source = "result = bitfieldInsert(base, insert, offset, bits);";
1029 }
1030
createInstance(Context & ctx) const1031 TestInstance* createInstance (Context& ctx) const
1032 {
1033 return new BitfieldInsertCaseInstance(ctx, m_shaderType, m_spec, m_numValues, getName());
1034 }
1035 };
1036
1037 class BitfieldReverseCaseInstance : public IntegerFunctionTestInstance
1038 {
1039 public:
BitfieldReverseCaseInstance(Context & context,glu::ShaderType shaderType,const ShaderSpec & spec,int numValues,const char * name)1040 BitfieldReverseCaseInstance (Context& context, glu::ShaderType shaderType, const ShaderSpec& spec, int numValues, const char* name)
1041 : IntegerFunctionTestInstance (context, shaderType, spec, numValues, name)
1042 {
1043 }
1044
getInputValues(int numValues,void * const * values) const1045 void getInputValues (int numValues, void* const* values) const
1046 {
1047 de::Random rnd (deStringHash(m_name) ^ 0xff23a4);
1048 const glu::DataType type = m_spec.inputs[0].varType.getBasicType();
1049 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision();
1050 deUint32* inValue = (deUint32*)values[0];
1051
1052 generateRandomInputData(rnd, m_shaderType, type, precision, inValue, numValues);
1053 }
1054
compare(const void * const * inputs,const void * const * outputs)1055 bool compare (const void* const* inputs, const void* const* outputs)
1056 {
1057 const glu::DataType type = m_spec.inputs[0].varType.getBasicType();
1058 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision();
1059 const int integerLength = getShaderUintBitCount(m_shaderType, precision);
1060 const int scalarSize = glu::getDataTypeScalarSize(type);
1061 const deUint32 cmpMask = reverseBits(getLowBitMask(integerLength));
1062
1063 for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1064 {
1065 const deUint32 value = ((const deUint32*)inputs[0])[compNdx];
1066 const deInt32 out = ((const deUint32*)outputs[0])[compNdx];
1067 const deUint32 ref = reverseBits(value);
1068
1069 if ((out&cmpMask) != (ref&cmpMask))
1070 {
1071 m_failMsg << "Expected [" << compNdx << "] = " << tcu::toHex(ref);
1072 return false;
1073 }
1074 }
1075
1076 return true;
1077 }
1078 };
1079
1080 class BitfieldReverseCase : public IntegerFunctionCase
1081 {
1082 public:
BitfieldReverseCase(tcu::TestContext & testCtx,glu::DataType baseType,glu::Precision precision,glu::ShaderType shaderType)1083 BitfieldReverseCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
1084 : IntegerFunctionCase (testCtx, getIntegerFuncCaseName(baseType, precision, shaderType).c_str(), "bitfieldReverse", shaderType)
1085 {
1086 m_spec.inputs.push_back(Symbol("value", glu::VarType(baseType, precision)));
1087 m_spec.outputs.push_back(Symbol("result", glu::VarType(baseType, glu::PRECISION_HIGHP)));
1088 m_spec.source = "result = bitfieldReverse(value);";
1089 }
1090
createInstance(Context & ctx) const1091 TestInstance* createInstance (Context& ctx) const
1092 {
1093 return new BitfieldReverseCaseInstance(ctx, m_shaderType, m_spec, m_numValues, getName());
1094 }
1095 };
1096
1097 class BitCountCaseInstance : public IntegerFunctionTestInstance
1098 {
1099 public:
BitCountCaseInstance(Context & context,glu::ShaderType shaderType,const ShaderSpec & spec,int numValues,const char * name)1100 BitCountCaseInstance (Context& context, glu::ShaderType shaderType, const ShaderSpec& spec, int numValues, const char* name)
1101 : IntegerFunctionTestInstance (context, shaderType, spec, numValues, name)
1102 {
1103 }
1104
getInputValues(int numValues,void * const * values) const1105 void getInputValues (int numValues, void* const* values) const
1106 {
1107 de::Random rnd (deStringHash(m_name) ^ 0xab2cca4);
1108 const glu::DataType type = m_spec.inputs[0].varType.getBasicType();
1109 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision();
1110 deUint32* inValue = (deUint32*)values[0];
1111
1112 generateRandomInputData(rnd, m_shaderType, type, precision, inValue, numValues);
1113 }
1114
compare(const void * const * inputs,const void * const * outputs)1115 bool compare (const void* const* inputs, const void* const* outputs)
1116 {
1117 const glu::DataType type = m_spec.inputs[0].varType.getBasicType();
1118 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision();
1119 const int integerLength = getShaderUintBitCount(m_shaderType, precision);
1120 const int scalarSize = glu::getDataTypeScalarSize(type);
1121 const deUint32 countMask = getLowBitMask(integerLength);
1122
1123 for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1124 {
1125 const deUint32 value = ((const deUint32*)inputs[0])[compNdx];
1126 const int out = ((const int*)outputs[0])[compNdx];
1127 const int minRef = dePop32(value&countMask);
1128 const int maxRef = dePop32(value);
1129
1130 if (!de::inRange(out, minRef, maxRef))
1131 {
1132 m_failMsg << "Expected [" << compNdx << "] in range [" << minRef << ", " << maxRef << "]";
1133 return false;
1134 }
1135 }
1136
1137 return true;
1138 }
1139 };
1140
1141 class BitCountCase : public IntegerFunctionCase
1142 {
1143 public:
BitCountCase(tcu::TestContext & testCtx,glu::DataType baseType,glu::Precision precision,glu::ShaderType shaderType)1144 BitCountCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
1145 : IntegerFunctionCase (testCtx, getIntegerFuncCaseName(baseType, precision, shaderType).c_str(), "bitCount", shaderType)
1146 {
1147 const int vecSize = glu::getDataTypeScalarSize(baseType);
1148 const glu::DataType intType = vecSize == 1 ? glu::TYPE_INT : glu::getDataTypeIntVec(vecSize);
1149
1150 m_spec.inputs.push_back(Symbol("value", glu::VarType(baseType, precision)));
1151 m_spec.outputs.push_back(Symbol("count", glu::VarType(intType, glu::PRECISION_MEDIUMP)));
1152 m_spec.source = "count = bitCount(value);";
1153 }
1154
createInstance(Context & ctx) const1155 TestInstance* createInstance (Context& ctx) const
1156 {
1157 return new BitCountCaseInstance(ctx, m_shaderType, m_spec, m_numValues, getName());
1158 }
1159 };
1160
1161 class FindLSBCaseInstance : public IntegerFunctionTestInstance
1162 {
1163 public:
FindLSBCaseInstance(Context & context,glu::ShaderType shaderType,const ShaderSpec & spec,int numValues,const char * name)1164 FindLSBCaseInstance (Context& context, glu::ShaderType shaderType, const ShaderSpec& spec, int numValues, const char* name)
1165 : IntegerFunctionTestInstance (context, shaderType, spec, numValues, name)
1166 {
1167 }
1168
getInputValues(int numValues,void * const * values) const1169 void getInputValues (int numValues, void* const* values) const
1170 {
1171 de::Random rnd (deStringHash(m_name) ^ 0x9923c2af);
1172 const glu::DataType type = m_spec.inputs[0].varType.getBasicType();
1173 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision();
1174 deUint32* inValue = (deUint32*)values[0];
1175
1176 generateRandomInputData(rnd, m_shaderType, type, precision, inValue, numValues);
1177 }
1178
compare(const void * const * inputs,const void * const * outputs)1179 bool compare (const void* const* inputs, const void* const* outputs)
1180 {
1181 const glu::DataType type = m_spec.inputs[0].varType.getBasicType();
1182 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision();
1183 const int scalarSize = glu::getDataTypeScalarSize(type);
1184 const int integerLength = getShaderUintBitCount(m_shaderType, precision);
1185 const deUint32 mask = getLowBitMask(integerLength);
1186
1187 for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1188 {
1189 const deUint32 value = ((const deUint32*)inputs[0])[compNdx];
1190 const int out = ((const int*)outputs[0])[compNdx];
1191 const int minRef = findLSB(value&mask);
1192 const int maxRef = findLSB(value);
1193
1194 if (!de::inRange(out, minRef, maxRef))
1195 {
1196 m_failMsg << "Expected [" << compNdx << "] in range [" << minRef << ", " << maxRef << "]";
1197 return false;
1198 }
1199 }
1200
1201 return true;
1202 }
1203 };
1204
1205 class FindLSBCase : public IntegerFunctionCase
1206 {
1207 public:
FindLSBCase(tcu::TestContext & testCtx,glu::DataType baseType,glu::Precision precision,glu::ShaderType shaderType)1208 FindLSBCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
1209 : IntegerFunctionCase (testCtx, getIntegerFuncCaseName(baseType, precision, shaderType).c_str(), "findLSB", shaderType)
1210 {
1211 const int vecSize = glu::getDataTypeScalarSize(baseType);
1212 const glu::DataType intType = vecSize == 1 ? glu::TYPE_INT : glu::getDataTypeIntVec(vecSize);
1213
1214 m_spec.inputs.push_back(Symbol("value", glu::VarType(baseType, precision)));
1215 m_spec.outputs.push_back(Symbol("lsb", glu::VarType(intType, glu::PRECISION_LOWP)));
1216 m_spec.source = "lsb = findLSB(value);";
1217 }
1218
createInstance(Context & ctx) const1219 TestInstance* createInstance (Context& ctx) const
1220 {
1221 return new FindLSBCaseInstance(ctx, m_shaderType, m_spec, m_numValues, getName());
1222 }
1223 };
1224
1225 class findMSBCaseInstance : public IntegerFunctionTestInstance
1226 {
1227 public:
findMSBCaseInstance(Context & context,glu::ShaderType shaderType,const ShaderSpec & spec,int numValues,const char * name)1228 findMSBCaseInstance (Context& context, glu::ShaderType shaderType, const ShaderSpec& spec, int numValues, const char* name)
1229 : IntegerFunctionTestInstance (context, shaderType, spec, numValues, name)
1230 {
1231 }
1232
getInputValues(int numValues,void * const * values) const1233 void getInputValues (int numValues, void* const* values) const
1234 {
1235 de::Random rnd (deStringHash(m_name) ^ 0x742ac4e);
1236 const glu::DataType type = m_spec.inputs[0].varType.getBasicType();
1237 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision();
1238 deUint32* inValue = (deUint32*)values[0];
1239
1240 generateRandomInputData(rnd, m_shaderType, type, precision, inValue, numValues);
1241 }
1242
compare(const void * const * inputs,const void * const * outputs)1243 bool compare (const void* const* inputs, const void* const* outputs)
1244 {
1245 const glu::DataType type = m_spec.inputs[0].varType.getBasicType();
1246 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision();
1247 const bool isSigned = glu::isDataTypeIntOrIVec(type);
1248 const int scalarSize = glu::getDataTypeScalarSize(type);
1249 const int integerLength = getShaderUintBitCount(m_shaderType, precision);
1250
1251 for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1252 {
1253 const deUint32 value = ((const deUint32*)inputs[0])[compNdx];
1254 const int out = ((const deInt32*)outputs[0])[compNdx];
1255 const int minRef = isSigned ? findMSB(toPrecision(deInt32(value), integerLength)) : findMSB(toPrecision(value, integerLength));
1256 const int maxRef = isSigned ? findMSB(deInt32(value)) : findMSB(value);
1257
1258 if (!de::inRange(out, minRef, maxRef))
1259 {
1260 m_failMsg << "Expected [" << compNdx << "] in range [" << minRef << ", " << maxRef << "]";
1261 return false;
1262 }
1263 }
1264
1265 return true;
1266 }
1267 };
1268
1269 class findMSBCase : public IntegerFunctionCase
1270 {
1271 public:
findMSBCase(tcu::TestContext & testCtx,glu::DataType baseType,glu::Precision precision,glu::ShaderType shaderType)1272 findMSBCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
1273 : IntegerFunctionCase (testCtx, getIntegerFuncCaseName(baseType, precision, shaderType).c_str(), "findMSB", shaderType)
1274 {
1275 const int vecSize = glu::getDataTypeScalarSize(baseType);
1276 const glu::DataType intType = vecSize == 1 ? glu::TYPE_INT : glu::getDataTypeIntVec(vecSize);
1277
1278 m_spec.inputs.push_back(Symbol("value", glu::VarType(baseType, precision)));
1279 m_spec.outputs.push_back(Symbol("msb", glu::VarType(intType, glu::PRECISION_LOWP)));
1280 m_spec.source = "msb = findMSB(value);";
1281 }
1282
createInstance(Context & ctx) const1283 TestInstance* createInstance (Context& ctx) const
1284 {
1285 return new findMSBCaseInstance(ctx, m_shaderType, m_spec, m_numValues, getName());
1286 }
1287 };
1288
ShaderIntegerFunctionTests(tcu::TestContext & testCtx)1289 ShaderIntegerFunctionTests::ShaderIntegerFunctionTests (tcu::TestContext& testCtx)
1290 : tcu::TestCaseGroup (testCtx, "integer", "Integer function tests")
1291 {
1292 }
1293
~ShaderIntegerFunctionTests(void)1294 ShaderIntegerFunctionTests::~ShaderIntegerFunctionTests (void)
1295 {
1296 }
1297
init(void)1298 void ShaderIntegerFunctionTests::init (void)
1299 {
1300 enum
1301 {
1302 VS = (1<<glu::SHADERTYPE_VERTEX),
1303 FS = (1<<glu::SHADERTYPE_FRAGMENT),
1304 CS = (1<<glu::SHADERTYPE_COMPUTE),
1305 GS = (1<<glu::SHADERTYPE_GEOMETRY),
1306 TC = (1<<glu::SHADERTYPE_TESSELLATION_CONTROL),
1307 TE = (1<<glu::SHADERTYPE_TESSELLATION_EVALUATION),
1308
1309 ALL_SHADERS = VS|TC|TE|GS|FS|CS
1310 };
1311
1312 // Int? Uint? AllPrec? Shaders
1313 addFunctionCases<UaddCarryCase> (this, "uaddcarry", false, true, true, ALL_SHADERS);
1314 addFunctionCases<UsubBorrowCase> (this, "usubborrow", false, true, true, ALL_SHADERS);
1315 addFunctionCases<UmulExtendedCase> (this, "umulextended", false, true, false, ALL_SHADERS);
1316 addFunctionCases<ImulExtendedCase> (this, "imulextended", true, false, false, ALL_SHADERS);
1317 addFunctionCases<BitfieldExtractCase> (this, "bitfieldextract", true, true, true, ALL_SHADERS);
1318 addFunctionCases<BitfieldInsertCase> (this, "bitfieldinsert", true, true, true, ALL_SHADERS);
1319 addFunctionCases<BitfieldReverseCase> (this, "bitfieldreverse", true, true, true, ALL_SHADERS);
1320 addFunctionCases<BitCountCase> (this, "bitcount", true, true, true, ALL_SHADERS);
1321 addFunctionCases<FindLSBCase> (this, "findlsb", true, true, true, ALL_SHADERS);
1322 addFunctionCases<findMSBCase> (this, "findMSB", true, true, true, ALL_SHADERS);
1323 }
1324
1325 } // shaderexecutor
1326 } // vkt
1327