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