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 39namespace vkt 40{ 41namespace shaderexecutor 42{ 43 44using std::vector; 45using std::string; 46using tcu::TestLog; 47 48using tcu::IVec2; 49using tcu::IVec3; 50using tcu::IVec4; 51using tcu::UVec2; 52using tcu::UVec3; 53using tcu::UVec4; 54 55// Utilities 56 57namespace 58{ 59 60struct HexFloat 61{ 62 const float value; 63 HexFloat (const float value_) : value(value_) {} 64}; 65 66std::ostream& operator<< (std::ostream& str, const HexFloat& v) 67{ 68 return str << v.value << " / " << tcu::toHex(tcu::Float32(v.value).bits()); 69} 70 71struct VarValue 72{ 73 const glu::VarType& type; 74 const void* value; 75 76 VarValue (const glu::VarType& type_, const void* value_) : type(type_), value(value_) {} 77}; 78 79std::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 113inline 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 122static 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 129static 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 139static 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 160static 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 168static 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 176static 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 196static 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 209static 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 224static 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 229static 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 238static 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 248static 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 258static int findMSB (deUint32 value) 259{ 260 if (value > 0) 261 return 31 - deClz32(value); 262 else 263 return -1; 264} 265 266static deUint32 toPrecision (deUint32 value, int numIntegerBits) 267{ 268 return value & getLowBitMask(numIntegerBits); 269} 270 271static deInt32 toPrecision (deInt32 value, int numIntegerBits) 272{ 273 return (deInt32)extendSignTo32((deUint32)value & getLowBitMask(numIntegerBits), numIntegerBits); 274} 275 276template<class TestClass> 277static 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 316class IntegerFunctionCase : public TestCase 317{ 318public: 319 IntegerFunctionCase (tcu::TestContext& testCtx, const char* name, const char* description, glu::ShaderType shaderType); 320 ~IntegerFunctionCase (void); 321 322 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 329protected: 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 340IntegerFunctionCase::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 347IntegerFunctionCase::~IntegerFunctionCase (void) 348{ 349} 350 351// IntegerFunctionTestInstance 352 353class IntegerFunctionTestInstance : public TestInstance 354{ 355public: 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); 366protected: 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 384tcu::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 451class UaddCarryCaseInstance : public IntegerFunctionTestInstance 452{ 453public: 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 459 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 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 542class UaddCarryCase : public IntegerFunctionCase 543{ 544public: 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 555 TestInstance* createInstance (Context& ctx) const 556 { 557 return new UaddCarryCaseInstance(ctx, m_shaderType, m_spec, m_numValues, getName()); 558 } 559}; 560 561class UsubBorrowCaseInstance : public IntegerFunctionTestInstance 562{ 563public: 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 569 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 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 650class UsubBorrowCase : public IntegerFunctionCase 651{ 652public: 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 663 TestInstance* createInstance (Context& ctx) const 664 { 665 return new UsubBorrowCaseInstance(ctx, m_shaderType, m_spec, m_numValues, getName()); 666 } 667}; 668 669class UmulExtendedCaseInstance : public IntegerFunctionTestInstance 670{ 671public: 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 677 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 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 754class UmulExtendedCase : public IntegerFunctionCase 755{ 756public: 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 767 TestInstance* createInstance (Context& ctx) const 768 { 769 return new UmulExtendedCaseInstance(ctx, m_shaderType, m_spec, m_numValues, getName()); 770 } 771}; 772 773class ImulExtendedCaseInstance : public IntegerFunctionTestInstance 774{ 775public: 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 781 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 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 859class ImulExtendedCase : public IntegerFunctionCase 860{ 861public: 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 872 TestInstance* createInstance (Context& ctx) const 873 { 874 return new ImulExtendedCaseInstance(ctx, m_shaderType, m_spec, m_numValues, getName()); 875 } 876}; 877 878class BitfieldExtractCaseInstance : public IntegerFunctionTestInstance 879{ 880public: 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 886 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 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 936class BitfieldExtractCase : public IntegerFunctionCase 937{ 938public: 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 949 TestInstance* createInstance (Context& ctx) const 950 { 951 return new BitfieldExtractCaseInstance(ctx, m_shaderType, m_spec, m_numValues, getName()); 952 } 953}; 954 955class BitfieldInsertCaseInstance : public IntegerFunctionTestInstance 956{ 957public: 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 963 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 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 1017class BitfieldInsertCase : public IntegerFunctionCase 1018{ 1019public: 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 1031 TestInstance* createInstance (Context& ctx) const 1032 { 1033 return new BitfieldInsertCaseInstance(ctx, m_shaderType, m_spec, m_numValues, getName()); 1034 } 1035}; 1036 1037class BitfieldReverseCaseInstance : public IntegerFunctionTestInstance 1038{ 1039public: 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 1045 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 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 1080class BitfieldReverseCase : public IntegerFunctionCase 1081{ 1082public: 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 1091 TestInstance* createInstance (Context& ctx) const 1092 { 1093 return new BitfieldReverseCaseInstance(ctx, m_shaderType, m_spec, m_numValues, getName()); 1094 } 1095}; 1096 1097class BitCountCaseInstance : public IntegerFunctionTestInstance 1098{ 1099public: 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 1105 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 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 1141class BitCountCase : public IntegerFunctionCase 1142{ 1143public: 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 1155 TestInstance* createInstance (Context& ctx) const 1156 { 1157 return new BitCountCaseInstance(ctx, m_shaderType, m_spec, m_numValues, getName()); 1158 } 1159}; 1160 1161class FindLSBCaseInstance : public IntegerFunctionTestInstance 1162{ 1163public: 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 1169 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 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 1205class FindLSBCase : public IntegerFunctionCase 1206{ 1207public: 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 1219 TestInstance* createInstance (Context& ctx) const 1220 { 1221 return new FindLSBCaseInstance(ctx, m_shaderType, m_spec, m_numValues, getName()); 1222 } 1223}; 1224 1225class findMSBCaseInstance : public IntegerFunctionTestInstance 1226{ 1227public: 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 1233 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 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 1269class findMSBCase : public IntegerFunctionCase 1270{ 1271public: 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 1283 TestInstance* createInstance (Context& ctx) const 1284 { 1285 return new findMSBCaseInstance(ctx, m_shaderType, m_spec, m_numValues, getName()); 1286 } 1287}; 1288 1289ShaderIntegerFunctionTests::ShaderIntegerFunctionTests (tcu::TestContext& testCtx) 1290 : tcu::TestCaseGroup (testCtx, "integer", "Integer function tests") 1291{ 1292} 1293 1294ShaderIntegerFunctionTests::~ShaderIntegerFunctionTests (void) 1295{ 1296} 1297 1298void 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