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