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