1/*------------------------------------------------------------------------- 2 * drawElements Quality Program OpenGL ES 3.0 Module 3 * ------------------------------------------------- 4 * 5 * Copyright 2014 The Android Open Source Project 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License"); 8 * you may not use this file except in compliance with the License. 9 * You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 * 19 *//*! 20 * \file 21 * \brief Common built-in function tests. 22 *//*--------------------------------------------------------------------*/ 23 24#include "es3fShaderCommonFunctionTests.hpp" 25#include "glsShaderExecUtil.hpp" 26#include "tcuTestLog.hpp" 27#include "tcuFormatUtil.hpp" 28#include "tcuFloat.hpp" 29#include "deRandom.hpp" 30#include "deMath.h" 31#include "deString.h" 32 33namespace deqp 34{ 35namespace gles3 36{ 37namespace Functional 38{ 39 40using std::vector; 41using std::string; 42using tcu::TestLog; 43using namespace gls::ShaderExecUtil; 44 45using tcu::Vec2; 46using tcu::Vec3; 47using tcu::Vec4; 48using tcu::IVec2; 49using tcu::IVec3; 50using tcu::IVec4; 51 52// Utilities 53 54template<typename T, int Size> 55struct VecArrayAccess 56{ 57public: 58 VecArrayAccess (const void* ptr) : m_array((tcu::Vector<T, Size>*)ptr) {} 59 ~VecArrayAccess (void) {} 60 61 const tcu::Vector<T, Size>& operator[] (size_t offset) const { return m_array[offset]; } 62 tcu::Vector<T, Size>& operator[] (size_t offset) { return m_array[offset]; } 63 64private: 65 tcu::Vector<T, Size>* m_array; 66}; 67 68template<typename T> T randomScalar (de::Random& rnd, T minValue, T maxValue); 69template<> inline float randomScalar (de::Random& rnd, float minValue, float maxValue) { return rnd.getFloat(minValue, maxValue); } 70template<> inline deInt32 randomScalar (de::Random& rnd, deInt32 minValue, deInt32 maxValue) { return rnd.getInt(minValue, maxValue); } 71template<> inline deUint32 randomScalar (de::Random& rnd, deUint32 minValue, deUint32 maxValue) { return minValue + rnd.getUint32() % (maxValue - minValue + 1); } 72 73template<typename T, int Size> 74inline tcu::Vector<T, Size> randomVector (de::Random& rnd, const tcu::Vector<T, Size>& minValue, const tcu::Vector<T, Size>& maxValue) 75{ 76 tcu::Vector<T, Size> res; 77 for (int ndx = 0; ndx < Size; ndx++) 78 res[ndx] = randomScalar<T>(rnd, minValue[ndx], maxValue[ndx]); 79 return res; 80} 81 82template<typename T, int Size> 83static void fillRandomVectors (de::Random& rnd, const tcu::Vector<T, Size>& minValue, const tcu::Vector<T, Size>& maxValue, void* dst, int numValues, int offset = 0) 84{ 85 VecArrayAccess<T, Size> access(dst); 86 for (int ndx = 0; ndx < numValues; ndx++) 87 access[offset + ndx] = randomVector<T, Size>(rnd, minValue, maxValue); 88} 89 90template<typename T> 91static void fillRandomScalars (de::Random& rnd, T minValue, T maxValue, void* dst, int numValues, int offset = 0) 92{ 93 T* typedPtr = (T*)dst; 94 for (int ndx = 0; ndx < numValues; ndx++) 95 typedPtr[offset + ndx] = randomScalar<T>(rnd, minValue, maxValue); 96} 97 98inline int numBitsLostInOp (float input, float output) 99{ 100 const int inExp = tcu::Float32(input).exponent(); 101 const int outExp = tcu::Float32(output).exponent(); 102 103 return de::max(0, inExp-outExp); // Lost due to mantissa shift. 104} 105 106inline deUint32 getUlpDiff (float a, float b) 107{ 108 const deUint32 aBits = tcu::Float32(a).bits(); 109 const deUint32 bBits = tcu::Float32(b).bits(); 110 return aBits > bBits ? aBits - bBits : bBits - aBits; 111} 112 113inline deUint32 getUlpDiffIgnoreZeroSign (float a, float b) 114{ 115 if (tcu::Float32(a).isZero()) 116 return getUlpDiff(tcu::Float32::construct(tcu::Float32(b).sign(), 0, 0).asFloat(), b); 117 else if (tcu::Float32(b).isZero()) 118 return getUlpDiff(a, tcu::Float32::construct(tcu::Float32(a).sign(), 0, 0).asFloat()); 119 else 120 return getUlpDiff(a, b); 121} 122 123inline bool supportsSignedZero (glu::Precision precision) 124{ 125 // \note GLSL ES 3.0 doesn't really require support for -0, but we require it for highp 126 // as it is very widely supported. 127 return precision == glu::PRECISION_HIGHP; 128} 129 130inline float getEpsFromMaxUlpDiff (float value, deUint32 ulpDiff) 131{ 132 const int exp = tcu::Float32(value).exponent(); 133 return tcu::Float32::construct(+1, exp, (1u<<23) | ulpDiff).asFloat() - tcu::Float32::construct(+1, exp, 1u<<23).asFloat(); 134} 135 136inline deUint32 getMaxUlpDiffFromBits (int numAccurateBits) 137{ 138 const int numGarbageBits = 23-numAccurateBits; 139 const deUint32 mask = (1u<<numGarbageBits)-1u; 140 141 return mask; 142} 143 144inline float getEpsFromBits (float value, int numAccurateBits) 145{ 146 return getEpsFromMaxUlpDiff(value, getMaxUlpDiffFromBits(numAccurateBits)); 147} 148 149static int getMinMantissaBits (glu::Precision precision) 150{ 151 const int bits[] = 152 { 153 7, // lowp 154 10, // mediump 155 23 // highp 156 }; 157 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(bits) == glu::PRECISION_LAST); 158 DE_ASSERT(de::inBounds<int>(precision, 0, DE_LENGTH_OF_ARRAY(bits))); 159 return bits[precision]; 160} 161 162// CommonFunctionCase 163 164class CommonFunctionCase : public TestCase 165{ 166public: 167 CommonFunctionCase (Context& context, const char* name, const char* description, glu::ShaderType shaderType); 168 ~CommonFunctionCase (void); 169 170 void init (void); 171 void deinit (void); 172 IterateResult iterate (void); 173 174protected: 175 CommonFunctionCase (const CommonFunctionCase& other); 176 CommonFunctionCase& operator= (const CommonFunctionCase& other); 177 178 virtual void getInputValues (int numValues, void* const* values) const = 0; 179 virtual bool compare (const void* const* inputs, const void* const* outputs) = 0; 180 181 glu::ShaderType m_shaderType; 182 ShaderSpec m_spec; 183 int m_numValues; 184 185 std::ostringstream m_failMsg; //!< Comparison failure help message. 186 187private: 188 ShaderExecutor* m_executor; 189}; 190 191CommonFunctionCase::CommonFunctionCase (Context& context, const char* name, const char* description, glu::ShaderType shaderType) 192 : TestCase (context, name, description) 193 , m_shaderType (shaderType) 194 , m_numValues (100) 195 , m_executor (DE_NULL) 196{ 197 m_spec.version = glu::GLSL_VERSION_300_ES; 198} 199 200CommonFunctionCase::~CommonFunctionCase (void) 201{ 202 CommonFunctionCase::deinit(); 203} 204 205void CommonFunctionCase::init (void) 206{ 207 DE_ASSERT(!m_executor); 208 209 m_executor = createExecutor(m_context.getRenderContext(), m_shaderType, m_spec); 210 m_testCtx.getLog() << m_executor; 211 212 if (!m_executor->isOk()) 213 throw tcu::TestError("Compile failed"); 214} 215 216void CommonFunctionCase::deinit (void) 217{ 218 delete m_executor; 219 m_executor = DE_NULL; 220} 221 222static vector<int> getScalarSizes (const vector<Symbol>& symbols) 223{ 224 vector<int> sizes(symbols.size()); 225 for (int ndx = 0; ndx < (int)symbols.size(); ++ndx) 226 sizes[ndx] = symbols[ndx].varType.getScalarSize(); 227 return sizes; 228} 229 230static int computeTotalScalarSize (const vector<Symbol>& symbols) 231{ 232 int totalSize = 0; 233 for (vector<Symbol>::const_iterator sym = symbols.begin(); sym != symbols.end(); ++sym) 234 totalSize += sym->varType.getScalarSize(); 235 return totalSize; 236} 237 238static vector<void*> getInputOutputPointers (const vector<Symbol>& symbols, vector<deUint32>& data, const int numValues) 239{ 240 vector<void*> pointers (symbols.size()); 241 int curScalarOffset = 0; 242 243 for (int varNdx = 0; varNdx < (int)symbols.size(); ++varNdx) 244 { 245 const Symbol& var = symbols[varNdx]; 246 const int scalarSize = var.varType.getScalarSize(); 247 248 // Uses planar layout as input/output specs do not support strides. 249 pointers[varNdx] = &data[curScalarOffset]; 250 curScalarOffset += scalarSize*numValues; 251 } 252 253 DE_ASSERT(curScalarOffset == (int)data.size()); 254 255 return pointers; 256} 257 258// \todo [2013-08-08 pyry] Make generic utility and move to glu? 259 260struct HexFloat 261{ 262 const float value; 263 HexFloat (const float value_) : value(value_) {} 264}; 265 266std::ostream& operator<< (std::ostream& str, const HexFloat& v) 267{ 268 return str << v.value << " / " << tcu::toHex(tcu::Float32(v.value).bits()); 269} 270 271struct HexBool 272{ 273 const deUint32 value; 274 HexBool (const deUint32 value_) : value(value_) {} 275}; 276 277std::ostream& operator<< (std::ostream& str, const HexBool& v) 278{ 279 return str << (v.value ? "true" : "false") << " / " << tcu::toHex(v.value); 280} 281 282struct VarValue 283{ 284 const glu::VarType& type; 285 const void* value; 286 287 VarValue (const glu::VarType& type_, const void* value_) : type(type_), value(value_) {} 288}; 289 290std::ostream& operator<< (std::ostream& str, const VarValue& varValue) 291{ 292 DE_ASSERT(varValue.type.isBasicType()); 293 294 const glu::DataType basicType = varValue.type.getBasicType(); 295 const glu::DataType scalarType = glu::getDataTypeScalarType(basicType); 296 const int numComponents = glu::getDataTypeScalarSize(basicType); 297 298 if (numComponents > 1) 299 str << glu::getDataTypeName(basicType) << "("; 300 301 for (int compNdx = 0; compNdx < numComponents; compNdx++) 302 { 303 if (compNdx != 0) 304 str << ", "; 305 306 switch (scalarType) 307 { 308 case glu::TYPE_FLOAT: str << HexFloat(((const float*)varValue.value)[compNdx]); break; 309 case glu::TYPE_INT: str << ((const deInt32*)varValue.value)[compNdx]; break; 310 case glu::TYPE_UINT: str << tcu::toHex(((const deUint32*)varValue.value)[compNdx]); break; 311 case glu::TYPE_BOOL: str << HexBool(((const deUint32*)varValue.value)[compNdx]); break; 312 313 default: 314 DE_ASSERT(false); 315 } 316 } 317 318 if (numComponents > 1) 319 str << ")"; 320 321 return str; 322} 323 324CommonFunctionCase::IterateResult CommonFunctionCase::iterate (void) 325{ 326 const int numInputScalars = computeTotalScalarSize(m_spec.inputs); 327 const int numOutputScalars = computeTotalScalarSize(m_spec.outputs); 328 vector<deUint32> inputData (numInputScalars * m_numValues); 329 vector<deUint32> outputData (numOutputScalars * m_numValues); 330 const vector<void*> inputPointers = getInputOutputPointers(m_spec.inputs, inputData, m_numValues); 331 const vector<void*> outputPointers = getInputOutputPointers(m_spec.outputs, outputData, m_numValues); 332 333 // Initialize input data. 334 getInputValues(m_numValues, &inputPointers[0]); 335 336 // Execute shader. 337 m_executor->useProgram(); 338 m_executor->execute(m_numValues, &inputPointers[0], &outputPointers[0]); 339 340 // Compare results. 341 { 342 const vector<int> inScalarSizes = getScalarSizes(m_spec.inputs); 343 const vector<int> outScalarSizes = getScalarSizes(m_spec.outputs); 344 vector<void*> curInputPtr (inputPointers.size()); 345 vector<void*> curOutputPtr (outputPointers.size()); 346 int numFailed = 0; 347 348 for (int valNdx = 0; valNdx < m_numValues; valNdx++) 349 { 350 // Set up pointers for comparison. 351 for (int inNdx = 0; inNdx < (int)curInputPtr.size(); ++inNdx) 352 curInputPtr[inNdx] = (deUint32*)inputPointers[inNdx] + inScalarSizes[inNdx]*valNdx; 353 354 for (int outNdx = 0; outNdx < (int)curOutputPtr.size(); ++outNdx) 355 curOutputPtr[outNdx] = (deUint32*)outputPointers[outNdx] + outScalarSizes[outNdx]*valNdx; 356 357 if (!compare(&curInputPtr[0], &curOutputPtr[0])) 358 { 359 // \todo [2013-08-08 pyry] We probably want to log reference value as well? 360 361 m_testCtx.getLog() << TestLog::Message << "ERROR: comparison failed for value " << valNdx << ":\n " << m_failMsg.str() << TestLog::EndMessage; 362 363 m_testCtx.getLog() << TestLog::Message << " inputs:" << TestLog::EndMessage; 364 for (int inNdx = 0; inNdx < (int)curInputPtr.size(); inNdx++) 365 m_testCtx.getLog() << TestLog::Message << " " << m_spec.inputs[inNdx].name << " = " 366 << VarValue(m_spec.inputs[inNdx].varType, curInputPtr[inNdx]) 367 << TestLog::EndMessage; 368 369 m_testCtx.getLog() << TestLog::Message << " outputs:" << TestLog::EndMessage; 370 for (int outNdx = 0; outNdx < (int)curOutputPtr.size(); outNdx++) 371 m_testCtx.getLog() << TestLog::Message << " " << m_spec.outputs[outNdx].name << " = " 372 << VarValue(m_spec.outputs[outNdx].varType, curOutputPtr[outNdx]) 373 << TestLog::EndMessage; 374 375 m_failMsg.str(""); 376 m_failMsg.clear(); 377 numFailed += 1; 378 } 379 } 380 381 m_testCtx.getLog() << TestLog::Message << (m_numValues - numFailed) << " / " << m_numValues << " values passed" << TestLog::EndMessage; 382 383 m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, 384 numFailed == 0 ? "Pass" : "Result comparison failed"); 385 } 386 387 return STOP; 388} 389 390static const char* getPrecisionPostfix (glu::Precision precision) 391{ 392 static const char* s_postfix[] = 393 { 394 "_lowp", 395 "_mediump", 396 "_highp" 397 }; 398 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_postfix) == glu::PRECISION_LAST); 399 DE_ASSERT(de::inBounds<int>(precision, 0, DE_LENGTH_OF_ARRAY(s_postfix))); 400 return s_postfix[precision]; 401} 402 403static const char* getShaderTypePostfix (glu::ShaderType shaderType) 404{ 405 static const char* s_postfix[] = 406 { 407 "_vertex", 408 "_fragment" 409 }; 410 DE_ASSERT(de::inBounds<int>(shaderType, 0, DE_LENGTH_OF_ARRAY(s_postfix))); 411 return s_postfix[shaderType]; 412} 413 414static std::string getCommonFuncCaseName (glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType) 415{ 416 return string(glu::getDataTypeName(baseType)) + getPrecisionPostfix(precision) + getShaderTypePostfix(shaderType); 417} 418 419class AbsCase : public CommonFunctionCase 420{ 421public: 422 AbsCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType) 423 : CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "abs", shaderType) 424 { 425 m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision))); 426 m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision))); 427 m_spec.source = "out0 = abs(in0);"; 428 } 429 430 void getInputValues (int numValues, void* const* values) const 431 { 432 const Vec2 floatRanges[] = 433 { 434 Vec2(-2.0f, 2.0f), // lowp 435 Vec2(-1e3f, 1e3f), // mediump 436 Vec2(-1e7f, 1e7f) // highp 437 }; 438 const IVec2 intRanges[] = 439 { 440 IVec2(-(1<<7)+1, (1<<7)-1), 441 IVec2(-(1<<15)+1, (1<<15)-1), 442 IVec2(0x80000001, 0x7fffffff) 443 }; 444 445 de::Random rnd (deStringHash(getName()) ^ 0x235facu); 446 const glu::DataType type = m_spec.inputs[0].varType.getBasicType(); 447 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision(); 448 const int scalarSize = glu::getDataTypeScalarSize(type); 449 450 if (glu::isDataTypeFloatOrVec(type)) 451 fillRandomScalars(rnd, floatRanges[precision].x(), floatRanges[precision].y(), values[0], numValues*scalarSize); 452 else 453 fillRandomScalars(rnd, intRanges[precision].x(), intRanges[precision].y(), values[0], numValues*scalarSize); 454 } 455 456 bool compare (const void* const* inputs, const void* const* outputs) 457 { 458 const glu::DataType type = m_spec.inputs[0].varType.getBasicType(); 459 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision(); 460 const int scalarSize = glu::getDataTypeScalarSize(type); 461 462 if (glu::isDataTypeFloatOrVec(type)) 463 { 464 const int mantissaBits = getMinMantissaBits(precision); 465 const deUint32 maxUlpDiff = (1u<<(23-mantissaBits))-1u; 466 467 for (int compNdx = 0; compNdx < scalarSize; compNdx++) 468 { 469 const float in0 = ((const float*)inputs[0])[compNdx]; 470 const float out0 = ((const float*)outputs[0])[compNdx]; 471 const float ref0 = de::abs(in0); 472 const deUint32 ulpDiff0 = getUlpDiff(out0, ref0); 473 474 if (ulpDiff0 > maxUlpDiff) 475 { 476 m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref0) << " with ULP threshold " << maxUlpDiff << ", got ULP diff " << ulpDiff0; 477 return false; 478 } 479 } 480 } 481 else 482 { 483 for (int compNdx = 0; compNdx < scalarSize; compNdx++) 484 { 485 const int in0 = ((const int*)inputs[0])[compNdx]; 486 const int out0 = ((const int*)outputs[0])[compNdx]; 487 const int ref0 = de::abs(in0); 488 489 if (out0 != ref0) 490 { 491 m_failMsg << "Expected [" << compNdx << "] = " << ref0; 492 return false; 493 } 494 } 495 } 496 497 return true; 498 } 499}; 500 501class SignCase : public CommonFunctionCase 502{ 503public: 504 SignCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType) 505 : CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "sign", shaderType) 506 { 507 m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision))); 508 m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision))); 509 m_spec.source = "out0 = sign(in0);"; 510 } 511 512 void getInputValues (int numValues, void* const* values) const 513 { 514 const Vec2 floatRanges[] = 515 { 516 Vec2(-2.0f, 2.0f), // lowp 517 Vec2(-1e4f, 1e4f), // mediump - note: may end up as inf 518 Vec2(-1e8f, 1e8f) // highp - note: may end up as inf 519 }; 520 const IVec2 intRanges[] = 521 { 522 IVec2(-(1<<7), (1<<7)-1), 523 IVec2(-(1<<15), (1<<15)-1), 524 IVec2(0x80000000, 0x7fffffff) 525 }; 526 527 de::Random rnd (deStringHash(getName()) ^ 0x324u); 528 const glu::DataType type = m_spec.inputs[0].varType.getBasicType(); 529 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision(); 530 const int scalarSize = glu::getDataTypeScalarSize(type); 531 532 if (glu::isDataTypeFloatOrVec(type)) 533 { 534 // Special cases. 535 std::fill((float*)values[0], (float*)values[0] + scalarSize, +1.0f); 536 std::fill((float*)values[0] + scalarSize*1, (float*)values[0] + scalarSize*2, -1.0f); 537 std::fill((float*)values[0] + scalarSize*2, (float*)values[0] + scalarSize*3, 0.0f); 538 fillRandomScalars(rnd, floatRanges[precision].x(), floatRanges[precision].y(), (float*)values[0] + scalarSize*3, (numValues-3)*scalarSize); 539 } 540 else 541 { 542 std::fill((int*)values[0], (int*)values[0] + scalarSize, +1); 543 std::fill((int*)values[0] + scalarSize*1, (int*)values[0] + scalarSize*2, -1); 544 std::fill((int*)values[0] + scalarSize*2, (int*)values[0] + scalarSize*3, 0); 545 fillRandomScalars(rnd, intRanges[precision].x(), intRanges[precision].y(), (int*)values[0] + scalarSize*3, (numValues-3)*scalarSize); 546 } 547 } 548 549 bool compare (const void* const* inputs, const void* const* outputs) 550 { 551 const glu::DataType type = m_spec.inputs[0].varType.getBasicType(); 552 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision(); 553 const int scalarSize = glu::getDataTypeScalarSize(type); 554 555 if (glu::isDataTypeFloatOrVec(type)) 556 { 557 // Both highp and mediump should be able to represent -1, 0, and +1 exactly 558 const deUint32 maxUlpDiff = precision == glu::PRECISION_LOWP ? getMaxUlpDiffFromBits(getMinMantissaBits(precision)) : 0; 559 560 for (int compNdx = 0; compNdx < scalarSize; compNdx++) 561 { 562 const float in0 = ((const float*)inputs[0])[compNdx]; 563 const float out0 = ((const float*)outputs[0])[compNdx]; 564 const float ref0 = in0 < 0.0f ? -1.0f : 565 in0 > 0.0f ? +1.0f : 0.0f; 566 const deUint32 ulpDiff0 = getUlpDiff(out0, ref0); 567 568 if (ulpDiff0 > maxUlpDiff) 569 { 570 m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref0) << " with ULP threshold " << maxUlpDiff << ", got ULP diff " << ulpDiff0; 571 return false; 572 } 573 } 574 } 575 else 576 { 577 for (int compNdx = 0; compNdx < scalarSize; compNdx++) 578 { 579 const int in0 = ((const int*)inputs[0])[compNdx]; 580 const int out0 = ((const int*)outputs[0])[compNdx]; 581 const int ref0 = in0 < 0 ? -1 : 582 in0 > 0 ? +1 : 0; 583 584 if (out0 != ref0) 585 { 586 m_failMsg << "Expected [" << compNdx << "] = " << ref0; 587 return false; 588 } 589 } 590 } 591 592 return true; 593 } 594}; 595 596static float roundEven (float v) 597{ 598 const float q = deFloatFrac(v); 599 const int truncated = int(v-q); 600 const int rounded = (q > 0.5f) ? (truncated + 1) : // Rounded up 601 (q == 0.5f && (truncated % 2 != 0)) ? (truncated + 1) : // Round to nearest even at 0.5 602 truncated; // Rounded down 603 604 return float(rounded); 605} 606 607class RoundEvenCase : public CommonFunctionCase 608{ 609public: 610 RoundEvenCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType) 611 : CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "roundEven", shaderType) 612 { 613 m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision))); 614 m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision))); 615 m_spec.source = "out0 = roundEven(in0);"; 616 } 617 618 void getInputValues (int numValues, void* const* values) const 619 { 620 const Vec2 ranges[] = 621 { 622 Vec2(-2.0f, 2.0f), // lowp 623 Vec2(-1e3f, 1e3f), // mediump 624 Vec2(-1e7f, 1e7f) // highp 625 }; 626 627 de::Random rnd (deStringHash(getName()) ^ 0xac23fu); 628 const glu::DataType type = m_spec.inputs[0].varType.getBasicType(); 629 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision(); 630 const int scalarSize = glu::getDataTypeScalarSize(type); 631 int numSpecialCases = 0; 632 633 // Special cases. 634 if (precision != glu::PRECISION_LOWP) 635 { 636 DE_ASSERT(numValues >= 20); 637 for (int ndx = 0; ndx < 20; ndx++) 638 { 639 const float v = de::clamp(float(ndx) - 10.5f, ranges[precision].x(), ranges[precision].y()); 640 std::fill((float*)values[0], (float*)values[0] + scalarSize, v); 641 numSpecialCases += 1; 642 } 643 } 644 645 // Random cases. 646 fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), (float*)values[0] + numSpecialCases*scalarSize, (numValues-numSpecialCases)*scalarSize); 647 648 // If precision is mediump, make sure values can be represented in fp16 exactly 649 if (precision == glu::PRECISION_MEDIUMP) 650 { 651 for (int ndx = 0; ndx < numValues*scalarSize; ndx++) 652 ((float*)values[0])[ndx] = tcu::Float16(((float*)values[0])[ndx]).asFloat(); 653 } 654 } 655 656 bool compare (const void* const* inputs, const void* const* outputs) 657 { 658 const glu::DataType type = m_spec.inputs[0].varType.getBasicType(); 659 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision(); 660 const bool hasSignedZero = supportsSignedZero(precision); 661 const int scalarSize = glu::getDataTypeScalarSize(type); 662 663 if (precision == glu::PRECISION_HIGHP || precision == glu::PRECISION_MEDIUMP) 664 { 665 // Require exact rounding result. 666 for (int compNdx = 0; compNdx < scalarSize; compNdx++) 667 { 668 const float in0 = ((const float*)inputs[0])[compNdx]; 669 const float out0 = ((const float*)outputs[0])[compNdx]; 670 const float ref = roundEven(in0); 671 672 const deUint32 ulpDiff = hasSignedZero ? getUlpDiff(out0, ref) : getUlpDiffIgnoreZeroSign(out0, ref); 673 674 if (ulpDiff > 0) 675 { 676 m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref) << ", got ULP diff " << tcu::toHex(ulpDiff); 677 return false; 678 } 679 } 680 } 681 else 682 { 683 const int mantissaBits = getMinMantissaBits(precision); 684 const deUint32 maxUlpDiff = getMaxUlpDiffFromBits(mantissaBits); // ULP diff for rounded integer value. 685 const float eps = getEpsFromBits(1.0f, mantissaBits); // epsilon for rounding bounds 686 687 for (int compNdx = 0; compNdx < scalarSize; compNdx++) 688 { 689 const float in0 = ((const float*)inputs[0])[compNdx]; 690 const float out0 = ((const float*)outputs[0])[compNdx]; 691 const int minRes = int(roundEven(in0-eps)); 692 const int maxRes = int(roundEven(in0+eps)); 693 bool anyOk = false; 694 695 for (int roundedVal = minRes; roundedVal <= maxRes; roundedVal++) 696 { 697 const deUint32 ulpDiff = getUlpDiffIgnoreZeroSign(out0, float(roundedVal)); 698 699 if (ulpDiff <= maxUlpDiff) 700 { 701 anyOk = true; 702 break; 703 } 704 } 705 706 if (!anyOk) 707 { 708 m_failMsg << "Expected [" << compNdx << "] = [" << minRes << ", " << maxRes << "] with ULP threshold " << tcu::toHex(maxUlpDiff); 709 return false; 710 } 711 } 712 } 713 714 return true; 715 } 716}; 717 718class ModfCase : public CommonFunctionCase 719{ 720public: 721 ModfCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType) 722 : CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "modf", shaderType) 723 { 724 m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision))); 725 m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision))); 726 m_spec.outputs.push_back(Symbol("out1", glu::VarType(baseType, precision))); 727 m_spec.source = "out0 = modf(in0, out1);"; 728 } 729 730 void getInputValues (int numValues, void* const* values) const 731 { 732 const Vec2 ranges[] = 733 { 734 Vec2(-2.0f, 2.0f), // lowp 735 Vec2(-1e3f, 1e3f), // mediump 736 Vec2(-1e7f, 1e7f) // highp 737 }; 738 739 de::Random rnd (deStringHash(getName()) ^ 0xac23fu); 740 const glu::DataType type = m_spec.inputs[0].varType.getBasicType(); 741 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision(); 742 const int scalarSize = glu::getDataTypeScalarSize(type); 743 744 fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), values[0], numValues*scalarSize); 745 } 746 747 bool compare (const void* const* inputs, const void* const* outputs) 748 { 749 const glu::DataType type = m_spec.inputs[0].varType.getBasicType(); 750 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision(); 751 const bool hasZeroSign = supportsSignedZero(precision); 752 const int scalarSize = glu::getDataTypeScalarSize(type); 753 754 const int mantissaBits = getMinMantissaBits(precision); 755 756 for (int compNdx = 0; compNdx < scalarSize; compNdx++) 757 { 758 const float in0 = ((const float*)inputs[0])[compNdx]; 759 const float out0 = ((const float*)outputs[0])[compNdx]; 760 const float out1 = ((const float*)outputs[1])[compNdx]; 761 762 const float refOut1 = float(int(in0)); 763 const float refOut0 = in0 - refOut1; 764 765 const int bitsLost = precision != glu::PRECISION_HIGHP ? numBitsLostInOp(in0, refOut0) : 0; 766 const deUint32 maxUlpDiff = getMaxUlpDiffFromBits(de::max(mantissaBits - bitsLost, 0)); 767 768 const float resSum = out0 + out1; 769 770 const deUint32 ulpDiff = hasZeroSign ? getUlpDiff(resSum, in0) : getUlpDiffIgnoreZeroSign(resSum, in0); 771 772 if (ulpDiff > maxUlpDiff) 773 { 774 m_failMsg << "Expected [" << compNdx << "] = (" << HexFloat(refOut0) << ") + (" << HexFloat(refOut1) << ") = " << HexFloat(in0) << " with ULP threshold " 775 << tcu::toHex(maxUlpDiff) << ", got ULP diff " << tcu::toHex(ulpDiff); 776 return false; 777 } 778 } 779 780 return true; 781 } 782}; 783 784class IsnanCase : public CommonFunctionCase 785{ 786public: 787 IsnanCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType) 788 : CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "isnan", shaderType) 789 { 790 DE_ASSERT(glu::isDataTypeFloatOrVec(baseType)); 791 792 const int vecSize = glu::getDataTypeScalarSize(baseType); 793 const glu::DataType boolType = vecSize > 1 ? glu::getDataTypeBoolVec(vecSize) : glu::TYPE_BOOL; 794 795 m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision))); 796 m_spec.outputs.push_back(Symbol("out0", glu::VarType(boolType, glu::PRECISION_LAST))); 797 m_spec.source = "out0 = isnan(in0);"; 798 } 799 800 void getInputValues (int numValues, void* const* values) const 801 { 802 de::Random rnd (deStringHash(getName()) ^ 0xc2a39fu); 803 const glu::DataType type = m_spec.inputs[0].varType.getBasicType(); 804 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision(); 805 const int scalarSize = glu::getDataTypeScalarSize(type); 806 const int mantissaBits = getMinMantissaBits(precision); 807 const deUint32 mantissaMask = ~getMaxUlpDiffFromBits(mantissaBits) & ((1u<<23)-1u); 808 809 for (int valNdx = 0; valNdx < numValues*scalarSize; valNdx++) 810 { 811 const bool isNan = rnd.getFloat() > 0.3f; 812 const bool isInf = !isNan && rnd.getFloat() > 0.4f; 813 const deUint32 mantissa = !isInf ? ((1u<<22) | (rnd.getUint32() & mantissaMask)) : 0; 814 const deUint32 exp = !isNan && !isInf ? (rnd.getUint32() & 0x7fu) : 0xffu; 815 const deUint32 sign = rnd.getUint32() & 0x1u; 816 const deUint32 value = (sign << 31) | (exp << 23) | mantissa; 817 818 DE_ASSERT(tcu::Float32(value).isInf() == isInf && tcu::Float32(value).isNaN() == isNan); 819 820 ((deUint32*)values[0])[valNdx] = value; 821 } 822 } 823 824 bool compare (const void* const* inputs, const void* const* outputs) 825 { 826 const glu::DataType type = m_spec.inputs[0].varType.getBasicType(); 827 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision(); 828 const int scalarSize = glu::getDataTypeScalarSize(type); 829 830 if (precision == glu::PRECISION_HIGHP) 831 { 832 // Only highp is required to support inf/nan 833 for (int compNdx = 0; compNdx < scalarSize; compNdx++) 834 { 835 const float in0 = ((const float*)inputs[0])[compNdx]; 836 const deUint32 out0 = ((const deUint32*)outputs[0])[compNdx]; 837 const deUint32 ref = tcu::Float32(in0).isNaN() ? 1u : 0u; 838 839 if (out0 != ref) 840 { 841 m_failMsg << "Expected [" << compNdx << "] = " << HexBool(ref); 842 return false; 843 } 844 } 845 } 846 else 847 { 848 // Value can be either 0 or 1 849 for (int compNdx = 0; compNdx < scalarSize; compNdx++) 850 { 851 const int out0 = ((const int*)outputs[0])[compNdx]; 852 853 if (out0 != 0 && out0 != 1) 854 { 855 m_failMsg << "Expected [" << compNdx << "] = 0 / 1"; 856 return false; 857 } 858 } 859 } 860 861 return true; 862 } 863}; 864 865class IsinfCase : public CommonFunctionCase 866{ 867public: 868 IsinfCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType) 869 : CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "isinf", shaderType) 870 { 871 DE_ASSERT(glu::isDataTypeFloatOrVec(baseType)); 872 873 const int vecSize = glu::getDataTypeScalarSize(baseType); 874 const glu::DataType boolType = vecSize > 1 ? glu::getDataTypeBoolVec(vecSize) : glu::TYPE_BOOL; 875 876 m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision))); 877 m_spec.outputs.push_back(Symbol("out0", glu::VarType(boolType, glu::PRECISION_LAST))); 878 m_spec.source = "out0 = isinf(in0);"; 879 } 880 881 void getInputValues (int numValues, void* const* values) const 882 { 883 de::Random rnd (deStringHash(getName()) ^ 0xc2a39fu); 884 const glu::DataType type = m_spec.inputs[0].varType.getBasicType(); 885 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision(); 886 const int scalarSize = glu::getDataTypeScalarSize(type); 887 const int mantissaBits = getMinMantissaBits(precision); 888 const deUint32 mantissaMask = ~getMaxUlpDiffFromBits(mantissaBits) & ((1u<<23)-1u); 889 890 for (int valNdx = 0; valNdx < numValues*scalarSize; valNdx++) 891 { 892 const bool isInf = rnd.getFloat() > 0.3f; 893 const bool isNan = !isInf && rnd.getFloat() > 0.4f; 894 const deUint32 mantissa = !isInf ? ((1u<<22) | (rnd.getUint32() & mantissaMask)) : 0; 895 const deUint32 exp = !isNan && !isInf ? (rnd.getUint32() & 0x7fu) : 0xffu; 896 const deUint32 sign = rnd.getUint32() & 0x1u; 897 const deUint32 value = (sign << 31) | (exp << 23) | mantissa; 898 899 DE_ASSERT(tcu::Float32(value).isInf() == isInf && tcu::Float32(value).isNaN() == isNan); 900 901 ((deUint32*)values[0])[valNdx] = value; 902 } 903 } 904 905 bool compare (const void* const* inputs, const void* const* outputs) 906 { 907 const glu::DataType type = m_spec.inputs[0].varType.getBasicType(); 908 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision(); 909 const int scalarSize = glu::getDataTypeScalarSize(type); 910 911 if (precision == glu::PRECISION_HIGHP) 912 { 913 // Only highp is required to support inf/nan 914 for (int compNdx = 0; compNdx < scalarSize; compNdx++) 915 { 916 const float in0 = ((const float*)inputs[0])[compNdx]; 917 const deUint32 out0 = ((const deUint32*)outputs[0])[compNdx]; 918 const deUint32 ref = tcu::Float32(in0).isInf() ? 1u : 0u; 919 920 if (out0 != ref) 921 { 922 m_failMsg << "Expected [" << compNdx << "] = " << HexBool(ref); 923 return false; 924 } 925 } 926 } 927 else 928 { 929 // Value can be either 0 or 1 930 for (int compNdx = 0; compNdx < scalarSize; compNdx++) 931 { 932 const int out0 = ((const int*)outputs[0])[compNdx]; 933 934 if (out0 != 0 && out0 != 1) 935 { 936 m_failMsg << "Expected [" << compNdx << "] = 0 / 1"; 937 return false; 938 } 939 } 940 } 941 942 return true; 943 } 944}; 945 946class FloatBitsToUintIntCase : public CommonFunctionCase 947{ 948public: 949 FloatBitsToUintIntCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType, bool outIsSigned) 950 : CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), outIsSigned ? "floatBitsToInt" : "floatBitsToUint", shaderType) 951 { 952 const int vecSize = glu::getDataTypeScalarSize(baseType); 953 const glu::DataType intType = outIsSigned ? (vecSize > 1 ? glu::getDataTypeIntVec(vecSize) : glu::TYPE_INT) 954 : (vecSize > 1 ? glu::getDataTypeUintVec(vecSize) : glu::TYPE_UINT); 955 956 m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision))); 957 m_spec.outputs.push_back(Symbol("out0", glu::VarType(intType, glu::PRECISION_HIGHP))); 958 m_spec.source = outIsSigned ? "out0 = floatBitsToInt(in0);" : "out0 = floatBitsToUint(in0);"; 959 } 960 961 void getInputValues (int numValues, void* const* values) const 962 { 963 const Vec2 ranges[] = 964 { 965 Vec2(-2.0f, 2.0f), // lowp 966 Vec2(-1e3f, 1e3f), // mediump 967 Vec2(-1e7f, 1e7f) // highp 968 }; 969 970 de::Random rnd (deStringHash(getName()) ^ 0x2790au); 971 const glu::DataType type = m_spec.inputs[0].varType.getBasicType(); 972 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision(); 973 const int scalarSize = glu::getDataTypeScalarSize(type); 974 975 fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), values[0], numValues*scalarSize); 976 } 977 978 bool compare (const void* const* inputs, const void* const* outputs) 979 { 980 const glu::DataType type = m_spec.inputs[0].varType.getBasicType(); 981 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision(); 982 const int scalarSize = glu::getDataTypeScalarSize(type); 983 984 const int mantissaBits = getMinMantissaBits(precision); 985 const int maxUlpDiff = getMaxUlpDiffFromBits(mantissaBits); 986 987 for (int compNdx = 0; compNdx < scalarSize; compNdx++) 988 { 989 const float in0 = ((const float*)inputs[0])[compNdx]; 990 const deUint32 out0 = ((const deUint32*)outputs[0])[compNdx]; 991 const deUint32 refOut0 = tcu::Float32(in0).bits(); 992 const int ulpDiff = de::abs((int)out0 - (int)refOut0); 993 994 if (ulpDiff > maxUlpDiff) 995 { 996 m_failMsg << "Expected [" << compNdx << "] = " << tcu::toHex(refOut0) << " with threshold " 997 << tcu::toHex(maxUlpDiff) << ", got diff " << tcu::toHex(ulpDiff); 998 return false; 999 } 1000 } 1001 1002 return true; 1003 } 1004}; 1005 1006class FloatBitsToIntCase : public FloatBitsToUintIntCase 1007{ 1008public: 1009 FloatBitsToIntCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType) 1010 : FloatBitsToUintIntCase(context, baseType, precision, shaderType, true) 1011 { 1012 } 1013}; 1014 1015class FloatBitsToUintCase : public FloatBitsToUintIntCase 1016{ 1017public: 1018 FloatBitsToUintCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType) 1019 : FloatBitsToUintIntCase(context, baseType, precision, shaderType, false) 1020 { 1021 } 1022}; 1023 1024class BitsToFloatCase : public CommonFunctionCase 1025{ 1026public: 1027 BitsToFloatCase (Context& context, glu::DataType baseType, glu::ShaderType shaderType) 1028 : CommonFunctionCase(context, getCommonFuncCaseName(baseType, glu::PRECISION_HIGHP, shaderType).c_str(), glu::isDataTypeIntOrIVec(baseType) ? "intBitsToFloat" : "uintBitsToFloat", shaderType) 1029 { 1030 const bool inIsSigned = glu::isDataTypeIntOrIVec(baseType); 1031 const int vecSize = glu::getDataTypeScalarSize(baseType); 1032 const glu::DataType floatType = vecSize > 1 ? glu::getDataTypeFloatVec(vecSize) : glu::TYPE_FLOAT; 1033 1034 m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, glu::PRECISION_HIGHP))); 1035 m_spec.outputs.push_back(Symbol("out0", glu::VarType(floatType, glu::PRECISION_HIGHP))); 1036 m_spec.source = inIsSigned ? "out0 = intBitsToFloat(in0);" : "out0 = uintBitsToFloat(in0);"; 1037 } 1038 1039 void getInputValues (int numValues, void* const* values) const 1040 { 1041 de::Random rnd (deStringHash(getName()) ^ 0xbbb225u); 1042 const glu::DataType type = m_spec.inputs[0].varType.getBasicType(); 1043 const int scalarSize = glu::getDataTypeScalarSize(type); 1044 const Vec2 range (-1e8f, +1e8f); 1045 1046 // \note Filled as floats. 1047 fillRandomScalars(rnd, range.x(), range.y(), values[0], numValues*scalarSize); 1048 } 1049 1050 bool compare (const void* const* inputs, const void* const* outputs) 1051 { 1052 const glu::DataType type = m_spec.inputs[0].varType.getBasicType(); 1053 const int scalarSize = glu::getDataTypeScalarSize(type); 1054 const deUint32 maxUlpDiff = 0; 1055 1056 for (int compNdx = 0; compNdx < scalarSize; compNdx++) 1057 { 1058 const float in0 = ((const float*)inputs[0])[compNdx]; 1059 const float out0 = ((const float*)outputs[0])[compNdx]; 1060 const deUint32 ulpDiff = getUlpDiff(in0, out0); 1061 1062 if (ulpDiff > maxUlpDiff) 1063 { 1064 m_failMsg << "Expected [" << compNdx << "] = " << tcu::toHex(tcu::Float32(in0).bits()) << " with ULP threshold " 1065 << tcu::toHex(maxUlpDiff) << ", got ULP diff " << tcu::toHex(ulpDiff); 1066 return false; 1067 } 1068 } 1069 1070 return true; 1071 } 1072}; 1073 1074class FloorCase : public CommonFunctionCase 1075{ 1076public: 1077 FloorCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType) 1078 : CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "floor", shaderType) 1079 { 1080 m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision))); 1081 m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision))); 1082 m_spec.source = "out0 = floor(in0);"; 1083 } 1084 1085 void getInputValues (int numValues, void* const* values) const 1086 { 1087 const Vec2 ranges[] = 1088 { 1089 Vec2(-2.0f, 2.0f), // lowp 1090 Vec2(-1e3f, 1e3f), // mediump 1091 Vec2(-1e7f, 1e7f) // highp 1092 }; 1093 1094 de::Random rnd (deStringHash(getName()) ^ 0xac23fu); 1095 const glu::DataType type = m_spec.inputs[0].varType.getBasicType(); 1096 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision(); 1097 const int scalarSize = glu::getDataTypeScalarSize(type); 1098 // Random cases. 1099 fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), (float*)values[0], numValues*scalarSize); 1100 1101 // If precision is mediump, make sure values can be represented in fp16 exactly 1102 if (precision == glu::PRECISION_MEDIUMP) 1103 { 1104 for (int ndx = 0; ndx < numValues*scalarSize; ndx++) 1105 ((float*)values[0])[ndx] = tcu::Float16(((float*)values[0])[ndx]).asFloat(); 1106 } 1107 } 1108 1109 bool compare (const void* const* inputs, const void* const* outputs) 1110 { 1111 const glu::DataType type = m_spec.inputs[0].varType.getBasicType(); 1112 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision(); 1113 const int scalarSize = glu::getDataTypeScalarSize(type); 1114 1115 if (precision == glu::PRECISION_HIGHP || precision == glu::PRECISION_MEDIUMP) 1116 { 1117 // Require exact result. 1118 for (int compNdx = 0; compNdx < scalarSize; compNdx++) 1119 { 1120 const float in0 = ((const float*)inputs[0])[compNdx]; 1121 const float out0 = ((const float*)outputs[0])[compNdx]; 1122 const float ref = deFloatFloor(in0); 1123 1124 const deUint32 ulpDiff = getUlpDiff(out0, ref); 1125 1126 if (ulpDiff > 0) 1127 { 1128 m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref) << ", got ULP diff " << tcu::toHex(ulpDiff); 1129 return false; 1130 } 1131 } 1132 } 1133 else 1134 { 1135 const int mantissaBits = getMinMantissaBits(precision); 1136 const deUint32 maxUlpDiff = getMaxUlpDiffFromBits(mantissaBits); // ULP diff for rounded integer value. 1137 const float eps = getEpsFromBits(1.0f, mantissaBits); // epsilon for rounding bounds 1138 1139 for (int compNdx = 0; compNdx < scalarSize; compNdx++) 1140 { 1141 const float in0 = ((const float*)inputs[0])[compNdx]; 1142 const float out0 = ((const float*)outputs[0])[compNdx]; 1143 const int minRes = int(deFloatFloor(in0-eps)); 1144 const int maxRes = int(deFloatFloor(in0+eps)); 1145 bool anyOk = false; 1146 1147 for (int roundedVal = minRes; roundedVal <= maxRes; roundedVal++) 1148 { 1149 const deUint32 ulpDiff = getUlpDiff(out0, float(roundedVal)); 1150 1151 if (ulpDiff <= maxUlpDiff) 1152 { 1153 anyOk = true; 1154 break; 1155 } 1156 } 1157 1158 if (!anyOk) 1159 { 1160 m_failMsg << "Expected [" << compNdx << "] = [" << minRes << ", " << maxRes << "] with ULP threshold " << tcu::toHex(maxUlpDiff); 1161 return false; 1162 } 1163 } 1164 } 1165 1166 return true; 1167 } 1168}; 1169 1170class TruncCase : public CommonFunctionCase 1171{ 1172public: 1173 TruncCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType) 1174 : CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "trunc", shaderType) 1175 { 1176 m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision))); 1177 m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision))); 1178 m_spec.source = "out0 = trunc(in0);"; 1179 } 1180 1181 void getInputValues (int numValues, void* const* values) const 1182 { 1183 const Vec2 ranges[] = 1184 { 1185 Vec2(-2.0f, 2.0f), // lowp 1186 Vec2(-1e3f, 1e3f), // mediump 1187 Vec2(-1e7f, 1e7f) // highp 1188 }; 1189 1190 de::Random rnd (deStringHash(getName()) ^ 0xac23fu); 1191 const glu::DataType type = m_spec.inputs[0].varType.getBasicType(); 1192 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision(); 1193 const int scalarSize = glu::getDataTypeScalarSize(type); 1194 const float specialCases[] = { 0.0f, -0.0f, -0.9f, 0.9f, 1.0f, -1.0f }; 1195 const int numSpecialCases = DE_LENGTH_OF_ARRAY(specialCases); 1196 1197 // Special cases 1198 for (int caseNdx = 0; caseNdx < numSpecialCases; caseNdx++) 1199 { 1200 for (int scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++) 1201 ((float*)values[0])[caseNdx*scalarSize + scalarNdx] = specialCases[caseNdx]; 1202 } 1203 1204 // Random cases. 1205 fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), (float*)values[0] + scalarSize*numSpecialCases, (numValues-numSpecialCases)*scalarSize); 1206 1207 // If precision is mediump, make sure values can be represented in fp16 exactly 1208 if (precision == glu::PRECISION_MEDIUMP) 1209 { 1210 for (int ndx = 0; ndx < numValues*scalarSize; ndx++) 1211 ((float*)values[0])[ndx] = tcu::Float16(((float*)values[0])[ndx]).asFloat(); 1212 } 1213 } 1214 1215 bool compare (const void* const* inputs, const void* const* outputs) 1216 { 1217 const glu::DataType type = m_spec.inputs[0].varType.getBasicType(); 1218 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision(); 1219 const int scalarSize = glu::getDataTypeScalarSize(type); 1220 1221 if (precision == glu::PRECISION_HIGHP || precision == glu::PRECISION_MEDIUMP) 1222 { 1223 // Require exact result. 1224 for (int compNdx = 0; compNdx < scalarSize; compNdx++) 1225 { 1226 const float in0 = ((const float*)inputs[0])[compNdx]; 1227 const float out0 = ((const float*)outputs[0])[compNdx]; 1228 const bool isNeg = tcu::Float32(in0).sign() < 0; 1229 const float ref = isNeg ? (-float(int(-in0))) : float(int(in0)); 1230 1231 // \note: trunc() function definition is a bit broad on negative zeros. Ignore result sign if zero. 1232 const deUint32 ulpDiff = getUlpDiffIgnoreZeroSign(out0, ref); 1233 1234 if (ulpDiff > 0) 1235 { 1236 m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref) << ", got ULP diff " << tcu::toHex(ulpDiff); 1237 return false; 1238 } 1239 } 1240 } 1241 else 1242 { 1243 const int mantissaBits = getMinMantissaBits(precision); 1244 const deUint32 maxUlpDiff = getMaxUlpDiffFromBits(mantissaBits); // ULP diff for rounded integer value. 1245 const float eps = getEpsFromBits(1.0f, mantissaBits); // epsilon for rounding bounds 1246 1247 for (int compNdx = 0; compNdx < scalarSize; compNdx++) 1248 { 1249 const float in0 = ((const float*)inputs[0])[compNdx]; 1250 const float out0 = ((const float*)outputs[0])[compNdx]; 1251 const int minRes = int(in0-eps); 1252 const int maxRes = int(in0+eps); 1253 bool anyOk = false; 1254 1255 for (int roundedVal = minRes; roundedVal <= maxRes; roundedVal++) 1256 { 1257 const deUint32 ulpDiff = getUlpDiffIgnoreZeroSign(out0, float(roundedVal)); 1258 1259 if (ulpDiff <= maxUlpDiff) 1260 { 1261 anyOk = true; 1262 break; 1263 } 1264 } 1265 1266 if (!anyOk) 1267 { 1268 m_failMsg << "Expected [" << compNdx << "] = [" << minRes << ", " << maxRes << "] with ULP threshold " << tcu::toHex(maxUlpDiff); 1269 return false; 1270 } 1271 } 1272 } 1273 1274 return true; 1275 } 1276}; 1277 1278class RoundCase : public CommonFunctionCase 1279{ 1280public: 1281 RoundCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType) 1282 : CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "round", shaderType) 1283 { 1284 m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision))); 1285 m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision))); 1286 m_spec.source = "out0 = round(in0);"; 1287 } 1288 1289 void getInputValues (int numValues, void* const* values) const 1290 { 1291 const Vec2 ranges[] = 1292 { 1293 Vec2(-2.0f, 2.0f), // lowp 1294 Vec2(-1e3f, 1e3f), // mediump 1295 Vec2(-1e7f, 1e7f) // highp 1296 }; 1297 1298 de::Random rnd (deStringHash(getName()) ^ 0xac23fu); 1299 const glu::DataType type = m_spec.inputs[0].varType.getBasicType(); 1300 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision(); 1301 const int scalarSize = glu::getDataTypeScalarSize(type); 1302 int numSpecialCases = 0; 1303 1304 // Special cases. 1305 if (precision != glu::PRECISION_LOWP) 1306 { 1307 DE_ASSERT(numValues >= 10); 1308 for (int ndx = 0; ndx < 10; ndx++) 1309 { 1310 const float v = de::clamp(float(ndx) - 5.5f, ranges[precision].x(), ranges[precision].y()); 1311 std::fill((float*)values[0], (float*)values[0] + scalarSize, v); 1312 numSpecialCases += 1; 1313 } 1314 } 1315 1316 // Random cases. 1317 fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), (float*)values[0] + numSpecialCases*scalarSize, (numValues-numSpecialCases)*scalarSize); 1318 1319 // If precision is mediump, make sure values can be represented in fp16 exactly 1320 if (precision == glu::PRECISION_MEDIUMP) 1321 { 1322 for (int ndx = 0; ndx < numValues*scalarSize; ndx++) 1323 ((float*)values[0])[ndx] = tcu::Float16(((float*)values[0])[ndx]).asFloat(); 1324 } 1325 } 1326 1327 bool compare (const void* const* inputs, const void* const* outputs) 1328 { 1329 const glu::DataType type = m_spec.inputs[0].varType.getBasicType(); 1330 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision(); 1331 const bool hasZeroSign = supportsSignedZero(precision); 1332 const int scalarSize = glu::getDataTypeScalarSize(type); 1333 1334 if (precision == glu::PRECISION_HIGHP || precision == glu::PRECISION_MEDIUMP) 1335 { 1336 for (int compNdx = 0; compNdx < scalarSize; compNdx++) 1337 { 1338 const float in0 = ((const float*)inputs[0])[compNdx]; 1339 const float out0 = ((const float*)outputs[0])[compNdx]; 1340 1341 if (deFloatFrac(in0) == 0.5f) 1342 { 1343 // Allow both ceil(in) and floor(in) 1344 const float ref0 = deFloatFloor(in0); 1345 const float ref1 = deFloatCeil(in0); 1346 const deUint32 ulpDiff0 = hasZeroSign ? getUlpDiff(out0, ref0) : getUlpDiffIgnoreZeroSign(out0, ref0); 1347 const deUint32 ulpDiff1 = hasZeroSign ? getUlpDiff(out0, ref1) : getUlpDiffIgnoreZeroSign(out0, ref1); 1348 1349 if (ulpDiff0 > 0 && ulpDiff1 > 0) 1350 { 1351 m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref0) << " or " << HexFloat(ref1) << ", got ULP diff " << tcu::toHex(de::min(ulpDiff0, ulpDiff1)); 1352 return false; 1353 } 1354 } 1355 else 1356 { 1357 // Require exact result 1358 const float ref = roundEven(in0); 1359 const deUint32 ulpDiff = hasZeroSign ? getUlpDiff(out0, ref) : getUlpDiffIgnoreZeroSign(out0, ref); 1360 1361 if (ulpDiff > 0) 1362 { 1363 m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref) << ", got ULP diff " << tcu::toHex(ulpDiff); 1364 return false; 1365 } 1366 } 1367 } 1368 } 1369 else 1370 { 1371 const int mantissaBits = getMinMantissaBits(precision); 1372 const deUint32 maxUlpDiff = getMaxUlpDiffFromBits(mantissaBits); // ULP diff for rounded integer value. 1373 const float eps = getEpsFromBits(1.0f, mantissaBits); // epsilon for rounding bounds 1374 1375 for (int compNdx = 0; compNdx < scalarSize; compNdx++) 1376 { 1377 const float in0 = ((const float*)inputs[0])[compNdx]; 1378 const float out0 = ((const float*)outputs[0])[compNdx]; 1379 const int minRes = int(roundEven(in0-eps)); 1380 const int maxRes = int(roundEven(in0+eps)); 1381 bool anyOk = false; 1382 1383 for (int roundedVal = minRes; roundedVal <= maxRes; roundedVal++) 1384 { 1385 const deUint32 ulpDiff = getUlpDiffIgnoreZeroSign(out0, float(roundedVal)); 1386 1387 if (ulpDiff <= maxUlpDiff) 1388 { 1389 anyOk = true; 1390 break; 1391 } 1392 } 1393 1394 if (!anyOk) 1395 { 1396 m_failMsg << "Expected [" << compNdx << "] = [" << minRes << ", " << maxRes << "] with ULP threshold " << tcu::toHex(maxUlpDiff); 1397 return false; 1398 } 1399 } 1400 } 1401 1402 return true; 1403 } 1404}; 1405 1406class CeilCase : public CommonFunctionCase 1407{ 1408public: 1409 CeilCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType) 1410 : CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "ceil", shaderType) 1411 { 1412 m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision))); 1413 m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision))); 1414 m_spec.source = "out0 = ceil(in0);"; 1415 } 1416 1417 void getInputValues (int numValues, void* const* values) const 1418 { 1419 const Vec2 ranges[] = 1420 { 1421 Vec2(-2.0f, 2.0f), // lowp 1422 Vec2(-1e3f, 1e3f), // mediump 1423 Vec2(-1e7f, 1e7f) // highp 1424 }; 1425 1426 de::Random rnd (deStringHash(getName()) ^ 0xac23fu); 1427 const glu::DataType type = m_spec.inputs[0].varType.getBasicType(); 1428 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision(); 1429 const int scalarSize = glu::getDataTypeScalarSize(type); 1430 1431 // Random cases. 1432 fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), (float*)values[0], numValues*scalarSize); 1433 1434 // If precision is mediump, make sure values can be represented in fp16 exactly 1435 if (precision == glu::PRECISION_MEDIUMP) 1436 { 1437 for (int ndx = 0; ndx < numValues*scalarSize; ndx++) 1438 ((float*)values[0])[ndx] = tcu::Float16(((float*)values[0])[ndx]).asFloat(); 1439 } 1440 } 1441 1442 bool compare (const void* const* inputs, const void* const* outputs) 1443 { 1444 const glu::DataType type = m_spec.inputs[0].varType.getBasicType(); 1445 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision(); 1446 const bool hasZeroSign = supportsSignedZero(precision); 1447 const int scalarSize = glu::getDataTypeScalarSize(type); 1448 1449 if (precision == glu::PRECISION_HIGHP || precision == glu::PRECISION_MEDIUMP) 1450 { 1451 // Require exact result. 1452 for (int compNdx = 0; compNdx < scalarSize; compNdx++) 1453 { 1454 const float in0 = ((const float*)inputs[0])[compNdx]; 1455 const float out0 = ((const float*)outputs[0])[compNdx]; 1456 const float ref = deFloatCeil(in0); 1457 1458 const deUint32 ulpDiff = hasZeroSign ? getUlpDiff(out0, ref) : getUlpDiffIgnoreZeroSign(out0, ref); 1459 1460 if (ulpDiff > 0) 1461 { 1462 m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref) << ", got ULP diff " << tcu::toHex(ulpDiff); 1463 return false; 1464 } 1465 } 1466 } 1467 else 1468 { 1469 const int mantissaBits = getMinMantissaBits(precision); 1470 const deUint32 maxUlpDiff = getMaxUlpDiffFromBits(mantissaBits); // ULP diff for rounded integer value. 1471 const float eps = getEpsFromBits(1.0f, mantissaBits); // epsilon for rounding bounds 1472 1473 for (int compNdx = 0; compNdx < scalarSize; compNdx++) 1474 { 1475 const float in0 = ((const float*)inputs[0])[compNdx]; 1476 const float out0 = ((const float*)outputs[0])[compNdx]; 1477 const int minRes = int(deFloatCeil(in0-eps)); 1478 const int maxRes = int(deFloatCeil(in0+eps)); 1479 bool anyOk = false; 1480 1481 for (int roundedVal = minRes; roundedVal <= maxRes; roundedVal++) 1482 { 1483 const deUint32 ulpDiff = getUlpDiffIgnoreZeroSign(out0, float(roundedVal)); 1484 1485 if (ulpDiff <= maxUlpDiff) 1486 { 1487 anyOk = true; 1488 break; 1489 } 1490 } 1491 1492 if (!anyOk && de::inRange(0, minRes, maxRes)) 1493 { 1494 // Allow -0 as well. 1495 const int ulpDiff = de::abs((int)tcu::Float32(out0).bits() - (int)0x80000000u); 1496 anyOk = ((deUint32)ulpDiff <= maxUlpDiff); 1497 } 1498 1499 if (!anyOk) 1500 { 1501 m_failMsg << "Expected [" << compNdx << "] = [" << minRes << ", " << maxRes << "] with ULP threshold " << tcu::toHex(maxUlpDiff); 1502 return false; 1503 } 1504 } 1505 } 1506 1507 return true; 1508 } 1509}; 1510 1511class FractCase : public CommonFunctionCase 1512{ 1513public: 1514 FractCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType) 1515 : CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "fract", shaderType) 1516 { 1517 m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision))); 1518 m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision))); 1519 m_spec.source = "out0 = fract(in0);"; 1520 } 1521 1522 void getInputValues (int numValues, void* const* values) const 1523 { 1524 const Vec2 ranges[] = 1525 { 1526 Vec2(-2.0f, 2.0f), // lowp 1527 Vec2(-1e3f, 1e3f), // mediump 1528 Vec2(-1e7f, 1e7f) // highp 1529 }; 1530 1531 de::Random rnd (deStringHash(getName()) ^ 0xac23fu); 1532 const glu::DataType type = m_spec.inputs[0].varType.getBasicType(); 1533 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision(); 1534 const int scalarSize = glu::getDataTypeScalarSize(type); 1535 int numSpecialCases = 0; 1536 1537 // Special cases. 1538 if (precision != glu::PRECISION_LOWP) 1539 { 1540 DE_ASSERT(numValues >= 10); 1541 for (int ndx = 0; ndx < 10; ndx++) 1542 { 1543 const float v = de::clamp(float(ndx) - 5.5f, ranges[precision].x(), ranges[precision].y()); 1544 std::fill((float*)values[0], (float*)values[0] + scalarSize, v); 1545 numSpecialCases += 1; 1546 } 1547 } 1548 1549 // Random cases. 1550 fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), (float*)values[0] + numSpecialCases*scalarSize, (numValues-numSpecialCases)*scalarSize); 1551 1552 // If precision is mediump, make sure values can be represented in fp16 exactly 1553 if (precision == glu::PRECISION_MEDIUMP) 1554 { 1555 for (int ndx = 0; ndx < numValues*scalarSize; ndx++) 1556 ((float*)values[0])[ndx] = tcu::Float16(((float*)values[0])[ndx]).asFloat(); 1557 } 1558 } 1559 1560 bool compare (const void* const* inputs, const void* const* outputs) 1561 { 1562 const glu::DataType type = m_spec.inputs[0].varType.getBasicType(); 1563 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision(); 1564 const bool hasZeroSign = supportsSignedZero(precision); 1565 const int scalarSize = glu::getDataTypeScalarSize(type); 1566 1567 if (precision == glu::PRECISION_HIGHP || precision == glu::PRECISION_MEDIUMP) 1568 { 1569 // Require exact result. 1570 for (int compNdx = 0; compNdx < scalarSize; compNdx++) 1571 { 1572 const float in0 = ((const float*)inputs[0])[compNdx]; 1573 const float out0 = ((const float*)outputs[0])[compNdx]; 1574 const float ref = deFloatFrac(in0); 1575 1576 const deUint32 ulpDiff = hasZeroSign ? getUlpDiff(out0, ref) : getUlpDiffIgnoreZeroSign(out0, ref); 1577 1578 if (ulpDiff > 0) 1579 { 1580 m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref) << ", got ULP diff " << tcu::toHex(ulpDiff); 1581 return false; 1582 } 1583 } 1584 } 1585 else 1586 { 1587 const int mantissaBits = getMinMantissaBits(precision); 1588 const float eps = getEpsFromBits(1.0f, mantissaBits); // epsilon for rounding bounds 1589 1590 for (int compNdx = 0; compNdx < scalarSize; compNdx++) 1591 { 1592 const float in0 = ((const float*)inputs[0])[compNdx]; 1593 const float out0 = ((const float*)outputs[0])[compNdx]; 1594 1595 if (int(deFloatFloor(in0-eps)) == int(deFloatFloor(in0+eps))) 1596 { 1597 const float ref = deFloatFrac(in0); 1598 const int bitsLost = numBitsLostInOp(in0, ref); 1599 const deUint32 maxUlpDiff = getMaxUlpDiffFromBits(de::max(0, mantissaBits-bitsLost)); // ULP diff for rounded integer value. 1600 const deUint32 ulpDiff = getUlpDiffIgnoreZeroSign(out0, ref); 1601 1602 if (ulpDiff > maxUlpDiff) 1603 { 1604 m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref) << " with ULP threshold " << tcu::toHex(maxUlpDiff) << ", got diff " << tcu::toHex(ulpDiff); 1605 return false; 1606 } 1607 } 1608 else 1609 { 1610 if (out0 >= 1.0f) 1611 { 1612 m_failMsg << "Expected [" << compNdx << "] < 1.0"; 1613 return false; 1614 } 1615 } 1616 } 1617 } 1618 1619 return true; 1620 } 1621}; 1622 1623ShaderCommonFunctionTests::ShaderCommonFunctionTests (Context& context) 1624 : TestCaseGroup(context, "common", "Common function tests") 1625{ 1626} 1627 1628ShaderCommonFunctionTests::~ShaderCommonFunctionTests (void) 1629{ 1630} 1631 1632template<class TestClass> 1633static void addFunctionCases (TestCaseGroup* parent, const char* functionName, bool floatTypes, bool intTypes, bool uintTypes) 1634{ 1635 tcu::TestCaseGroup* group = new tcu::TestCaseGroup(parent->getTestContext(), functionName, functionName); 1636 parent->addChild(group); 1637 1638 const glu::DataType scalarTypes[] = 1639 { 1640 glu::TYPE_FLOAT, 1641 glu::TYPE_INT, 1642 glu::TYPE_UINT 1643 }; 1644 1645 for (int scalarTypeNdx = 0; scalarTypeNdx < DE_LENGTH_OF_ARRAY(scalarTypes); scalarTypeNdx++) 1646 { 1647 const glu::DataType scalarType = scalarTypes[scalarTypeNdx]; 1648 1649 if ((!floatTypes && scalarType == glu::TYPE_FLOAT) || 1650 (!intTypes && scalarType == glu::TYPE_INT) || 1651 (!uintTypes && scalarType == glu::TYPE_UINT)) 1652 continue; 1653 1654 for (int vecSize = 1; vecSize <= 4; vecSize++) 1655 { 1656 for (int prec = glu::PRECISION_LOWP; prec <= glu::PRECISION_HIGHP; prec++) 1657 { 1658 for (int shaderType = glu::SHADERTYPE_VERTEX; shaderType <= glu::SHADERTYPE_FRAGMENT; shaderType++) 1659 group->addChild(new TestClass(parent->getContext(), glu::DataType(scalarType + vecSize - 1), glu::Precision(prec), glu::ShaderType(shaderType))); 1660 } 1661 } 1662 } 1663} 1664 1665void ShaderCommonFunctionTests::init (void) 1666{ 1667 // Float? Int? Uint? 1668 addFunctionCases<AbsCase> (this, "abs", true, true, false); 1669 addFunctionCases<SignCase> (this, "sign", true, true, false); 1670 addFunctionCases<FloorCase> (this, "floor", true, false, false); 1671 addFunctionCases<TruncCase> (this, "trunc", true, false, false); 1672 addFunctionCases<RoundCase> (this, "round", true, false, false); 1673 addFunctionCases<RoundEvenCase> (this, "roundeven", true, false, false); 1674 addFunctionCases<CeilCase> (this, "ceil", true, false, false); 1675 addFunctionCases<FractCase> (this, "fract", true, false, false); 1676 // mod 1677 addFunctionCases<ModfCase> (this, "modf", true, false, false); 1678 // min 1679 // max 1680 // clamp 1681 // mix 1682 // step 1683 // smoothstep 1684 addFunctionCases<IsnanCase> (this, "isnan", true, false, false); 1685 addFunctionCases<IsinfCase> (this, "isinf", true, false, false); 1686 addFunctionCases<FloatBitsToIntCase> (this, "floatbitstoint", true, false, false); 1687 addFunctionCases<FloatBitsToUintCase> (this, "floatbitstouint", true, false, false); 1688 1689 // (u)intBitsToFloat() 1690 { 1691 tcu::TestCaseGroup* intGroup = new tcu::TestCaseGroup(m_testCtx, "intbitstofloat", "intBitsToFloat() Tests"); 1692 tcu::TestCaseGroup* uintGroup = new tcu::TestCaseGroup(m_testCtx, "uintbitstofloat", "uintBitsToFloat() Tests"); 1693 1694 addChild(intGroup); 1695 addChild(uintGroup); 1696 1697 for (int vecSize = 1; vecSize < 4; vecSize++) 1698 { 1699 const glu::DataType intType = vecSize > 1 ? glu::getDataTypeIntVec(vecSize) : glu::TYPE_INT; 1700 const glu::DataType uintType = vecSize > 1 ? glu::getDataTypeUintVec(vecSize) : glu::TYPE_UINT; 1701 1702 for (int shaderType = glu::SHADERTYPE_VERTEX; shaderType <= glu::SHADERTYPE_FRAGMENT; shaderType++) 1703 { 1704 intGroup->addChild(new BitsToFloatCase(m_context, intType, glu::ShaderType(shaderType))); 1705 uintGroup->addChild(new BitsToFloatCase(m_context, uintType, glu::ShaderType(shaderType))); 1706 } 1707 } 1708 } 1709} 1710 1711} // Functional 1712} // gles3 1713} // deqp 1714