1/*------------------------------------------------------------------------- 2 * drawElements Quality Program OpenGL ES 3.1 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 "es31fShaderCommonFunctionTests.hpp" 25#include "gluContextInfo.hpp" 26#include "glsShaderExecUtil.hpp" 27#include "tcuTestLog.hpp" 28#include "tcuFormatUtil.hpp" 29#include "tcuFloat.hpp" 30#include "tcuInterval.hpp" 31#include "tcuFloatFormat.hpp" 32#include "tcuVectorUtil.hpp" 33#include "deRandom.hpp" 34#include "deMath.h" 35#include "deString.h" 36#include "deArrayUtil.hpp" 37 38namespace deqp 39{ 40namespace gles31 41{ 42namespace Functional 43{ 44 45using std::vector; 46using std::string; 47using tcu::TestLog; 48using namespace gls::ShaderExecUtil; 49 50using tcu::Vec2; 51using tcu::Vec3; 52using tcu::Vec4; 53using tcu::IVec2; 54using tcu::IVec3; 55using tcu::IVec4; 56 57// Utilities 58 59template<typename T, int Size> 60struct VecArrayAccess 61{ 62public: 63 VecArrayAccess (const void* ptr) : m_array((tcu::Vector<T, Size>*)ptr) {} 64 ~VecArrayAccess (void) {} 65 66 const tcu::Vector<T, Size>& operator[] (size_t offset) const { return m_array[offset]; } 67 tcu::Vector<T, Size>& operator[] (size_t offset) { return m_array[offset]; } 68 69private: 70 tcu::Vector<T, Size>* m_array; 71}; 72 73template<typename T, int Size> 74static void fillRandomVectors (de::Random& rnd, const tcu::Vector<T, Size>& minValue, const tcu::Vector<T, Size>& maxValue, void* dst, int numValues, int offset = 0) 75{ 76 VecArrayAccess<T, Size> access(dst); 77 for (int ndx = 0; ndx < numValues; ndx++) 78 access[offset + ndx] = tcu::randomVector<T, Size>(rnd, minValue, maxValue); 79} 80 81template<typename T> 82static void fillRandomScalars (de::Random& rnd, T minValue, T maxValue, void* dst, int numValues, int offset = 0) 83{ 84 T* typedPtr = (T*)dst; 85 for (int ndx = 0; ndx < numValues; ndx++) 86 typedPtr[offset + ndx] = de::randomScalar<T>(rnd, minValue, maxValue); 87} 88 89inline int numBitsLostInOp (float input, float output) 90{ 91 const int inExp = tcu::Float32(input).exponent(); 92 const int outExp = tcu::Float32(output).exponent(); 93 94 return de::max(0, inExp-outExp); // Lost due to mantissa shift. 95} 96 97inline deUint32 getUlpDiff (float a, float b) 98{ 99 const deUint32 aBits = tcu::Float32(a).bits(); 100 const deUint32 bBits = tcu::Float32(b).bits(); 101 return aBits > bBits ? aBits - bBits : bBits - aBits; 102} 103 104inline deUint32 getUlpDiffIgnoreZeroSign (float a, float b) 105{ 106 if (tcu::Float32(a).isZero()) 107 return getUlpDiff(tcu::Float32::construct(tcu::Float32(b).sign(), 0, 0).asFloat(), b); 108 else if (tcu::Float32(b).isZero()) 109 return getUlpDiff(a, tcu::Float32::construct(tcu::Float32(a).sign(), 0, 0).asFloat()); 110 else 111 return getUlpDiff(a, b); 112} 113 114inline bool supportsSignedZero (glu::Precision precision) 115{ 116 // \note GLSL ES 3.1 doesn't really require support for -0, but we require it for highp 117 // as it is very widely supported. 118 return precision == glu::PRECISION_HIGHP; 119} 120 121inline float getEpsFromMaxUlpDiff (float value, deUint32 ulpDiff) 122{ 123 const int exp = tcu::Float32(value).exponent(); 124 return tcu::Float32::construct(+1, exp, (1u<<23) | ulpDiff).asFloat() - tcu::Float32::construct(+1, exp, 1u<<23).asFloat(); 125} 126 127inline deUint32 getMaxUlpDiffFromBits (int numAccurateBits) 128{ 129 const int numGarbageBits = 23-numAccurateBits; 130 const deUint32 mask = (1u<<numGarbageBits)-1u; 131 132 return mask; 133} 134 135inline float getEpsFromBits (float value, int numAccurateBits) 136{ 137 return getEpsFromMaxUlpDiff(value, getMaxUlpDiffFromBits(numAccurateBits)); 138} 139 140static int getMinMantissaBits (glu::Precision precision) 141{ 142 const int bits[] = 143 { 144 7, // lowp 145 10, // mediump 146 23 // highp 147 }; 148 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(bits) == glu::PRECISION_LAST); 149 DE_ASSERT(de::inBounds<int>(precision, 0, DE_LENGTH_OF_ARRAY(bits))); 150 return bits[precision]; 151} 152 153static int getMaxNormalizedValueExponent (glu::Precision precision) 154{ 155 const int exponent[] = 156 { 157 0, // lowp 158 13, // mediump 159 127 // highp 160 }; 161 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(exponent) == glu::PRECISION_LAST); 162 DE_ASSERT(de::inBounds<int>(precision, 0, DE_LENGTH_OF_ARRAY(exponent))); 163 return exponent[precision]; 164} 165 166static int getMinNormalizedValueExponent (glu::Precision precision) 167{ 168 const int exponent[] = 169 { 170 -7, // lowp 171 -13, // mediump 172 -126 // highp 173 }; 174 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(exponent) == glu::PRECISION_LAST); 175 DE_ASSERT(de::inBounds<int>(precision, 0, DE_LENGTH_OF_ARRAY(exponent))); 176 return exponent[precision]; 177} 178 179static float makeFloatRepresentable (float f, glu::Precision precision) 180{ 181 if (precision == glu::PRECISION_HIGHP) 182 { 183 // \note: assuming f is not extended-precision 184 return f; 185 } 186 else 187 { 188 const int numMantissaBits = getMinMantissaBits(precision); 189 const int maxNormalizedValueExponent = getMaxNormalizedValueExponent(precision); 190 const int minNormalizedValueExponent = getMinNormalizedValueExponent(precision); 191 const deUint32 representableMantissaMask = ((deUint32(1) << numMantissaBits) - 1) << (23 - (deUint32)numMantissaBits); 192 const float largestRepresentableValue = tcu::Float32::constructBits(+1, maxNormalizedValueExponent, ((1u << numMantissaBits) - 1u) << (23u - (deUint32)numMantissaBits)).asFloat(); 193 const bool zeroNotRepresentable = (precision == glu::PRECISION_LOWP); 194 195 // if zero is not required to be representable, use smallest positive non-subnormal value 196 const float zeroValue = (zeroNotRepresentable) ? (tcu::Float32::constructBits(+1, minNormalizedValueExponent, 1).asFloat()) : (0.0f); 197 198 const tcu::Float32 float32Representation (f); 199 200 if (float32Representation.exponent() < minNormalizedValueExponent) 201 { 202 // flush too small values to zero 203 return zeroValue; 204 } 205 else if (float32Representation.exponent() > maxNormalizedValueExponent) 206 { 207 // clamp too large values 208 return (float32Representation.sign() == +1) ? (largestRepresentableValue) : (-largestRepresentableValue); 209 } 210 else 211 { 212 // remove unrepresentable mantissa bits 213 const tcu::Float32 targetRepresentation(tcu::Float32::constructBits(float32Representation.sign(), 214 float32Representation.exponent(), 215 float32Representation.mantissaBits() & representableMantissaMask)); 216 217 return targetRepresentation.asFloat(); 218 } 219 } 220} 221 222// CommonFunctionCase 223 224class CommonFunctionCase : public TestCase 225{ 226public: 227 CommonFunctionCase (Context& context, const char* name, const char* description, glu::ShaderType shaderType); 228 ~CommonFunctionCase (void); 229 230 void init (void); 231 void deinit (void); 232 IterateResult iterate (void); 233 234protected: 235 CommonFunctionCase (const CommonFunctionCase& other); 236 CommonFunctionCase& operator= (const CommonFunctionCase& other); 237 238 virtual void getInputValues (int numValues, void* const* values) const = 0; 239 virtual bool compare (const void* const* inputs, const void* const* outputs) = 0; 240 241 glu::ShaderType m_shaderType; 242 ShaderSpec m_spec; 243 int m_numValues; 244 245 std::ostringstream m_failMsg; //!< Comparison failure help message. 246 247private: 248 ShaderExecutor* m_executor; 249}; 250 251CommonFunctionCase::CommonFunctionCase (Context& context, const char* name, const char* description, glu::ShaderType shaderType) 252 : TestCase (context, name, description) 253 , m_shaderType (shaderType) 254 , m_numValues (100) 255 , m_executor (DE_NULL) 256{ 257} 258 259CommonFunctionCase::~CommonFunctionCase (void) 260{ 261 CommonFunctionCase::deinit(); 262} 263 264void CommonFunctionCase::init (void) 265{ 266 DE_ASSERT(!m_executor); 267 268 glu::ContextType contextType = m_context.getRenderContext().getType(); 269 m_spec.version = glu::getContextTypeGLSLVersion(contextType); 270 271 m_executor = createExecutor(m_context.getRenderContext(), m_shaderType, m_spec); 272 m_testCtx.getLog() << m_executor; 273 274 if (!m_executor->isOk()) 275 throw tcu::TestError("Compile failed"); 276} 277 278void CommonFunctionCase::deinit (void) 279{ 280 delete m_executor; 281 m_executor = DE_NULL; 282} 283 284static vector<int> getScalarSizes (const vector<Symbol>& symbols) 285{ 286 vector<int> sizes(symbols.size()); 287 for (int ndx = 0; ndx < (int)symbols.size(); ++ndx) 288 sizes[ndx] = symbols[ndx].varType.getScalarSize(); 289 return sizes; 290} 291 292static int computeTotalScalarSize (const vector<Symbol>& symbols) 293{ 294 int totalSize = 0; 295 for (vector<Symbol>::const_iterator sym = symbols.begin(); sym != symbols.end(); ++sym) 296 totalSize += sym->varType.getScalarSize(); 297 return totalSize; 298} 299 300static vector<void*> getInputOutputPointers (const vector<Symbol>& symbols, vector<deUint32>& data, const int numValues) 301{ 302 vector<void*> pointers (symbols.size()); 303 int curScalarOffset = 0; 304 305 for (int varNdx = 0; varNdx < (int)symbols.size(); ++varNdx) 306 { 307 const Symbol& var = symbols[varNdx]; 308 const int scalarSize = var.varType.getScalarSize(); 309 310 // Uses planar layout as input/output specs do not support strides. 311 pointers[varNdx] = &data[curScalarOffset]; 312 curScalarOffset += scalarSize*numValues; 313 } 314 315 DE_ASSERT(curScalarOffset == (int)data.size()); 316 317 return pointers; 318} 319 320// \todo [2013-08-08 pyry] Make generic utility and move to glu? 321 322struct HexFloat 323{ 324 const float value; 325 HexFloat (const float value_) : value(value_) {} 326}; 327 328std::ostream& operator<< (std::ostream& str, const HexFloat& v) 329{ 330 return str << v.value << " / " << tcu::toHex(tcu::Float32(v.value).bits()); 331} 332 333struct HexBool 334{ 335 const deUint32 value; 336 HexBool (const deUint32 value_) : value(value_) {} 337}; 338 339std::ostream& operator<< (std::ostream& str, const HexBool& v) 340{ 341 return str << (v.value ? "true" : "false") << " / " << tcu::toHex(v.value); 342} 343 344struct VarValue 345{ 346 const glu::VarType& type; 347 const void* value; 348 349 VarValue (const glu::VarType& type_, const void* value_) : type(type_), value(value_) {} 350}; 351 352std::ostream& operator<< (std::ostream& str, const VarValue& varValue) 353{ 354 DE_ASSERT(varValue.type.isBasicType()); 355 356 const glu::DataType basicType = varValue.type.getBasicType(); 357 const glu::DataType scalarType = glu::getDataTypeScalarType(basicType); 358 const int numComponents = glu::getDataTypeScalarSize(basicType); 359 360 if (numComponents > 1) 361 str << glu::getDataTypeName(basicType) << "("; 362 363 for (int compNdx = 0; compNdx < numComponents; compNdx++) 364 { 365 if (compNdx != 0) 366 str << ", "; 367 368 switch (scalarType) 369 { 370 case glu::TYPE_FLOAT: str << HexFloat(((const float*)varValue.value)[compNdx]); break; 371 case glu::TYPE_INT: str << ((const deInt32*)varValue.value)[compNdx]; break; 372 case glu::TYPE_UINT: str << tcu::toHex(((const deUint32*)varValue.value)[compNdx]); break; 373 case glu::TYPE_BOOL: str << HexBool(((const deUint32*)varValue.value)[compNdx]); break; 374 375 default: 376 DE_ASSERT(false); 377 } 378 } 379 380 if (numComponents > 1) 381 str << ")"; 382 383 return str; 384} 385 386CommonFunctionCase::IterateResult CommonFunctionCase::iterate (void) 387{ 388 const int numInputScalars = computeTotalScalarSize(m_spec.inputs); 389 const int numOutputScalars = computeTotalScalarSize(m_spec.outputs); 390 vector<deUint32> inputData (numInputScalars * m_numValues); 391 vector<deUint32> outputData (numOutputScalars * m_numValues); 392 const vector<void*> inputPointers = getInputOutputPointers(m_spec.inputs, inputData, m_numValues); 393 const vector<void*> outputPointers = getInputOutputPointers(m_spec.outputs, outputData, m_numValues); 394 395 // Initialize input data. 396 getInputValues(m_numValues, &inputPointers[0]); 397 398 // Execute shader. 399 m_executor->useProgram(); 400 m_executor->execute(m_numValues, &inputPointers[0], &outputPointers[0]); 401 402 // Compare results. 403 { 404 const vector<int> inScalarSizes = getScalarSizes(m_spec.inputs); 405 const vector<int> outScalarSizes = getScalarSizes(m_spec.outputs); 406 vector<void*> curInputPtr (inputPointers.size()); 407 vector<void*> curOutputPtr (outputPointers.size()); 408 int numFailed = 0; 409 410 for (int valNdx = 0; valNdx < m_numValues; valNdx++) 411 { 412 // Set up pointers for comparison. 413 for (int inNdx = 0; inNdx < (int)curInputPtr.size(); ++inNdx) 414 curInputPtr[inNdx] = (deUint32*)inputPointers[inNdx] + inScalarSizes[inNdx]*valNdx; 415 416 for (int outNdx = 0; outNdx < (int)curOutputPtr.size(); ++outNdx) 417 curOutputPtr[outNdx] = (deUint32*)outputPointers[outNdx] + outScalarSizes[outNdx]*valNdx; 418 419 if (!compare(&curInputPtr[0], &curOutputPtr[0])) 420 { 421 // \todo [2013-08-08 pyry] We probably want to log reference value as well? 422 423 m_testCtx.getLog() << TestLog::Message << "ERROR: comparison failed for value " << valNdx << ":\n " << m_failMsg.str() << TestLog::EndMessage; 424 425 m_testCtx.getLog() << TestLog::Message << " inputs:" << TestLog::EndMessage; 426 for (int inNdx = 0; inNdx < (int)curInputPtr.size(); inNdx++) 427 m_testCtx.getLog() << TestLog::Message << " " << m_spec.inputs[inNdx].name << " = " 428 << VarValue(m_spec.inputs[inNdx].varType, curInputPtr[inNdx]) 429 << TestLog::EndMessage; 430 431 m_testCtx.getLog() << TestLog::Message << " outputs:" << TestLog::EndMessage; 432 for (int outNdx = 0; outNdx < (int)curOutputPtr.size(); outNdx++) 433 m_testCtx.getLog() << TestLog::Message << " " << m_spec.outputs[outNdx].name << " = " 434 << VarValue(m_spec.outputs[outNdx].varType, curOutputPtr[outNdx]) 435 << TestLog::EndMessage; 436 437 m_failMsg.str(""); 438 m_failMsg.clear(); 439 numFailed += 1; 440 } 441 } 442 443 m_testCtx.getLog() << TestLog::Message << (m_numValues - numFailed) << " / " << m_numValues << " values passed" << TestLog::EndMessage; 444 445 m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, 446 numFailed == 0 ? "Pass" : "Result comparison failed"); 447 } 448 449 return STOP; 450} 451 452static std::string getCommonFuncCaseName (glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType) 453{ 454 return string(glu::getDataTypeName(baseType)) + getPrecisionPostfix(precision) + getShaderTypePostfix(shaderType); 455} 456 457class AbsCase : public CommonFunctionCase 458{ 459public: 460 AbsCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType) 461 : CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "abs", shaderType) 462 { 463 m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision))); 464 m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision))); 465 m_spec.source = "out0 = abs(in0);"; 466 } 467 468 void getInputValues (int numValues, void* const* values) const 469 { 470 const Vec2 floatRanges[] = 471 { 472 Vec2(-2.0f, 2.0f), // lowp 473 Vec2(-1e3f, 1e3f), // mediump 474 Vec2(-1e7f, 1e7f) // highp 475 }; 476 const IVec2 intRanges[] = 477 { 478 IVec2(-(1<<7)+1, (1<<7)-1), 479 IVec2(-(1<<15)+1, (1<<15)-1), 480 IVec2(0x80000001, 0x7fffffff) 481 }; 482 483 de::Random rnd (deStringHash(getName()) ^ 0x235facu); 484 const glu::DataType type = m_spec.inputs[0].varType.getBasicType(); 485 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision(); 486 const int scalarSize = glu::getDataTypeScalarSize(type); 487 488 if (glu::isDataTypeFloatOrVec(type)) 489 fillRandomScalars(rnd, floatRanges[precision].x(), floatRanges[precision].y(), values[0], numValues*scalarSize); 490 else 491 fillRandomScalars(rnd, intRanges[precision].x(), intRanges[precision].y(), values[0], numValues*scalarSize); 492 } 493 494 bool compare (const void* const* inputs, const void* const* outputs) 495 { 496 const glu::DataType type = m_spec.inputs[0].varType.getBasicType(); 497 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision(); 498 const int scalarSize = glu::getDataTypeScalarSize(type); 499 500 if (glu::isDataTypeFloatOrVec(type)) 501 { 502 const int mantissaBits = getMinMantissaBits(precision); 503 const deUint32 maxUlpDiff = (1u<<(23-mantissaBits))-1u; 504 505 for (int compNdx = 0; compNdx < scalarSize; compNdx++) 506 { 507 const float in0 = ((const float*)inputs[0])[compNdx]; 508 const float out0 = ((const float*)outputs[0])[compNdx]; 509 const float ref0 = de::abs(in0); 510 const deUint32 ulpDiff0 = getUlpDiff(out0, ref0); 511 512 if (ulpDiff0 > maxUlpDiff) 513 { 514 m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref0) << " with ULP threshold " << maxUlpDiff << ", got ULP diff " << ulpDiff0; 515 return false; 516 } 517 } 518 } 519 else 520 { 521 for (int compNdx = 0; compNdx < scalarSize; compNdx++) 522 { 523 const int in0 = ((const int*)inputs[0])[compNdx]; 524 const int out0 = ((const int*)outputs[0])[compNdx]; 525 const int ref0 = de::abs(in0); 526 527 if (out0 != ref0) 528 { 529 m_failMsg << "Expected [" << compNdx << "] = " << ref0; 530 return false; 531 } 532 } 533 } 534 535 return true; 536 } 537}; 538 539class SignCase : public CommonFunctionCase 540{ 541public: 542 SignCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType) 543 : CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "sign", shaderType) 544 { 545 m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision))); 546 m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision))); 547 m_spec.source = "out0 = sign(in0);"; 548 } 549 550 void getInputValues (int numValues, void* const* values) const 551 { 552 const Vec2 floatRanges[] = 553 { 554 Vec2(-2.0f, 2.0f), // lowp 555 Vec2(-1e4f, 1e4f), // mediump - note: may end up as inf 556 Vec2(-1e8f, 1e8f) // highp - note: may end up as inf 557 }; 558 const IVec2 intRanges[] = 559 { 560 IVec2(-(1<<7), (1<<7)-1), 561 IVec2(-(1<<15), (1<<15)-1), 562 IVec2(0x80000000, 0x7fffffff) 563 }; 564 565 de::Random rnd (deStringHash(getName()) ^ 0x324u); 566 const glu::DataType type = m_spec.inputs[0].varType.getBasicType(); 567 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision(); 568 const int scalarSize = glu::getDataTypeScalarSize(type); 569 570 if (glu::isDataTypeFloatOrVec(type)) 571 { 572 // Special cases. 573 std::fill((float*)values[0], (float*)values[0] + scalarSize, +1.0f); 574 std::fill((float*)values[0] + scalarSize*1, (float*)values[0] + scalarSize*2, -1.0f); 575 std::fill((float*)values[0] + scalarSize*2, (float*)values[0] + scalarSize*3, 0.0f); 576 fillRandomScalars(rnd, floatRanges[precision].x(), floatRanges[precision].y(), (float*)values[0] + scalarSize*3, (numValues-3)*scalarSize); 577 } 578 else 579 { 580 std::fill((int*)values[0], (int*)values[0] + scalarSize, +1); 581 std::fill((int*)values[0] + scalarSize*1, (int*)values[0] + scalarSize*2, -1); 582 std::fill((int*)values[0] + scalarSize*2, (int*)values[0] + scalarSize*3, 0); 583 fillRandomScalars(rnd, intRanges[precision].x(), intRanges[precision].y(), (int*)values[0] + scalarSize*3, (numValues-3)*scalarSize); 584 } 585 } 586 587 bool compare (const void* const* inputs, const void* const* outputs) 588 { 589 const glu::DataType type = m_spec.inputs[0].varType.getBasicType(); 590 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision(); 591 const int scalarSize = glu::getDataTypeScalarSize(type); 592 593 if (glu::isDataTypeFloatOrVec(type)) 594 { 595 // Both highp and mediump should be able to represent -1, 0, and +1 exactly 596 const deUint32 maxUlpDiff = precision == glu::PRECISION_LOWP ? getMaxUlpDiffFromBits(getMinMantissaBits(precision)) : 0; 597 598 for (int compNdx = 0; compNdx < scalarSize; compNdx++) 599 { 600 const float in0 = ((const float*)inputs[0])[compNdx]; 601 const float out0 = ((const float*)outputs[0])[compNdx]; 602 const float ref0 = in0 < 0.0f ? -1.0f : 603 in0 > 0.0f ? +1.0f : 0.0f; 604 const deUint32 ulpDiff0 = getUlpDiff(out0, ref0); 605 606 if (ulpDiff0 > maxUlpDiff) 607 { 608 m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref0) << " with ULP threshold " << maxUlpDiff << ", got ULP diff " << ulpDiff0; 609 return false; 610 } 611 } 612 } 613 else 614 { 615 for (int compNdx = 0; compNdx < scalarSize; compNdx++) 616 { 617 const int in0 = ((const int*)inputs[0])[compNdx]; 618 const int out0 = ((const int*)outputs[0])[compNdx]; 619 const int ref0 = in0 < 0 ? -1 : 620 in0 > 0 ? +1 : 0; 621 622 if (out0 != ref0) 623 { 624 m_failMsg << "Expected [" << compNdx << "] = " << ref0; 625 return false; 626 } 627 } 628 } 629 630 return true; 631 } 632}; 633 634static float roundEven (float v) 635{ 636 const float q = deFloatFrac(v); 637 const int truncated = int(v-q); 638 const int rounded = (q > 0.5f) ? (truncated + 1) : // Rounded up 639 (q == 0.5f && (truncated % 2 != 0)) ? (truncated + 1) : // Round to nearest even at 0.5 640 truncated; // Rounded down 641 642 return float(rounded); 643} 644 645class RoundEvenCase : public CommonFunctionCase 646{ 647public: 648 RoundEvenCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType) 649 : CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "roundEven", shaderType) 650 { 651 m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision))); 652 m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision))); 653 m_spec.source = "out0 = roundEven(in0);"; 654 } 655 656 void getInputValues (int numValues, void* const* values) const 657 { 658 const Vec2 ranges[] = 659 { 660 Vec2(-2.0f, 2.0f), // lowp 661 Vec2(-1e3f, 1e3f), // mediump 662 Vec2(-1e7f, 1e7f) // highp 663 }; 664 665 de::Random rnd (deStringHash(getName()) ^ 0xac23fu); 666 const glu::DataType type = m_spec.inputs[0].varType.getBasicType(); 667 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision(); 668 const int scalarSize = glu::getDataTypeScalarSize(type); 669 int numSpecialCases = 0; 670 671 // Special cases. 672 if (precision != glu::PRECISION_LOWP) 673 { 674 DE_ASSERT(numValues >= 20); 675 for (int ndx = 0; ndx < 20; ndx++) 676 { 677 const float v = de::clamp(float(ndx) - 10.5f, ranges[precision].x(), ranges[precision].y()); 678 std::fill((float*)values[0], (float*)values[0] + scalarSize, v); 679 numSpecialCases += 1; 680 } 681 } 682 683 // Random cases. 684 fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), (float*)values[0] + numSpecialCases*scalarSize, (numValues-numSpecialCases)*scalarSize); 685 686 // If precision is mediump, make sure values can be represented in fp16 exactly 687 if (precision == glu::PRECISION_MEDIUMP) 688 { 689 for (int ndx = 0; ndx < numValues*scalarSize; ndx++) 690 ((float*)values[0])[ndx] = tcu::Float16(((float*)values[0])[ndx]).asFloat(); 691 } 692 } 693 694 bool compare (const void* const* inputs, const void* const* outputs) 695 { 696 const glu::DataType type = m_spec.inputs[0].varType.getBasicType(); 697 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision(); 698 const bool hasSignedZero = supportsSignedZero(precision); 699 const int scalarSize = glu::getDataTypeScalarSize(type); 700 701 if (precision == glu::PRECISION_HIGHP || precision == glu::PRECISION_MEDIUMP) 702 { 703 // Require exact rounding result. 704 for (int compNdx = 0; compNdx < scalarSize; compNdx++) 705 { 706 const float in0 = ((const float*)inputs[0])[compNdx]; 707 const float out0 = ((const float*)outputs[0])[compNdx]; 708 const float ref = roundEven(in0); 709 710 const deUint32 ulpDiff = hasSignedZero ? getUlpDiff(out0, ref) : getUlpDiffIgnoreZeroSign(out0, ref); 711 712 if (ulpDiff > 0) 713 { 714 m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref) << ", got ULP diff " << tcu::toHex(ulpDiff); 715 return false; 716 } 717 } 718 } 719 else 720 { 721 const int mantissaBits = getMinMantissaBits(precision); 722 const deUint32 maxUlpDiff = getMaxUlpDiffFromBits(mantissaBits); // ULP diff for rounded integer value. 723 const float eps = getEpsFromBits(1.0f, mantissaBits); // epsilon for rounding bounds 724 725 for (int compNdx = 0; compNdx < scalarSize; compNdx++) 726 { 727 const float in0 = ((const float*)inputs[0])[compNdx]; 728 const float out0 = ((const float*)outputs[0])[compNdx]; 729 const int minRes = int(roundEven(in0-eps)); 730 const int maxRes = int(roundEven(in0+eps)); 731 bool anyOk = false; 732 733 for (int roundedVal = minRes; roundedVal <= maxRes; roundedVal++) 734 { 735 const deUint32 ulpDiff = getUlpDiffIgnoreZeroSign(out0, float(roundedVal)); 736 737 if (ulpDiff <= maxUlpDiff) 738 { 739 anyOk = true; 740 break; 741 } 742 } 743 744 if (!anyOk) 745 { 746 m_failMsg << "Expected [" << compNdx << "] = [" << minRes << ", " << maxRes << "] with ULP threshold " << tcu::toHex(maxUlpDiff); 747 return false; 748 } 749 } 750 } 751 752 return true; 753 } 754}; 755 756class ModfCase : public CommonFunctionCase 757{ 758public: 759 ModfCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType) 760 : CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "modf", shaderType) 761 { 762 m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision))); 763 m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision))); 764 m_spec.outputs.push_back(Symbol("out1", glu::VarType(baseType, precision))); 765 m_spec.source = "out0 = modf(in0, out1);"; 766 } 767 768 void getInputValues (int numValues, void* const* values) const 769 { 770 const Vec2 ranges[] = 771 { 772 Vec2(-2.0f, 2.0f), // lowp 773 Vec2(-1e3f, 1e3f), // mediump 774 Vec2(-1e7f, 1e7f) // highp 775 }; 776 777 de::Random rnd (deStringHash(getName()) ^ 0xac23fu); 778 const glu::DataType type = m_spec.inputs[0].varType.getBasicType(); 779 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision(); 780 const int scalarSize = glu::getDataTypeScalarSize(type); 781 782 fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), values[0], numValues*scalarSize); 783 } 784 785 bool compare (const void* const* inputs, const void* const* outputs) 786 { 787 const glu::DataType type = m_spec.inputs[0].varType.getBasicType(); 788 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision(); 789 const bool hasZeroSign = supportsSignedZero(precision); 790 const int scalarSize = glu::getDataTypeScalarSize(type); 791 792 const int mantissaBits = getMinMantissaBits(precision); 793 794 for (int compNdx = 0; compNdx < scalarSize; compNdx++) 795 { 796 const float in0 = ((const float*)inputs[0])[compNdx]; 797 const float out0 = ((const float*)outputs[0])[compNdx]; 798 const float out1 = ((const float*)outputs[1])[compNdx]; 799 800 const float refOut1 = float(int(in0)); 801 const float refOut0 = in0 - refOut1; 802 803 const int bitsLost = precision != glu::PRECISION_HIGHP ? numBitsLostInOp(in0, refOut0) : 0; 804 const deUint32 maxUlpDiff = getMaxUlpDiffFromBits(de::max(mantissaBits - bitsLost, 0)); 805 806 const float resSum = out0 + out1; 807 808 const deUint32 ulpDiff = hasZeroSign ? getUlpDiff(resSum, in0) : getUlpDiffIgnoreZeroSign(resSum, in0); 809 810 if (ulpDiff > maxUlpDiff) 811 { 812 m_failMsg << "Expected [" << compNdx << "] = (" << HexFloat(refOut0) << ") + (" << HexFloat(refOut1) << ") = " << HexFloat(in0) << " with ULP threshold " 813 << tcu::toHex(maxUlpDiff) << ", got ULP diff " << tcu::toHex(ulpDiff); 814 return false; 815 } 816 } 817 818 return true; 819 } 820}; 821 822class IsnanCase : public CommonFunctionCase 823{ 824public: 825 IsnanCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType) 826 : CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "isnan", shaderType) 827 { 828 DE_ASSERT(glu::isDataTypeFloatOrVec(baseType)); 829 830 const int vecSize = glu::getDataTypeScalarSize(baseType); 831 const glu::DataType boolType = vecSize > 1 ? glu::getDataTypeBoolVec(vecSize) : glu::TYPE_BOOL; 832 833 m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision))); 834 m_spec.outputs.push_back(Symbol("out0", glu::VarType(boolType, glu::PRECISION_LAST))); 835 m_spec.source = "out0 = isnan(in0);"; 836 } 837 838 void getInputValues (int numValues, void* const* values) const 839 { 840 de::Random rnd (deStringHash(getName()) ^ 0xc2a39fu); 841 const glu::DataType type = m_spec.inputs[0].varType.getBasicType(); 842 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision(); 843 const int scalarSize = glu::getDataTypeScalarSize(type); 844 const int mantissaBits = getMinMantissaBits(precision); 845 const deUint32 mantissaMask = ~getMaxUlpDiffFromBits(mantissaBits) & ((1u<<23)-1u); 846 847 for (int valNdx = 0; valNdx < numValues*scalarSize; valNdx++) 848 { 849 const bool isNan = rnd.getFloat() > 0.3f; 850 const bool isInf = !isNan && rnd.getFloat() > 0.4f; 851 const deUint32 mantissa = !isInf ? ((1u<<22) | (rnd.getUint32() & mantissaMask)) : 0; 852 const deUint32 exp = !isNan && !isInf ? (rnd.getUint32() & 0x7fu) : 0xffu; 853 const deUint32 sign = rnd.getUint32() & 0x1u; 854 const deUint32 value = (sign << 31) | (exp << 23) | mantissa; 855 856 DE_ASSERT(tcu::Float32(value).isInf() == isInf && tcu::Float32(value).isNaN() == isNan); 857 858 ((deUint32*)values[0])[valNdx] = value; 859 } 860 } 861 862 bool compare (const void* const* inputs, const void* const* outputs) 863 { 864 const glu::DataType type = m_spec.inputs[0].varType.getBasicType(); 865 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision(); 866 const int scalarSize = glu::getDataTypeScalarSize(type); 867 868 if (precision == glu::PRECISION_HIGHP) 869 { 870 // Only highp is required to support inf/nan 871 for (int compNdx = 0; compNdx < scalarSize; compNdx++) 872 { 873 const float in0 = ((const float*)inputs[0])[compNdx]; 874 const bool out0 = ((const deUint32*)outputs[0])[compNdx] != 0; 875 const bool ref = tcu::Float32(in0).isNaN(); 876 877 if (out0 != ref) 878 { 879 m_failMsg << "Expected [" << compNdx << "] = " << (ref ? "true" : "false"); 880 return false; 881 } 882 } 883 } 884 else if (precision == glu::PRECISION_MEDIUMP || precision == glu::PRECISION_LOWP) 885 { 886 // NaN support is optional, check that inputs that are not NaN don't result in true. 887 for (int compNdx = 0; compNdx < scalarSize; compNdx++) 888 { 889 const float in0 = ((const float*)inputs[0])[compNdx]; 890 const bool out0 = ((const deUint32*)outputs[0])[compNdx] != 0; 891 const bool ref = tcu::Float32(in0).isNaN(); 892 893 if (!ref && out0) 894 { 895 m_failMsg << "Expected [" << compNdx << "] = " << (ref ? "true" : "false"); 896 return false; 897 } 898 } 899 } 900 901 return true; 902 } 903}; 904 905class IsinfCase : public CommonFunctionCase 906{ 907public: 908 IsinfCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType) 909 : CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "isinf", shaderType) 910 { 911 DE_ASSERT(glu::isDataTypeFloatOrVec(baseType)); 912 913 const int vecSize = glu::getDataTypeScalarSize(baseType); 914 const glu::DataType boolType = vecSize > 1 ? glu::getDataTypeBoolVec(vecSize) : glu::TYPE_BOOL; 915 916 m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision))); 917 m_spec.outputs.push_back(Symbol("out0", glu::VarType(boolType, glu::PRECISION_LAST))); 918 m_spec.source = "out0 = isinf(in0);"; 919 } 920 921 void getInputValues (int numValues, void* const* values) const 922 { 923 de::Random rnd (deStringHash(getName()) ^ 0xc2a39fu); 924 const glu::DataType type = m_spec.inputs[0].varType.getBasicType(); 925 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision(); 926 const int scalarSize = glu::getDataTypeScalarSize(type); 927 const int mantissaBits = getMinMantissaBits(precision); 928 const deUint32 mantissaMask = ~getMaxUlpDiffFromBits(mantissaBits) & ((1u<<23)-1u); 929 930 for (int valNdx = 0; valNdx < numValues*scalarSize; valNdx++) 931 { 932 const bool isInf = rnd.getFloat() > 0.3f; 933 const bool isNan = !isInf && rnd.getFloat() > 0.4f; 934 const deUint32 mantissa = !isInf ? ((1u<<22) | (rnd.getUint32() & mantissaMask)) : 0; 935 const deUint32 exp = !isNan && !isInf ? (rnd.getUint32() & 0x7fu) : 0xffu; 936 const deUint32 sign = rnd.getUint32() & 0x1u; 937 const deUint32 value = (sign << 31) | (exp << 23) | mantissa; 938 939 DE_ASSERT(tcu::Float32(value).isInf() == isInf && tcu::Float32(value).isNaN() == isNan); 940 941 ((deUint32*)values[0])[valNdx] = value; 942 } 943 } 944 945 bool compare (const void* const* inputs, const void* const* outputs) 946 { 947 const glu::DataType type = m_spec.inputs[0].varType.getBasicType(); 948 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision(); 949 const int scalarSize = glu::getDataTypeScalarSize(type); 950 951 if (precision == glu::PRECISION_HIGHP) 952 { 953 // Only highp is required to support inf/nan 954 for (int compNdx = 0; compNdx < scalarSize; compNdx++) 955 { 956 const float in0 = ((const float*)inputs[0])[compNdx]; 957 const bool out0 = ((const deUint32*)outputs[0])[compNdx] != 0; 958 const bool ref = tcu::Float32(in0).isInf(); 959 960 if (out0 != ref) 961 { 962 m_failMsg << "Expected [" << compNdx << "] = " << HexBool(ref); 963 return false; 964 } 965 } 966 } 967 else if (precision == glu::PRECISION_MEDIUMP) 968 { 969 // Inf support is optional, check that inputs that are not Inf in mediump don't result in true. 970 for (int compNdx = 0; compNdx < scalarSize; compNdx++) 971 { 972 const float in0 = ((const float*)inputs[0])[compNdx]; 973 const bool out0 = ((const deUint32*)outputs[0])[compNdx] != 0; 974 const bool ref = tcu::Float16(in0).isInf(); 975 976 if (!ref && out0) 977 { 978 m_failMsg << "Expected [" << compNdx << "] = " << (ref ? "true" : "false"); 979 return false; 980 } 981 } 982 } 983 // else: no verification can be performed 984 985 return true; 986 } 987}; 988 989class FloatBitsToUintIntCase : public CommonFunctionCase 990{ 991public: 992 FloatBitsToUintIntCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType, bool outIsSigned) 993 : CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), outIsSigned ? "floatBitsToInt" : "floatBitsToUint", shaderType) 994 { 995 const int vecSize = glu::getDataTypeScalarSize(baseType); 996 const glu::DataType intType = outIsSigned ? (vecSize > 1 ? glu::getDataTypeIntVec(vecSize) : glu::TYPE_INT) 997 : (vecSize > 1 ? glu::getDataTypeUintVec(vecSize) : glu::TYPE_UINT); 998 999 m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision))); 1000 m_spec.outputs.push_back(Symbol("out0", glu::VarType(intType, glu::PRECISION_HIGHP))); 1001 m_spec.source = outIsSigned ? "out0 = floatBitsToInt(in0);" : "out0 = floatBitsToUint(in0);"; 1002 } 1003 1004 void getInputValues (int numValues, void* const* values) const 1005 { 1006 const Vec2 ranges[] = 1007 { 1008 Vec2(-2.0f, 2.0f), // lowp 1009 Vec2(-1e3f, 1e3f), // mediump 1010 Vec2(-1e7f, 1e7f) // highp 1011 }; 1012 1013 de::Random rnd (deStringHash(getName()) ^ 0x2790au); 1014 const glu::DataType type = m_spec.inputs[0].varType.getBasicType(); 1015 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision(); 1016 const int scalarSize = glu::getDataTypeScalarSize(type); 1017 1018 fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), values[0], numValues*scalarSize); 1019 } 1020 1021 bool compare (const void* const* inputs, const void* const* outputs) 1022 { 1023 const glu::DataType type = m_spec.inputs[0].varType.getBasicType(); 1024 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision(); 1025 const int scalarSize = glu::getDataTypeScalarSize(type); 1026 1027 const int mantissaBits = getMinMantissaBits(precision); 1028 const int maxUlpDiff = getMaxUlpDiffFromBits(mantissaBits); 1029 1030 for (int compNdx = 0; compNdx < scalarSize; compNdx++) 1031 { 1032 const float in0 = ((const float*)inputs[0])[compNdx]; 1033 const deUint32 out0 = ((const deUint32*)outputs[0])[compNdx]; 1034 const deUint32 refOut0 = tcu::Float32(in0).bits(); 1035 const int ulpDiff = de::abs((int)out0 - (int)refOut0); 1036 1037 if (ulpDiff > maxUlpDiff) 1038 { 1039 m_failMsg << "Expected [" << compNdx << "] = " << tcu::toHex(refOut0) << " with threshold " 1040 << tcu::toHex(maxUlpDiff) << ", got diff " << tcu::toHex(ulpDiff); 1041 return false; 1042 } 1043 } 1044 1045 return true; 1046 } 1047}; 1048 1049class FloatBitsToIntCase : public FloatBitsToUintIntCase 1050{ 1051public: 1052 FloatBitsToIntCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType) 1053 : FloatBitsToUintIntCase(context, baseType, precision, shaderType, true) 1054 { 1055 } 1056}; 1057 1058class FloatBitsToUintCase : public FloatBitsToUintIntCase 1059{ 1060public: 1061 FloatBitsToUintCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType) 1062 : FloatBitsToUintIntCase(context, baseType, precision, shaderType, false) 1063 { 1064 } 1065}; 1066 1067class BitsToFloatCase : public CommonFunctionCase 1068{ 1069public: 1070 BitsToFloatCase (Context& context, glu::DataType baseType, glu::ShaderType shaderType) 1071 : CommonFunctionCase(context, getCommonFuncCaseName(baseType, glu::PRECISION_HIGHP, shaderType).c_str(), glu::isDataTypeIntOrIVec(baseType) ? "intBitsToFloat" : "uintBitsToFloat", shaderType) 1072 { 1073 const bool inIsSigned = glu::isDataTypeIntOrIVec(baseType); 1074 const int vecSize = glu::getDataTypeScalarSize(baseType); 1075 const glu::DataType floatType = vecSize > 1 ? glu::getDataTypeFloatVec(vecSize) : glu::TYPE_FLOAT; 1076 1077 m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, glu::PRECISION_HIGHP))); 1078 m_spec.outputs.push_back(Symbol("out0", glu::VarType(floatType, glu::PRECISION_HIGHP))); 1079 m_spec.source = inIsSigned ? "out0 = intBitsToFloat(in0);" : "out0 = uintBitsToFloat(in0);"; 1080 } 1081 1082 void getInputValues (int numValues, void* const* values) const 1083 { 1084 de::Random rnd (deStringHash(getName()) ^ 0xbbb225u); 1085 const glu::DataType type = m_spec.inputs[0].varType.getBasicType(); 1086 const int scalarSize = glu::getDataTypeScalarSize(type); 1087 const Vec2 range (-1e8f, +1e8f); 1088 1089 // \note Filled as floats. 1090 fillRandomScalars(rnd, range.x(), range.y(), values[0], numValues*scalarSize); 1091 } 1092 1093 bool compare (const void* const* inputs, const void* const* outputs) 1094 { 1095 const glu::DataType type = m_spec.inputs[0].varType.getBasicType(); 1096 const int scalarSize = glu::getDataTypeScalarSize(type); 1097 const deUint32 maxUlpDiff = 0; 1098 1099 for (int compNdx = 0; compNdx < scalarSize; compNdx++) 1100 { 1101 const float in0 = ((const float*)inputs[0])[compNdx]; 1102 const float out0 = ((const float*)outputs[0])[compNdx]; 1103 const deUint32 ulpDiff = getUlpDiff(in0, out0); 1104 1105 if (ulpDiff > maxUlpDiff) 1106 { 1107 m_failMsg << "Expected [" << compNdx << "] = " << tcu::toHex(tcu::Float32(in0).bits()) << " with ULP threshold " 1108 << tcu::toHex(maxUlpDiff) << ", got ULP diff " << tcu::toHex(ulpDiff); 1109 return false; 1110 } 1111 } 1112 1113 return true; 1114 } 1115}; 1116 1117class FloorCase : public CommonFunctionCase 1118{ 1119public: 1120 FloorCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType) 1121 : CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "floor", shaderType) 1122 { 1123 m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision))); 1124 m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision))); 1125 m_spec.source = "out0 = floor(in0);"; 1126 } 1127 1128 void getInputValues (int numValues, void* const* values) const 1129 { 1130 const Vec2 ranges[] = 1131 { 1132 Vec2(-2.0f, 2.0f), // lowp 1133 Vec2(-1e3f, 1e3f), // mediump 1134 Vec2(-1e7f, 1e7f) // highp 1135 }; 1136 1137 de::Random rnd (deStringHash(getName()) ^ 0xac23fu); 1138 const glu::DataType type = m_spec.inputs[0].varType.getBasicType(); 1139 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision(); 1140 const int scalarSize = glu::getDataTypeScalarSize(type); 1141 // Random cases. 1142 fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), (float*)values[0], numValues*scalarSize); 1143 1144 // If precision is mediump, make sure values can be represented in fp16 exactly 1145 if (precision == glu::PRECISION_MEDIUMP) 1146 { 1147 for (int ndx = 0; ndx < numValues*scalarSize; ndx++) 1148 ((float*)values[0])[ndx] = tcu::Float16(((float*)values[0])[ndx]).asFloat(); 1149 } 1150 } 1151 1152 bool compare (const void* const* inputs, const void* const* outputs) 1153 { 1154 const glu::DataType type = m_spec.inputs[0].varType.getBasicType(); 1155 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision(); 1156 const int scalarSize = glu::getDataTypeScalarSize(type); 1157 1158 if (precision == glu::PRECISION_HIGHP || precision == glu::PRECISION_MEDIUMP) 1159 { 1160 // Require exact result. 1161 for (int compNdx = 0; compNdx < scalarSize; compNdx++) 1162 { 1163 const float in0 = ((const float*)inputs[0])[compNdx]; 1164 const float out0 = ((const float*)outputs[0])[compNdx]; 1165 const float ref = deFloatFloor(in0); 1166 1167 const deUint32 ulpDiff = getUlpDiff(out0, ref); 1168 1169 if (ulpDiff > 0) 1170 { 1171 m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref) << ", got ULP diff " << tcu::toHex(ulpDiff); 1172 return false; 1173 } 1174 } 1175 } 1176 else 1177 { 1178 const int mantissaBits = getMinMantissaBits(precision); 1179 const deUint32 maxUlpDiff = getMaxUlpDiffFromBits(mantissaBits); // ULP diff for rounded integer value. 1180 const float eps = getEpsFromBits(1.0f, mantissaBits); // epsilon for rounding bounds 1181 1182 for (int compNdx = 0; compNdx < scalarSize; compNdx++) 1183 { 1184 const float in0 = ((const float*)inputs[0])[compNdx]; 1185 const float out0 = ((const float*)outputs[0])[compNdx]; 1186 const int minRes = int(deFloatFloor(in0-eps)); 1187 const int maxRes = int(deFloatFloor(in0+eps)); 1188 bool anyOk = false; 1189 1190 for (int roundedVal = minRes; roundedVal <= maxRes; roundedVal++) 1191 { 1192 const deUint32 ulpDiff = getUlpDiff(out0, float(roundedVal)); 1193 1194 if (ulpDiff <= maxUlpDiff) 1195 { 1196 anyOk = true; 1197 break; 1198 } 1199 } 1200 1201 if (!anyOk) 1202 { 1203 m_failMsg << "Expected [" << compNdx << "] = [" << minRes << ", " << maxRes << "] with ULP threshold " << tcu::toHex(maxUlpDiff); 1204 return false; 1205 } 1206 } 1207 } 1208 1209 return true; 1210 } 1211}; 1212 1213class TruncCase : public CommonFunctionCase 1214{ 1215public: 1216 TruncCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType) 1217 : CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "trunc", shaderType) 1218 { 1219 m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision))); 1220 m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision))); 1221 m_spec.source = "out0 = trunc(in0);"; 1222 } 1223 1224 void getInputValues (int numValues, void* const* values) const 1225 { 1226 const Vec2 ranges[] = 1227 { 1228 Vec2(-2.0f, 2.0f), // lowp 1229 Vec2(-1e3f, 1e3f), // mediump 1230 Vec2(-1e7f, 1e7f) // highp 1231 }; 1232 1233 de::Random rnd (deStringHash(getName()) ^ 0xac23fu); 1234 const glu::DataType type = m_spec.inputs[0].varType.getBasicType(); 1235 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision(); 1236 const int scalarSize = glu::getDataTypeScalarSize(type); 1237 const float specialCases[] = { 0.0f, -0.0f, -0.9f, 0.9f, 1.0f, -1.0f }; 1238 const int numSpecialCases = DE_LENGTH_OF_ARRAY(specialCases); 1239 1240 // Special cases 1241 for (int caseNdx = 0; caseNdx < numSpecialCases; caseNdx++) 1242 { 1243 for (int scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++) 1244 ((float*)values[0])[caseNdx*scalarSize + scalarNdx] = specialCases[caseNdx]; 1245 } 1246 1247 // Random cases. 1248 fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), (float*)values[0] + scalarSize*numSpecialCases, (numValues-numSpecialCases)*scalarSize); 1249 1250 // If precision is mediump, make sure values can be represented in fp16 exactly 1251 if (precision == glu::PRECISION_MEDIUMP) 1252 { 1253 for (int ndx = 0; ndx < numValues*scalarSize; ndx++) 1254 ((float*)values[0])[ndx] = tcu::Float16(((float*)values[0])[ndx]).asFloat(); 1255 } 1256 } 1257 1258 bool compare (const void* const* inputs, const void* const* outputs) 1259 { 1260 const glu::DataType type = m_spec.inputs[0].varType.getBasicType(); 1261 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision(); 1262 const int scalarSize = glu::getDataTypeScalarSize(type); 1263 1264 if (precision == glu::PRECISION_HIGHP || precision == glu::PRECISION_MEDIUMP) 1265 { 1266 // Require exact result. 1267 for (int compNdx = 0; compNdx < scalarSize; compNdx++) 1268 { 1269 const float in0 = ((const float*)inputs[0])[compNdx]; 1270 const float out0 = ((const float*)outputs[0])[compNdx]; 1271 const bool isNeg = tcu::Float32(in0).sign() < 0; 1272 const float ref = isNeg ? (-float(int(-in0))) : float(int(in0)); 1273 1274 // \note: trunc() function definition is a bit broad on negative zeros. Ignore result sign if zero. 1275 const deUint32 ulpDiff = getUlpDiffIgnoreZeroSign(out0, ref); 1276 1277 if (ulpDiff > 0) 1278 { 1279 m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref) << ", got ULP diff " << tcu::toHex(ulpDiff); 1280 return false; 1281 } 1282 } 1283 } 1284 else 1285 { 1286 const int mantissaBits = getMinMantissaBits(precision); 1287 const deUint32 maxUlpDiff = getMaxUlpDiffFromBits(mantissaBits); // ULP diff for rounded integer value. 1288 const float eps = getEpsFromBits(1.0f, mantissaBits); // epsilon for rounding bounds 1289 1290 for (int compNdx = 0; compNdx < scalarSize; compNdx++) 1291 { 1292 const float in0 = ((const float*)inputs[0])[compNdx]; 1293 const float out0 = ((const float*)outputs[0])[compNdx]; 1294 const int minRes = int(in0-eps); 1295 const int maxRes = int(in0+eps); 1296 bool anyOk = false; 1297 1298 for (int roundedVal = minRes; roundedVal <= maxRes; roundedVal++) 1299 { 1300 const deUint32 ulpDiff = getUlpDiffIgnoreZeroSign(out0, float(roundedVal)); 1301 1302 if (ulpDiff <= maxUlpDiff) 1303 { 1304 anyOk = true; 1305 break; 1306 } 1307 } 1308 1309 if (!anyOk) 1310 { 1311 m_failMsg << "Expected [" << compNdx << "] = [" << minRes << ", " << maxRes << "] with ULP threshold " << tcu::toHex(maxUlpDiff); 1312 return false; 1313 } 1314 } 1315 } 1316 1317 return true; 1318 } 1319}; 1320 1321class RoundCase : public CommonFunctionCase 1322{ 1323public: 1324 RoundCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType) 1325 : CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "round", shaderType) 1326 { 1327 m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision))); 1328 m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision))); 1329 m_spec.source = "out0 = round(in0);"; 1330 } 1331 1332 void getInputValues (int numValues, void* const* values) const 1333 { 1334 const Vec2 ranges[] = 1335 { 1336 Vec2(-2.0f, 2.0f), // lowp 1337 Vec2(-1e3f, 1e3f), // mediump 1338 Vec2(-1e7f, 1e7f) // highp 1339 }; 1340 1341 de::Random rnd (deStringHash(getName()) ^ 0xac23fu); 1342 const glu::DataType type = m_spec.inputs[0].varType.getBasicType(); 1343 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision(); 1344 const int scalarSize = glu::getDataTypeScalarSize(type); 1345 int numSpecialCases = 0; 1346 1347 // Special cases. 1348 if (precision != glu::PRECISION_LOWP) 1349 { 1350 DE_ASSERT(numValues >= 10); 1351 for (int ndx = 0; ndx < 10; ndx++) 1352 { 1353 const float v = de::clamp(float(ndx) - 5.5f, ranges[precision].x(), ranges[precision].y()); 1354 std::fill((float*)values[0], (float*)values[0] + scalarSize, v); 1355 numSpecialCases += 1; 1356 } 1357 } 1358 1359 // Random cases. 1360 fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), (float*)values[0] + numSpecialCases*scalarSize, (numValues-numSpecialCases)*scalarSize); 1361 1362 // If precision is mediump, make sure values can be represented in fp16 exactly 1363 if (precision == glu::PRECISION_MEDIUMP) 1364 { 1365 for (int ndx = 0; ndx < numValues*scalarSize; ndx++) 1366 ((float*)values[0])[ndx] = tcu::Float16(((float*)values[0])[ndx]).asFloat(); 1367 } 1368 } 1369 1370 bool compare (const void* const* inputs, const void* const* outputs) 1371 { 1372 const glu::DataType type = m_spec.inputs[0].varType.getBasicType(); 1373 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision(); 1374 const bool hasZeroSign = supportsSignedZero(precision); 1375 const int scalarSize = glu::getDataTypeScalarSize(type); 1376 1377 if (precision == glu::PRECISION_HIGHP || precision == glu::PRECISION_MEDIUMP) 1378 { 1379 for (int compNdx = 0; compNdx < scalarSize; compNdx++) 1380 { 1381 const float in0 = ((const float*)inputs[0])[compNdx]; 1382 const float out0 = ((const float*)outputs[0])[compNdx]; 1383 1384 if (deFloatFrac(in0) == 0.5f) 1385 { 1386 // Allow both ceil(in) and floor(in) 1387 const float ref0 = deFloatFloor(in0); 1388 const float ref1 = deFloatCeil(in0); 1389 const deUint32 ulpDiff0 = hasZeroSign ? getUlpDiff(out0, ref0) : getUlpDiffIgnoreZeroSign(out0, ref0); 1390 const deUint32 ulpDiff1 = hasZeroSign ? getUlpDiff(out0, ref1) : getUlpDiffIgnoreZeroSign(out0, ref1); 1391 1392 if (ulpDiff0 > 0 && ulpDiff1 > 0) 1393 { 1394 m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref0) << " or " << HexFloat(ref1) << ", got ULP diff " << tcu::toHex(de::min(ulpDiff0, ulpDiff1)); 1395 return false; 1396 } 1397 } 1398 else 1399 { 1400 // Require exact result 1401 const float ref = roundEven(in0); 1402 const deUint32 ulpDiff = hasZeroSign ? getUlpDiff(out0, ref) : getUlpDiffIgnoreZeroSign(out0, ref); 1403 1404 if (ulpDiff > 0) 1405 { 1406 m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref) << ", got ULP diff " << tcu::toHex(ulpDiff); 1407 return false; 1408 } 1409 } 1410 } 1411 } 1412 else 1413 { 1414 const int mantissaBits = getMinMantissaBits(precision); 1415 const deUint32 maxUlpDiff = getMaxUlpDiffFromBits(mantissaBits); // ULP diff for rounded integer value. 1416 const float eps = getEpsFromBits(1.0f, mantissaBits); // epsilon for rounding bounds 1417 1418 for (int compNdx = 0; compNdx < scalarSize; compNdx++) 1419 { 1420 const float in0 = ((const float*)inputs[0])[compNdx]; 1421 const float out0 = ((const float*)outputs[0])[compNdx]; 1422 const int minRes = int(roundEven(in0-eps)); 1423 const int maxRes = int(roundEven(in0+eps)); 1424 bool anyOk = false; 1425 1426 for (int roundedVal = minRes; roundedVal <= maxRes; roundedVal++) 1427 { 1428 const deUint32 ulpDiff = getUlpDiffIgnoreZeroSign(out0, float(roundedVal)); 1429 1430 if (ulpDiff <= maxUlpDiff) 1431 { 1432 anyOk = true; 1433 break; 1434 } 1435 } 1436 1437 if (!anyOk) 1438 { 1439 m_failMsg << "Expected [" << compNdx << "] = [" << minRes << ", " << maxRes << "] with ULP threshold " << tcu::toHex(maxUlpDiff); 1440 return false; 1441 } 1442 } 1443 } 1444 1445 return true; 1446 } 1447}; 1448 1449class CeilCase : public CommonFunctionCase 1450{ 1451public: 1452 CeilCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType) 1453 : CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "ceil", shaderType) 1454 { 1455 m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision))); 1456 m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision))); 1457 m_spec.source = "out0 = ceil(in0);"; 1458 } 1459 1460 void getInputValues (int numValues, void* const* values) const 1461 { 1462 const Vec2 ranges[] = 1463 { 1464 Vec2(-2.0f, 2.0f), // lowp 1465 Vec2(-1e3f, 1e3f), // mediump 1466 Vec2(-1e7f, 1e7f) // highp 1467 }; 1468 1469 de::Random rnd (deStringHash(getName()) ^ 0xac23fu); 1470 const glu::DataType type = m_spec.inputs[0].varType.getBasicType(); 1471 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision(); 1472 const int scalarSize = glu::getDataTypeScalarSize(type); 1473 1474 // Random cases. 1475 fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), (float*)values[0], numValues*scalarSize); 1476 1477 // If precision is mediump, make sure values can be represented in fp16 exactly 1478 if (precision == glu::PRECISION_MEDIUMP) 1479 { 1480 for (int ndx = 0; ndx < numValues*scalarSize; ndx++) 1481 ((float*)values[0])[ndx] = tcu::Float16(((float*)values[0])[ndx]).asFloat(); 1482 } 1483 } 1484 1485 bool compare (const void* const* inputs, const void* const* outputs) 1486 { 1487 const glu::DataType type = m_spec.inputs[0].varType.getBasicType(); 1488 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision(); 1489 const bool hasZeroSign = supportsSignedZero(precision); 1490 const int scalarSize = glu::getDataTypeScalarSize(type); 1491 1492 if (precision == glu::PRECISION_HIGHP || precision == glu::PRECISION_MEDIUMP) 1493 { 1494 // Require exact result. 1495 for (int compNdx = 0; compNdx < scalarSize; compNdx++) 1496 { 1497 const float in0 = ((const float*)inputs[0])[compNdx]; 1498 const float out0 = ((const float*)outputs[0])[compNdx]; 1499 const float ref = deFloatCeil(in0); 1500 1501 const deUint32 ulpDiff = hasZeroSign ? getUlpDiff(out0, ref) : getUlpDiffIgnoreZeroSign(out0, ref); 1502 1503 if (ulpDiff > 0) 1504 { 1505 m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref) << ", got ULP diff " << tcu::toHex(ulpDiff); 1506 return false; 1507 } 1508 } 1509 } 1510 else 1511 { 1512 const int mantissaBits = getMinMantissaBits(precision); 1513 const deUint32 maxUlpDiff = getMaxUlpDiffFromBits(mantissaBits); // ULP diff for rounded integer value. 1514 const float eps = getEpsFromBits(1.0f, mantissaBits); // epsilon for rounding bounds 1515 1516 for (int compNdx = 0; compNdx < scalarSize; compNdx++) 1517 { 1518 const float in0 = ((const float*)inputs[0])[compNdx]; 1519 const float out0 = ((const float*)outputs[0])[compNdx]; 1520 const int minRes = int(deFloatCeil(in0-eps)); 1521 const int maxRes = int(deFloatCeil(in0+eps)); 1522 bool anyOk = false; 1523 1524 for (int roundedVal = minRes; roundedVal <= maxRes; roundedVal++) 1525 { 1526 const deUint32 ulpDiff = getUlpDiffIgnoreZeroSign(out0, float(roundedVal)); 1527 1528 if (ulpDiff <= maxUlpDiff) 1529 { 1530 anyOk = true; 1531 break; 1532 } 1533 } 1534 1535 if (!anyOk && de::inRange(0, minRes, maxRes)) 1536 { 1537 // Allow -0 as well. 1538 const int ulpDiff = de::abs((int)tcu::Float32(out0).bits() - (int)0x80000000u); 1539 anyOk = ((deUint32)ulpDiff <= maxUlpDiff); 1540 } 1541 1542 if (!anyOk) 1543 { 1544 m_failMsg << "Expected [" << compNdx << "] = [" << minRes << ", " << maxRes << "] with ULP threshold " << tcu::toHex(maxUlpDiff); 1545 return false; 1546 } 1547 } 1548 } 1549 1550 return true; 1551 } 1552}; 1553 1554class FractCase : public CommonFunctionCase 1555{ 1556public: 1557 FractCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType) 1558 : CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "fract", shaderType) 1559 { 1560 m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision))); 1561 m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision))); 1562 m_spec.source = "out0 = fract(in0);"; 1563 } 1564 1565 void getInputValues (int numValues, void* const* values) const 1566 { 1567 const Vec2 ranges[] = 1568 { 1569 Vec2(-2.0f, 2.0f), // lowp 1570 Vec2(-1e3f, 1e3f), // mediump 1571 Vec2(-1e7f, 1e7f) // highp 1572 }; 1573 1574 de::Random rnd (deStringHash(getName()) ^ 0xac23fu); 1575 const glu::DataType type = m_spec.inputs[0].varType.getBasicType(); 1576 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision(); 1577 const int scalarSize = glu::getDataTypeScalarSize(type); 1578 int numSpecialCases = 0; 1579 1580 // Special cases. 1581 if (precision != glu::PRECISION_LOWP) 1582 { 1583 DE_ASSERT(numValues >= 10); 1584 for (int ndx = 0; ndx < 10; ndx++) 1585 { 1586 const float v = de::clamp(float(ndx) - 5.5f, ranges[precision].x(), ranges[precision].y()); 1587 std::fill((float*)values[0], (float*)values[0] + scalarSize, v); 1588 numSpecialCases += 1; 1589 } 1590 } 1591 1592 // Random cases. 1593 fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), (float*)values[0] + numSpecialCases*scalarSize, (numValues-numSpecialCases)*scalarSize); 1594 1595 // If precision is mediump, make sure values can be represented in fp16 exactly 1596 if (precision == glu::PRECISION_MEDIUMP) 1597 { 1598 for (int ndx = 0; ndx < numValues*scalarSize; ndx++) 1599 ((float*)values[0])[ndx] = tcu::Float16(((float*)values[0])[ndx]).asFloat(); 1600 } 1601 } 1602 1603 bool compare (const void* const* inputs, const void* const* outputs) 1604 { 1605 const glu::DataType type = m_spec.inputs[0].varType.getBasicType(); 1606 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision(); 1607 const bool hasZeroSign = supportsSignedZero(precision); 1608 const int scalarSize = glu::getDataTypeScalarSize(type); 1609 1610 if (precision == glu::PRECISION_HIGHP || precision == glu::PRECISION_MEDIUMP) 1611 { 1612 // Require exact result. 1613 for (int compNdx = 0; compNdx < scalarSize; compNdx++) 1614 { 1615 const float in0 = ((const float*)inputs[0])[compNdx]; 1616 const float out0 = ((const float*)outputs[0])[compNdx]; 1617 const float ref = deFloatFrac(in0); 1618 1619 const deUint32 ulpDiff = hasZeroSign ? getUlpDiff(out0, ref) : getUlpDiffIgnoreZeroSign(out0, ref); 1620 1621 if (ulpDiff > 0) 1622 { 1623 m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref) << ", got ULP diff " << tcu::toHex(ulpDiff); 1624 return false; 1625 } 1626 } 1627 } 1628 else 1629 { 1630 const int mantissaBits = getMinMantissaBits(precision); 1631 const float eps = getEpsFromBits(1.0f, mantissaBits); // epsilon for rounding bounds 1632 1633 for (int compNdx = 0; compNdx < scalarSize; compNdx++) 1634 { 1635 const float in0 = ((const float*)inputs[0])[compNdx]; 1636 const float out0 = ((const float*)outputs[0])[compNdx]; 1637 1638 if (int(deFloatFloor(in0-eps)) == int(deFloatFloor(in0+eps))) 1639 { 1640 const float ref = deFloatFrac(in0); 1641 const int bitsLost = numBitsLostInOp(in0, ref); 1642 const deUint32 maxUlpDiff = getMaxUlpDiffFromBits(de::max(0, mantissaBits-bitsLost)); // ULP diff for rounded integer value. 1643 const deUint32 ulpDiff = getUlpDiffIgnoreZeroSign(out0, ref); 1644 1645 if (ulpDiff > maxUlpDiff) 1646 { 1647 m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref) << " with ULP threshold " << tcu::toHex(maxUlpDiff) << ", got diff " << tcu::toHex(ulpDiff); 1648 return false; 1649 } 1650 } 1651 else 1652 { 1653 if (out0 >= 1.0f) 1654 { 1655 m_failMsg << "Expected [" << compNdx << "] < 1.0"; 1656 return false; 1657 } 1658 } 1659 } 1660 } 1661 1662 return true; 1663 } 1664}; 1665 1666static inline void frexp (float in, float* significand, int* exponent) 1667{ 1668 const tcu::Float32 fpValue(in); 1669 1670 if (!fpValue.isZero()) 1671 { 1672 // Construct float that has exactly the mantissa, and exponent of -1. 1673 *significand = tcu::Float32::construct(fpValue.sign(), -1, fpValue.mantissa()).asFloat(); 1674 *exponent = fpValue.exponent()+1; 1675 } 1676 else 1677 { 1678 *significand = fpValue.sign() < 0 ? -0.0f : 0.0f; 1679 *exponent = 0; 1680 } 1681} 1682 1683static inline float ldexp (float significand, int exponent) 1684{ 1685 const tcu::Float32 mant(significand); 1686 1687 if (exponent == 0 && mant.isZero()) 1688 { 1689 return mant.sign() < 0 ? -0.0f : 0.0f; 1690 } 1691 else 1692 { 1693 return tcu::Float32::construct(mant.sign(), exponent+mant.exponent(), mant.mantissa()).asFloat(); 1694 } 1695} 1696 1697class FrexpCase : public CommonFunctionCase 1698{ 1699public: 1700 FrexpCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType) 1701 : CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "frexp", shaderType) 1702 { 1703 const int vecSize = glu::getDataTypeScalarSize(baseType); 1704 const glu::DataType intType = vecSize > 1 ? glu::getDataTypeIntVec(vecSize) : glu::TYPE_INT; 1705 1706 m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision))); 1707 m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, glu::PRECISION_HIGHP))); 1708 m_spec.outputs.push_back(Symbol("out1", glu::VarType(intType, glu::PRECISION_HIGHP))); 1709 m_spec.source = "out0 = frexp(in0, out1);"; 1710 } 1711 1712 void getInputValues (int numValues, void* const* values) const 1713 { 1714 const Vec2 ranges[] = 1715 { 1716 Vec2(-2.0f, 2.0f), // lowp 1717 Vec2(-1e3f, 1e3f), // mediump 1718 Vec2(-1e7f, 1e7f) // highp 1719 }; 1720 1721 de::Random rnd (deStringHash(getName()) ^ 0x2790au); 1722 const glu::DataType type = m_spec.inputs[0].varType.getBasicType(); 1723 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision(); 1724 const int scalarSize = glu::getDataTypeScalarSize(type); 1725 1726 // Special cases 1727 for (int compNdx = 0; compNdx < scalarSize; compNdx++) 1728 { 1729 ((float*)values[0])[scalarSize*0 + compNdx] = 0.0f; 1730 ((float*)values[0])[scalarSize*1 + compNdx] = -0.0f; 1731 ((float*)values[0])[scalarSize*2 + compNdx] = 0.5f; 1732 ((float*)values[0])[scalarSize*3 + compNdx] = -0.5f; 1733 ((float*)values[0])[scalarSize*4 + compNdx] = 1.0f; 1734 ((float*)values[0])[scalarSize*5 + compNdx] = -1.0f; 1735 ((float*)values[0])[scalarSize*6 + compNdx] = 2.0f; 1736 ((float*)values[0])[scalarSize*7 + compNdx] = -2.0f; 1737 } 1738 1739 fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), (float*)values[0] + 8*scalarSize, (numValues-8)*scalarSize); 1740 1741 // Make sure the values are representable in the target format 1742 for (int caseNdx = 0; caseNdx < numValues; ++caseNdx) 1743 { 1744 for (int scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++) 1745 { 1746 float* const valuePtr = &((float*)values[0])[caseNdx * scalarSize + scalarNdx]; 1747 1748 *valuePtr = makeFloatRepresentable(*valuePtr, precision); 1749 } 1750 } 1751 } 1752 1753 bool compare (const void* const* inputs, const void* const* outputs) 1754 { 1755 const glu::DataType type = m_spec.inputs[0].varType.getBasicType(); 1756 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision(); 1757 const int scalarSize = glu::getDataTypeScalarSize(type); 1758 const bool signedZero = false; 1759 1760 const int mantissaBits = getMinMantissaBits(precision); 1761 const deUint32 maxUlpDiff = getMaxUlpDiffFromBits(mantissaBits); 1762 1763 for (int compNdx = 0; compNdx < scalarSize; compNdx++) 1764 { 1765 const float in0 = ((const float*)inputs[0])[compNdx]; 1766 const float out0 = ((const float*)outputs[0])[compNdx]; 1767 const int out1 = ((const int*)outputs[1])[compNdx]; 1768 1769 float refOut0; 1770 int refOut1; 1771 1772 frexp(in0, &refOut0, &refOut1); 1773 1774 const deUint32 ulpDiff0 = signedZero ? getUlpDiff(out0, refOut0) : getUlpDiffIgnoreZeroSign(out0, refOut0); 1775 1776 if (ulpDiff0 > maxUlpDiff || out1 != refOut1) 1777 { 1778 m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(refOut0) << ", " << refOut1 << " with ULP threshold " 1779 << tcu::toHex(maxUlpDiff) << ", got ULP diff " << tcu::toHex(ulpDiff0); 1780 return false; 1781 } 1782 } 1783 1784 return true; 1785 } 1786}; 1787 1788class LdexpCase : public CommonFunctionCase 1789{ 1790public: 1791 LdexpCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType) 1792 : CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "ldexp", shaderType) 1793 { 1794 const int vecSize = glu::getDataTypeScalarSize(baseType); 1795 const glu::DataType intType = vecSize > 1 ? glu::getDataTypeIntVec(vecSize) : glu::TYPE_INT; 1796 1797 m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision))); 1798 m_spec.inputs.push_back(Symbol("in1", glu::VarType(intType, glu::PRECISION_HIGHP))); 1799 m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, glu::PRECISION_HIGHP))); 1800 m_spec.source = "out0 = ldexp(in0, in1);"; 1801 } 1802 1803 void getInputValues (int numValues, void* const* values) const 1804 { 1805 const Vec2 ranges[] = 1806 { 1807 Vec2(-2.0f, 2.0f), // lowp 1808 Vec2(-1e3f, 1e3f), // mediump 1809 Vec2(-1e7f, 1e7f) // highp 1810 }; 1811 1812 de::Random rnd (deStringHash(getName()) ^ 0x2790au); 1813 const glu::DataType type = m_spec.inputs[0].varType.getBasicType(); 1814 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision(); 1815 const int scalarSize = glu::getDataTypeScalarSize(type); 1816 int valueNdx = 0; 1817 1818 { 1819 const float easySpecialCases[] = { 0.0f, -0.0f, 0.5f, -0.5f, 1.0f, -1.0f, 2.0f, -2.0f }; 1820 1821 DE_ASSERT(valueNdx + DE_LENGTH_OF_ARRAY(easySpecialCases) <= numValues); 1822 for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(easySpecialCases); caseNdx++) 1823 { 1824 float in0; 1825 int in1; 1826 1827 frexp(easySpecialCases[caseNdx], &in0, &in1); 1828 1829 for (int compNdx = 0; compNdx < scalarSize; compNdx++) 1830 { 1831 ((float*)values[0])[valueNdx*scalarSize + compNdx] = in0; 1832 ((int*)values[1])[valueNdx*scalarSize + compNdx] = in1; 1833 } 1834 1835 valueNdx += 1; 1836 } 1837 } 1838 1839 { 1840 // \note lowp and mediump can not necessarily fit the values in hard cases, so we'll use only easy ones. 1841 const int numEasyRandomCases = precision == glu::PRECISION_HIGHP ? 50 : (numValues-valueNdx); 1842 1843 DE_ASSERT(valueNdx + numEasyRandomCases <= numValues); 1844 for (int caseNdx = 0; caseNdx < numEasyRandomCases; caseNdx++) 1845 { 1846 for (int compNdx = 0; compNdx < scalarSize; compNdx++) 1847 { 1848 const float in = rnd.getFloat(ranges[precision].x(), ranges[precision].y()); 1849 float in0; 1850 int in1; 1851 1852 frexp(in, &in0, &in1); 1853 1854 ((float*)values[0])[valueNdx*scalarSize + compNdx] = in0; 1855 ((int*)values[1])[valueNdx*scalarSize + compNdx] = in1; 1856 } 1857 1858 valueNdx += 1; 1859 } 1860 } 1861 1862 { 1863 const int numHardRandomCases = numValues-valueNdx; 1864 DE_ASSERT(numHardRandomCases >= 0 && valueNdx + numHardRandomCases <= numValues); 1865 1866 for (int caseNdx = 0; caseNdx < numHardRandomCases; caseNdx++) 1867 { 1868 for (int compNdx = 0; compNdx < scalarSize; compNdx++) 1869 { 1870 const int fpExp = rnd.getInt(-126, 127); 1871 const int sign = rnd.getBool() ? -1 : +1; 1872 const deUint32 mantissa = (1u<<23) | (rnd.getUint32() & ((1u<<23)-1)); 1873 const int in1 = rnd.getInt(de::max(-126, -126-fpExp), de::min(127, 127-fpExp)); 1874 const float in0 = tcu::Float32::construct(sign, fpExp, mantissa).asFloat(); 1875 1876 DE_ASSERT(de::inRange(in1, -126, 127)); // See Khronos bug 11180 1877 DE_ASSERT(de::inRange(in1+fpExp, -126, 127)); 1878 1879 const float out = ldexp(in0, in1); 1880 1881 DE_ASSERT(!tcu::Float32(out).isInf() && !tcu::Float32(out).isDenorm()); 1882 DE_UNREF(out); 1883 1884 ((float*)values[0])[valueNdx*scalarSize + compNdx] = in0; 1885 ((int*)values[1])[valueNdx*scalarSize + compNdx] = in1; 1886 } 1887 1888 valueNdx += 1; 1889 } 1890 } 1891 } 1892 1893 bool compare (const void* const* inputs, const void* const* outputs) 1894 { 1895 const glu::DataType type = m_spec.inputs[0].varType.getBasicType(); 1896 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision(); 1897 const int scalarSize = glu::getDataTypeScalarSize(type); 1898 1899 const int mantissaBits = getMinMantissaBits(precision); 1900 const deUint32 maxUlpDiff = getMaxUlpDiffFromBits(mantissaBits); 1901 1902 for (int compNdx = 0; compNdx < scalarSize; compNdx++) 1903 { 1904 const float in0 = ((const float*)inputs[0])[compNdx]; 1905 const int in1 = ((const int*)inputs[1])[compNdx]; 1906 const float out0 = ((const float*)outputs[0])[compNdx]; 1907 const float refOut0 = ldexp(in0, in1); 1908 const deUint32 ulpDiff = getUlpDiffIgnoreZeroSign(out0, refOut0); 1909 1910 const int inExp = tcu::Float32(in0).exponent(); 1911 1912 if (ulpDiff > maxUlpDiff) 1913 { 1914 m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(refOut0) << ", (exp = " << inExp << ") with ULP threshold " 1915 << tcu::toHex(maxUlpDiff) << ", got ULP diff " << tcu::toHex(ulpDiff); 1916 return false; 1917 } 1918 } 1919 1920 return true; 1921 } 1922}; 1923 1924class FmaCase : public CommonFunctionCase 1925{ 1926public: 1927 FmaCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType) 1928 : CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "fma", shaderType) 1929 { 1930 m_spec.inputs.push_back(Symbol("a", glu::VarType(baseType, precision))); 1931 m_spec.inputs.push_back(Symbol("b", glu::VarType(baseType, precision))); 1932 m_spec.inputs.push_back(Symbol("c", glu::VarType(baseType, precision))); 1933 m_spec.outputs.push_back(Symbol("res", glu::VarType(baseType, precision))); 1934 m_spec.source = "res = fma(a, b, c);"; 1935 1936 if (!glu::contextSupports(context.getRenderContext().getType(), glu::ApiType::es(3, 2)) 1937 && !glu::contextSupports(context.getRenderContext().getType(), glu::ApiType::core(4, 5))) 1938 m_spec.globalDeclarations = "#extension GL_EXT_gpu_shader5 : require\n"; 1939 } 1940 1941 void init (void) 1942 { 1943 if (!glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)) 1944 && !m_context.getContextInfo().isExtensionSupported("GL_EXT_gpu_shader5") 1945 && !glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5))) 1946 throw tcu::NotSupportedError("OpenGL ES 3.2, GL_EXT_gpu_shader5 not supported and OpenGL 4.5"); 1947 1948 CommonFunctionCase::init(); 1949 } 1950 1951 void getInputValues (int numValues, void* const* values) const 1952 { 1953 const Vec2 ranges[] = 1954 { 1955 Vec2(-2.0f, 2.0f), // lowp 1956 Vec2(-127.f, 127.f), // mediump 1957 Vec2(-1e7f, 1e7f) // highp 1958 }; 1959 1960 de::Random rnd (deStringHash(getName()) ^ 0xac23fu); 1961 const glu::DataType type = m_spec.inputs[0].varType.getBasicType(); 1962 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision(); 1963 const int scalarSize = glu::getDataTypeScalarSize(type); 1964 const float specialCases[][3] = 1965 { 1966 // a b c 1967 { 0.0f, 0.0f, 0.0f }, 1968 { 0.0f, 1.0f, 0.0f }, 1969 { 0.0f, 0.0f, -1.0f }, 1970 { 1.0f, 1.0f, 0.0f }, 1971 { 1.0f, 1.0f, 1.0f }, 1972 { -1.0f, 1.0f, 0.0f }, 1973 { 1.0f, -1.0f, 0.0f }, 1974 { -1.0f, -1.0f, 0.0f }, 1975 { -0.0f, 1.0f, 0.0f }, 1976 { 1.0f, -0.0f, 0.0f } 1977 }; 1978 const int numSpecialCases = DE_LENGTH_OF_ARRAY(specialCases); 1979 1980 // Special cases 1981 for (int caseNdx = 0; caseNdx < numSpecialCases; caseNdx++) 1982 { 1983 for (int inputNdx = 0; inputNdx < 3; inputNdx++) 1984 { 1985 for (int scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++) 1986 ((float*)values[inputNdx])[caseNdx*scalarSize + scalarNdx] = specialCases[caseNdx][inputNdx]; 1987 } 1988 } 1989 1990 // Random cases. 1991 { 1992 const int numScalars = (numValues-numSpecialCases)*scalarSize; 1993 const int offs = scalarSize*numSpecialCases; 1994 1995 for (int inputNdx = 0; inputNdx < 3; inputNdx++) 1996 fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), (float*)values[inputNdx] + offs, numScalars); 1997 } 1998 1999 // Make sure the values are representable in the target format 2000 for (int inputNdx = 0; inputNdx < 3; inputNdx++) 2001 { 2002 for (int caseNdx = 0; caseNdx < numValues; ++caseNdx) 2003 { 2004 for (int scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++) 2005 { 2006 float* const valuePtr = &((float*)values[inputNdx])[caseNdx * scalarSize + scalarNdx]; 2007 2008 *valuePtr = makeFloatRepresentable(*valuePtr, precision); 2009 } 2010 } 2011 } 2012 } 2013 2014 static tcu::Interval fma (glu::Precision precision, float a, float b, float c) 2015 { 2016 const tcu::FloatFormat formats[] = 2017 { 2018 // minExp maxExp mantissa exact, subnormals infinities NaN 2019 tcu::FloatFormat(0, 0, 7, false, tcu::YES, tcu::MAYBE, tcu::MAYBE), 2020 tcu::FloatFormat(-13, 13, 9, false, tcu::MAYBE, tcu::MAYBE, tcu::MAYBE), 2021 tcu::FloatFormat(-126, 127, 23, true, tcu::MAYBE, tcu::YES, tcu::MAYBE) 2022 }; 2023 const tcu::FloatFormat& format = de::getSizedArrayElement<glu::PRECISION_LAST>(formats, precision); 2024 const tcu::Interval ia = format.convert(a); 2025 const tcu::Interval ib = format.convert(b); 2026 const tcu::Interval ic = format.convert(c); 2027 tcu::Interval prod0; 2028 tcu::Interval prod1; 2029 tcu::Interval prod2; 2030 tcu::Interval prod3; 2031 tcu::Interval prod; 2032 tcu::Interval res; 2033 2034 TCU_SET_INTERVAL(prod0, tmp, tmp = ia.lo() * ib.lo()); 2035 TCU_SET_INTERVAL(prod1, tmp, tmp = ia.lo() * ib.hi()); 2036 TCU_SET_INTERVAL(prod2, tmp, tmp = ia.hi() * ib.lo()); 2037 TCU_SET_INTERVAL(prod3, tmp, tmp = ia.hi() * ib.hi()); 2038 2039 prod = format.convert(format.roundOut(prod0 | prod1 | prod2 | prod3, ia.isFinite(format.getMaxValue()) && ib.isFinite(format.getMaxValue()))); 2040 2041 TCU_SET_INTERVAL_BOUNDS(res, tmp, 2042 tmp = prod.lo() + ic.lo(), 2043 tmp = prod.hi() + ic.hi()); 2044 2045 return format.convert(format.roundOut(res, prod.isFinite(format.getMaxValue()) && ic.isFinite(format.getMaxValue()))); 2046 } 2047 2048 bool compare (const void* const* inputs, const void* const* outputs) 2049 { 2050 const glu::DataType type = m_spec.inputs[0].varType.getBasicType(); 2051 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision(); 2052 const int scalarSize = glu::getDataTypeScalarSize(type); 2053 2054 for (int compNdx = 0; compNdx < scalarSize; compNdx++) 2055 { 2056 const float a = ((const float*)inputs[0])[compNdx]; 2057 const float b = ((const float*)inputs[1])[compNdx]; 2058 const float c = ((const float*)inputs[2])[compNdx]; 2059 const float res = ((const float*)outputs[0])[compNdx]; 2060 const tcu::Interval ref = fma(precision, a, b, c); 2061 2062 if (!ref.contains(res)) 2063 { 2064 m_failMsg << "Expected [" << compNdx << "] = " << ref; 2065 return false; 2066 } 2067 } 2068 2069 return true; 2070 } 2071}; 2072 2073ShaderCommonFunctionTests::ShaderCommonFunctionTests (Context& context) 2074 : TestCaseGroup(context, "common", "Common function tests") 2075{ 2076} 2077 2078ShaderCommonFunctionTests::~ShaderCommonFunctionTests (void) 2079{ 2080} 2081 2082template<class TestClass> 2083static void addFunctionCases (TestCaseGroup* parent, const char* functionName, bool floatTypes, bool intTypes, bool uintTypes, deUint32 shaderBits) 2084{ 2085 tcu::TestCaseGroup* group = new tcu::TestCaseGroup(parent->getTestContext(), functionName, functionName); 2086 parent->addChild(group); 2087 2088 const glu::DataType scalarTypes[] = 2089 { 2090 glu::TYPE_FLOAT, 2091 glu::TYPE_INT, 2092 glu::TYPE_UINT 2093 }; 2094 2095 for (int scalarTypeNdx = 0; scalarTypeNdx < DE_LENGTH_OF_ARRAY(scalarTypes); scalarTypeNdx++) 2096 { 2097 const glu::DataType scalarType = scalarTypes[scalarTypeNdx]; 2098 2099 if ((!floatTypes && scalarType == glu::TYPE_FLOAT) || 2100 (!intTypes && scalarType == glu::TYPE_INT) || 2101 (!uintTypes && scalarType == glu::TYPE_UINT)) 2102 continue; 2103 2104 for (int vecSize = 1; vecSize <= 4; vecSize++) 2105 { 2106 for (int prec = glu::PRECISION_LOWP; prec <= glu::PRECISION_HIGHP; prec++) 2107 { 2108 for (int shaderTypeNdx = 0; shaderTypeNdx < glu::SHADERTYPE_LAST; shaderTypeNdx++) 2109 { 2110 if (shaderBits & (1<<shaderTypeNdx)) 2111 group->addChild(new TestClass(parent->getContext(), glu::DataType(scalarType + vecSize - 1), glu::Precision(prec), glu::ShaderType(shaderTypeNdx))); 2112 } 2113 } 2114 } 2115 } 2116} 2117 2118void ShaderCommonFunctionTests::init (void) 2119{ 2120 enum 2121 { 2122 VS = (1<<glu::SHADERTYPE_VERTEX), 2123 TC = (1<<glu::SHADERTYPE_TESSELLATION_CONTROL), 2124 TE = (1<<glu::SHADERTYPE_TESSELLATION_EVALUATION), 2125 GS = (1<<glu::SHADERTYPE_GEOMETRY), 2126 FS = (1<<glu::SHADERTYPE_FRAGMENT), 2127 CS = (1<<glu::SHADERTYPE_COMPUTE), 2128 2129 ALL_SHADERS = VS|TC|TE|GS|FS|CS, 2130 NEW_SHADERS = TC|TE|GS|CS, 2131 }; 2132 2133 // Float? Int? Uint? Shaders 2134 addFunctionCases<AbsCase> (this, "abs", true, true, false, NEW_SHADERS); 2135 addFunctionCases<SignCase> (this, "sign", true, true, false, NEW_SHADERS); 2136 addFunctionCases<FloorCase> (this, "floor", true, false, false, NEW_SHADERS); 2137 addFunctionCases<TruncCase> (this, "trunc", true, false, false, NEW_SHADERS); 2138 addFunctionCases<RoundCase> (this, "round", true, false, false, NEW_SHADERS); 2139 addFunctionCases<RoundEvenCase> (this, "roundeven", true, false, false, NEW_SHADERS); 2140 addFunctionCases<CeilCase> (this, "ceil", true, false, false, NEW_SHADERS); 2141 addFunctionCases<FractCase> (this, "fract", true, false, false, NEW_SHADERS); 2142 // mod 2143 addFunctionCases<ModfCase> (this, "modf", true, false, false, NEW_SHADERS); 2144 // min 2145 // max 2146 // clamp 2147 // mix 2148 // step 2149 // smoothstep 2150 addFunctionCases<IsnanCase> (this, "isnan", true, false, false, NEW_SHADERS); 2151 addFunctionCases<IsinfCase> (this, "isinf", true, false, false, NEW_SHADERS); 2152 addFunctionCases<FloatBitsToIntCase> (this, "floatbitstoint", true, false, false, NEW_SHADERS); 2153 addFunctionCases<FloatBitsToUintCase> (this, "floatbitstouint", true, false, false, NEW_SHADERS); 2154 2155 addFunctionCases<FrexpCase> (this, "frexp", true, false, false, ALL_SHADERS); 2156 addFunctionCases<LdexpCase> (this, "ldexp", true, false, false, ALL_SHADERS); 2157 addFunctionCases<FmaCase> (this, "fma", true, false, false, ALL_SHADERS); 2158 2159 // (u)intBitsToFloat() 2160 { 2161 const deUint32 shaderBits = NEW_SHADERS; 2162 tcu::TestCaseGroup* intGroup = new tcu::TestCaseGroup(m_testCtx, "intbitstofloat", "intBitsToFloat() Tests"); 2163 tcu::TestCaseGroup* uintGroup = new tcu::TestCaseGroup(m_testCtx, "uintbitstofloat", "uintBitsToFloat() Tests"); 2164 2165 addChild(intGroup); 2166 addChild(uintGroup); 2167 2168 for (int vecSize = 1; vecSize < 4; vecSize++) 2169 { 2170 const glu::DataType intType = vecSize > 1 ? glu::getDataTypeIntVec(vecSize) : glu::TYPE_INT; 2171 const glu::DataType uintType = vecSize > 1 ? glu::getDataTypeUintVec(vecSize) : glu::TYPE_UINT; 2172 2173 for (int shaderType = 0; shaderType < glu::SHADERTYPE_LAST; shaderType++) 2174 { 2175 if (shaderBits & (1<<shaderType)) 2176 { 2177 intGroup->addChild(new BitsToFloatCase(m_context, intType, glu::ShaderType(shaderType))); 2178 uintGroup->addChild(new BitsToFloatCase(m_context, uintType, glu::ShaderType(shaderType))); 2179 } 2180 } 2181 } 2182 } 2183} 2184 2185} // Functional 2186} // gles31 2187} // deqp 2188