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