Fix missing dependency on sparse binds
[platform/upstream/VK-GL-CTS.git] / modules / gles3 / functional / es3fShaderCommonFunctionTests.cpp
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES 3.0 Module
3  * -------------------------------------------------
4  *
5  * Copyright 2014 The Android Open Source Project
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Common built-in function tests.
22  *//*--------------------------------------------------------------------*/
23
24 #include "es3fShaderCommonFunctionTests.hpp"
25 #include "glsShaderExecUtil.hpp"
26 #include "tcuTestLog.hpp"
27 #include "tcuFormatUtil.hpp"
28 #include "tcuVectorUtil.hpp"
29 #include "tcuFloat.hpp"
30 #include "deRandom.hpp"
31 #include "deMath.h"
32 #include "deString.h"
33
34 namespace deqp
35 {
36 namespace gles3
37 {
38 namespace Functional
39 {
40
41 using std::vector;
42 using std::string;
43 using tcu::TestLog;
44 using namespace gls::ShaderExecUtil;
45
46 using tcu::Vec2;
47 using tcu::Vec3;
48 using tcu::Vec4;
49 using tcu::IVec2;
50 using tcu::IVec3;
51 using tcu::IVec4;
52
53 // Utilities
54
55 template<typename T, int Size>
56 struct VecArrayAccess
57 {
58 public:
59                                                                         VecArrayAccess  (const void* ptr) : m_array((tcu::Vector<T, Size>*)ptr) {}
60                                                                         ~VecArrayAccess (void) {}
61
62         const tcu::Vector<T, Size>&             operator[]              (size_t offset) const   { return m_array[offset];       }
63         tcu::Vector<T, Size>&                   operator[]              (size_t offset)                 { return m_array[offset];       }
64
65 private:
66         tcu::Vector<T, Size>*                   m_array;
67 };
68
69 template<typename T, int Size>
70 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)
71 {
72         VecArrayAccess<T, Size> access(dst);
73         for (int ndx = 0; ndx < numValues; ndx++)
74                 access[offset + ndx] = tcu::randomVector<T, Size>(rnd, minValue, maxValue);
75 }
76
77 template<typename T>
78 static void fillRandomScalars (de::Random& rnd, T minValue, T maxValue, void* dst, int numValues, int offset = 0)
79 {
80         T* typedPtr = (T*)dst;
81         for (int ndx = 0; ndx < numValues; ndx++)
82                 typedPtr[offset + ndx] = de::randomScalar<T>(rnd, minValue, maxValue);
83 }
84
85 inline int numBitsLostInOp (float input, float output)
86 {
87         const int       inExp           = tcu::Float32(input).exponent();
88         const int       outExp          = tcu::Float32(output).exponent();
89
90         return de::max(0, inExp-outExp); // Lost due to mantissa shift.
91 }
92
93 inline deUint32 getUlpDiff (float a, float b)
94 {
95         const deUint32  aBits   = tcu::Float32(a).bits();
96         const deUint32  bBits   = tcu::Float32(b).bits();
97         return aBits > bBits ? aBits - bBits : bBits - aBits;
98 }
99
100 inline deUint32 getUlpDiffIgnoreZeroSign (float a, float b)
101 {
102         if (tcu::Float32(a).isZero())
103                 return getUlpDiff(tcu::Float32::construct(tcu::Float32(b).sign(), 0, 0).asFloat(), b);
104         else if (tcu::Float32(b).isZero())
105                 return getUlpDiff(a, tcu::Float32::construct(tcu::Float32(a).sign(), 0, 0).asFloat());
106         else
107                 return getUlpDiff(a, b);
108 }
109
110 inline bool supportsSignedZero (glu::Precision precision)
111 {
112         // \note GLSL ES 3.0 doesn't really require support for -0, but we require it for highp
113         //               as it is very widely supported.
114         return precision == glu::PRECISION_HIGHP;
115 }
116
117 inline float getEpsFromMaxUlpDiff (float value, deUint32 ulpDiff)
118 {
119         const int exp = tcu::Float32(value).exponent();
120         return tcu::Float32::construct(+1, exp, (1u<<23) | ulpDiff).asFloat() - tcu::Float32::construct(+1, exp, 1u<<23).asFloat();
121 }
122
123 inline deUint32 getMaxUlpDiffFromBits (int numAccurateBits)
124 {
125         const int               numGarbageBits  = 23-numAccurateBits;
126         const deUint32  mask                    = (1u<<numGarbageBits)-1u;
127
128         return mask;
129 }
130
131 inline float getEpsFromBits (float value, int numAccurateBits)
132 {
133         return getEpsFromMaxUlpDiff(value, getMaxUlpDiffFromBits(numAccurateBits));
134 }
135
136 static int getMinMantissaBits (glu::Precision precision)
137 {
138         const int bits[] =
139         {
140                 7,              // lowp
141                 10,             // mediump
142                 23              // highp
143         };
144         DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(bits) == glu::PRECISION_LAST);
145         DE_ASSERT(de::inBounds<int>(precision, 0, DE_LENGTH_OF_ARRAY(bits)));
146         return bits[precision];
147 }
148
149 // CommonFunctionCase
150
151 class CommonFunctionCase : public TestCase
152 {
153 public:
154                                                         CommonFunctionCase              (Context& context, const char* name, const char* description, glu::ShaderType shaderType);
155                                                         ~CommonFunctionCase             (void);
156
157         void                                    init                                    (void);
158         void                                    deinit                                  (void);
159         IterateResult                   iterate                                 (void);
160
161 protected:
162                                                         CommonFunctionCase              (const CommonFunctionCase& other);
163         CommonFunctionCase&             operator=                               (const CommonFunctionCase& other);
164
165         virtual void                    getInputValues                  (int numValues, void* const* values) const = 0;
166         virtual bool                    compare                                 (const void* const* inputs, const void* const* outputs) = 0;
167
168         glu::ShaderType                 m_shaderType;
169         ShaderSpec                              m_spec;
170         int                                             m_numValues;
171
172         std::ostringstream              m_failMsg;                              //!< Comparison failure help message.
173
174 private:
175         ShaderExecutor*                 m_executor;
176 };
177
178 CommonFunctionCase::CommonFunctionCase (Context& context, const char* name, const char* description, glu::ShaderType shaderType)
179         : TestCase              (context, name, description)
180         , m_shaderType  (shaderType)
181         , m_numValues   (100)
182         , m_executor    (DE_NULL)
183 {
184         m_spec.version = glu::GLSL_VERSION_300_ES;
185 }
186
187 CommonFunctionCase::~CommonFunctionCase (void)
188 {
189         CommonFunctionCase::deinit();
190 }
191
192 void CommonFunctionCase::init (void)
193 {
194         DE_ASSERT(!m_executor);
195
196         m_executor = createExecutor(m_context.getRenderContext(), m_shaderType, m_spec);
197         m_testCtx.getLog() << m_executor;
198
199         if (!m_executor->isOk())
200                 throw tcu::TestError("Compile failed");
201 }
202
203 void CommonFunctionCase::deinit (void)
204 {
205         delete m_executor;
206         m_executor = DE_NULL;
207 }
208
209 static vector<int> getScalarSizes (const vector<Symbol>& symbols)
210 {
211         vector<int> sizes(symbols.size());
212         for (int ndx = 0; ndx < (int)symbols.size(); ++ndx)
213                 sizes[ndx] = symbols[ndx].varType.getScalarSize();
214         return sizes;
215 }
216
217 static int computeTotalScalarSize (const vector<Symbol>& symbols)
218 {
219         int totalSize = 0;
220         for (vector<Symbol>::const_iterator sym = symbols.begin(); sym != symbols.end(); ++sym)
221                 totalSize += sym->varType.getScalarSize();
222         return totalSize;
223 }
224
225 static vector<void*> getInputOutputPointers (const vector<Symbol>& symbols, vector<deUint32>& data, const int numValues)
226 {
227         vector<void*>   pointers                (symbols.size());
228         int                             curScalarOffset = 0;
229
230         for (int varNdx = 0; varNdx < (int)symbols.size(); ++varNdx)
231         {
232                 const Symbol&   var                             = symbols[varNdx];
233                 const int               scalarSize              = var.varType.getScalarSize();
234
235                 // Uses planar layout as input/output specs do not support strides.
236                 pointers[varNdx] = &data[curScalarOffset];
237                 curScalarOffset += scalarSize*numValues;
238         }
239
240         DE_ASSERT(curScalarOffset == (int)data.size());
241
242         return pointers;
243 }
244
245 // \todo [2013-08-08 pyry] Make generic utility and move to glu?
246
247 struct HexFloat
248 {
249         const float value;
250         HexFloat (const float value_) : value(value_) {}
251 };
252
253 std::ostream& operator<< (std::ostream& str, const HexFloat& v)
254 {
255         return str << v.value << " / " << tcu::toHex(tcu::Float32(v.value).bits());
256 }
257
258 struct HexBool
259 {
260         const deUint32 value;
261         HexBool (const deUint32 value_) : value(value_) {}
262 };
263
264 std::ostream& operator<< (std::ostream& str, const HexBool& v)
265 {
266         return str << (v.value ? "true" : "false") << " / " << tcu::toHex(v.value);
267 }
268
269 struct VarValue
270 {
271         const glu::VarType&     type;
272         const void*                     value;
273
274         VarValue (const glu::VarType& type_, const void* value_) : type(type_), value(value_) {}
275 };
276
277 std::ostream& operator<< (std::ostream& str, const VarValue& varValue)
278 {
279         DE_ASSERT(varValue.type.isBasicType());
280
281         const glu::DataType             basicType               = varValue.type.getBasicType();
282         const glu::DataType             scalarType              = glu::getDataTypeScalarType(basicType);
283         const int                               numComponents   = glu::getDataTypeScalarSize(basicType);
284
285         if (numComponents > 1)
286                 str << glu::getDataTypeName(basicType) << "(";
287
288         for (int compNdx = 0; compNdx < numComponents; compNdx++)
289         {
290                 if (compNdx != 0)
291                         str << ", ";
292
293                 switch (scalarType)
294                 {
295                         case glu::TYPE_FLOAT:   str << HexFloat(((const float*)varValue.value)[compNdx]);                       break;
296                         case glu::TYPE_INT:             str << ((const deInt32*)varValue.value)[compNdx];                                       break;
297                         case glu::TYPE_UINT:    str << tcu::toHex(((const deUint32*)varValue.value)[compNdx]);          break;
298                         case glu::TYPE_BOOL:    str << HexBool(((const deUint32*)varValue.value)[compNdx]);                     break;
299
300                         default:
301                                 DE_ASSERT(false);
302                 }
303         }
304
305         if (numComponents > 1)
306                 str << ")";
307
308         return str;
309 }
310
311 CommonFunctionCase::IterateResult CommonFunctionCase::iterate (void)
312 {
313         const int                               numInputScalars                 = computeTotalScalarSize(m_spec.inputs);
314         const int                               numOutputScalars                = computeTotalScalarSize(m_spec.outputs);
315         vector<deUint32>                inputData                               (numInputScalars * m_numValues);
316         vector<deUint32>                outputData                              (numOutputScalars * m_numValues);
317         const vector<void*>             inputPointers                   = getInputOutputPointers(m_spec.inputs, inputData, m_numValues);
318         const vector<void*>             outputPointers                  = getInputOutputPointers(m_spec.outputs, outputData, m_numValues);
319
320         // Initialize input data.
321         getInputValues(m_numValues, &inputPointers[0]);
322
323         // Execute shader.
324         m_executor->useProgram();
325         m_executor->execute(m_numValues, &inputPointers[0], &outputPointers[0]);
326
327         // Compare results.
328         {
329                 const vector<int>               inScalarSizes           = getScalarSizes(m_spec.inputs);
330                 const vector<int>               outScalarSizes          = getScalarSizes(m_spec.outputs);
331                 vector<void*>                   curInputPtr                     (inputPointers.size());
332                 vector<void*>                   curOutputPtr            (outputPointers.size());
333                 int                                             numFailed                       = 0;
334
335                 for (int valNdx = 0; valNdx < m_numValues; valNdx++)
336                 {
337                         // Set up pointers for comparison.
338                         for (int inNdx = 0; inNdx < (int)curInputPtr.size(); ++inNdx)
339                                 curInputPtr[inNdx] = (deUint32*)inputPointers[inNdx] + inScalarSizes[inNdx]*valNdx;
340
341                         for (int outNdx = 0; outNdx < (int)curOutputPtr.size(); ++outNdx)
342                                 curOutputPtr[outNdx] = (deUint32*)outputPointers[outNdx] + outScalarSizes[outNdx]*valNdx;
343
344                         if (!compare(&curInputPtr[0], &curOutputPtr[0]))
345                         {
346                                 // \todo [2013-08-08 pyry] We probably want to log reference value as well?
347
348                                 m_testCtx.getLog() << TestLog::Message << "ERROR: comparison failed for value " << valNdx << ":\n  " << m_failMsg.str() << TestLog::EndMessage;
349
350                                 m_testCtx.getLog() << TestLog::Message << "  inputs:" << TestLog::EndMessage;
351                                 for (int inNdx = 0; inNdx < (int)curInputPtr.size(); inNdx++)
352                                         m_testCtx.getLog() << TestLog::Message << "    " << m_spec.inputs[inNdx].name << " = "
353                                                                                                                    << VarValue(m_spec.inputs[inNdx].varType, curInputPtr[inNdx])
354                                                                            << TestLog::EndMessage;
355
356                                 m_testCtx.getLog() << TestLog::Message << "  outputs:" << TestLog::EndMessage;
357                                 for (int outNdx = 0; outNdx < (int)curOutputPtr.size(); outNdx++)
358                                         m_testCtx.getLog() << TestLog::Message << "    " << m_spec.outputs[outNdx].name << " = "
359                                                                                                                    << VarValue(m_spec.outputs[outNdx].varType, curOutputPtr[outNdx])
360                                                                            << TestLog::EndMessage;
361
362                                 m_failMsg.str("");
363                                 m_failMsg.clear();
364                                 numFailed += 1;
365                         }
366                 }
367
368                 m_testCtx.getLog() << TestLog::Message << (m_numValues - numFailed) << " / " << m_numValues << " values passed" << TestLog::EndMessage;
369
370                 m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS    : QP_TEST_RESULT_FAIL,
371                                                                 numFailed == 0 ? "Pass"                                 : "Result comparison failed");
372         }
373
374         return STOP;
375 }
376
377 static std::string getCommonFuncCaseName (glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
378 {
379         return string(glu::getDataTypeName(baseType)) + getPrecisionPostfix(precision) + getShaderTypePostfix(shaderType);
380 }
381
382 class AbsCase : public CommonFunctionCase
383 {
384 public:
385         AbsCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
386                 : CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "abs", shaderType)
387         {
388                 m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
389                 m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision)));
390                 m_spec.source = "out0 = abs(in0);";
391         }
392
393         void getInputValues (int numValues, void* const* values) const
394         {
395                 const Vec2 floatRanges[] =
396                 {
397                         Vec2(-2.0f,             2.0f),  // lowp
398                         Vec2(-1e3f,             1e3f),  // mediump
399                         Vec2(-1e7f,             1e7f)   // highp
400                 };
401                 const IVec2 intRanges[] =
402                 {
403                         IVec2(-(1<<7)+1,        (1<<7)-1),
404                         IVec2(-(1<<15)+1,       (1<<15)-1),
405                         IVec2(0x80000001,       0x7fffffff)
406                 };
407
408                 de::Random                              rnd                     (deStringHash(getName()) ^ 0x235facu);
409                 const glu::DataType             type            = m_spec.inputs[0].varType.getBasicType();
410                 const glu::Precision    precision       = m_spec.inputs[0].varType.getPrecision();
411                 const int                               scalarSize      = glu::getDataTypeScalarSize(type);
412
413                 if (glu::isDataTypeFloatOrVec(type))
414                         fillRandomScalars(rnd, floatRanges[precision].x(), floatRanges[precision].y(), values[0], numValues*scalarSize);
415                 else
416                         fillRandomScalars(rnd, intRanges[precision].x(), intRanges[precision].y(), values[0], numValues*scalarSize);
417         }
418
419         bool compare (const void* const* inputs, const void* const* outputs)
420         {
421                 const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
422                 const glu::Precision    precision               = m_spec.inputs[0].varType.getPrecision();
423                 const int                               scalarSize              = glu::getDataTypeScalarSize(type);
424
425                 if (glu::isDataTypeFloatOrVec(type))
426                 {
427                         const int               mantissaBits    = getMinMantissaBits(precision);
428                         const deUint32  maxUlpDiff              = (1u<<(23-mantissaBits))-1u;
429
430                         for (int compNdx = 0; compNdx < scalarSize; compNdx++)
431                         {
432                                 const float             in0                     = ((const float*)inputs[0])[compNdx];
433                                 const float             out0            = ((const float*)outputs[0])[compNdx];
434                                 const float             ref0            = de::abs(in0);
435                                 const deUint32  ulpDiff0        = getUlpDiff(out0, ref0);
436
437                                 if (ulpDiff0 > maxUlpDiff)
438                                 {
439                                         m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref0) << " with ULP threshold " << maxUlpDiff << ", got ULP diff " << ulpDiff0;
440                                         return false;
441                                 }
442                         }
443                 }
444                 else
445                 {
446                         for (int compNdx = 0; compNdx < scalarSize; compNdx++)
447                         {
448                                 const int       in0             = ((const int*)inputs[0])[compNdx];
449                                 const int       out0    = ((const int*)outputs[0])[compNdx];
450                                 const int       ref0    = de::abs(in0);
451
452                                 if (out0 != ref0)
453                                 {
454                                         m_failMsg << "Expected [" << compNdx << "] = " << ref0;
455                                         return false;
456                                 }
457                         }
458                 }
459
460                 return true;
461         }
462 };
463
464 class SignCase : public CommonFunctionCase
465 {
466 public:
467         SignCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
468                 : CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "sign", shaderType)
469         {
470                 m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
471                 m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision)));
472                 m_spec.source = "out0 = sign(in0);";
473         }
474
475         void getInputValues (int numValues, void* const* values) const
476         {
477                 const Vec2 floatRanges[] =
478                 {
479                         Vec2(-2.0f,             2.0f),  // lowp
480                         Vec2(-1e4f,             1e4f),  // mediump      - note: may end up as inf
481                         Vec2(-1e8f,             1e8f)   // highp        - note: may end up as inf
482                 };
483                 const IVec2 intRanges[] =
484                 {
485                         IVec2(-(1<<7),          (1<<7)-1),
486                         IVec2(-(1<<15),         (1<<15)-1),
487                         IVec2(0x80000000,       0x7fffffff)
488                 };
489
490                 de::Random                              rnd                     (deStringHash(getName()) ^ 0x324u);
491                 const glu::DataType             type            = m_spec.inputs[0].varType.getBasicType();
492                 const glu::Precision    precision       = m_spec.inputs[0].varType.getPrecision();
493                 const int                               scalarSize      = glu::getDataTypeScalarSize(type);
494
495                 if (glu::isDataTypeFloatOrVec(type))
496                 {
497                         // Special cases.
498                         std::fill((float*)values[0],                            (float*)values[0] + scalarSize,         +1.0f);
499                         std::fill((float*)values[0] + scalarSize*1,     (float*)values[0] + scalarSize*2,       -1.0f);
500                         std::fill((float*)values[0] + scalarSize*2,     (float*)values[0] + scalarSize*3,       0.0f);
501                         fillRandomScalars(rnd, floatRanges[precision].x(), floatRanges[precision].y(), (float*)values[0] + scalarSize*3, (numValues-3)*scalarSize);
502                 }
503                 else
504                 {
505                         std::fill((int*)values[0],                                      (int*)values[0] + scalarSize,           +1);
506                         std::fill((int*)values[0] + scalarSize*1,       (int*)values[0] + scalarSize*2,         -1);
507                         std::fill((int*)values[0] + scalarSize*2,       (int*)values[0] + scalarSize*3,         0);
508                         fillRandomScalars(rnd, intRanges[precision].x(), intRanges[precision].y(), (int*)values[0] + scalarSize*3, (numValues-3)*scalarSize);
509                 }
510         }
511
512         bool compare (const void* const* inputs, const void* const* outputs)
513         {
514                 const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
515                 const glu::Precision    precision               = m_spec.inputs[0].varType.getPrecision();
516                 const int                               scalarSize              = glu::getDataTypeScalarSize(type);
517
518                 if (glu::isDataTypeFloatOrVec(type))
519                 {
520                         // Both highp and mediump should be able to represent -1, 0, and +1 exactly
521                         const deUint32 maxUlpDiff = precision == glu::PRECISION_LOWP ? getMaxUlpDiffFromBits(getMinMantissaBits(precision)) : 0;
522
523                         for (int compNdx = 0; compNdx < scalarSize; compNdx++)
524                         {
525                                 const float             in0                     = ((const float*)inputs[0])[compNdx];
526                                 const float             out0            = ((const float*)outputs[0])[compNdx];
527                                 const float             ref0            = in0 < 0.0f ? -1.0f :
528                                                                                           in0 > 0.0f ? +1.0f : 0.0f;
529                                 const deUint32  ulpDiff0        = getUlpDiff(out0, ref0);
530
531                                 if (ulpDiff0 > maxUlpDiff)
532                                 {
533                                         m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref0) << " with ULP threshold " << maxUlpDiff << ", got ULP diff " << ulpDiff0;
534                                         return false;
535                                 }
536                         }
537                 }
538                 else
539                 {
540                         for (int compNdx = 0; compNdx < scalarSize; compNdx++)
541                         {
542                                 const int       in0             = ((const int*)inputs[0])[compNdx];
543                                 const int       out0    = ((const int*)outputs[0])[compNdx];
544                                 const int       ref0    = in0 < 0 ? -1 :
545                                                                           in0 > 0 ? +1 : 0;
546
547                                 if (out0 != ref0)
548                                 {
549                                         m_failMsg << "Expected [" << compNdx << "] = " << ref0;
550                                         return false;
551                                 }
552                         }
553                 }
554
555                 return true;
556         }
557 };
558
559 static float roundEven (float v)
560 {
561         const float             q                       = deFloatFrac(v);
562         const int               truncated       = int(v-q);
563         const int               rounded         = (q > 0.5f)                                                    ? (truncated + 1) :     // Rounded up
564                                                                         (q == 0.5f && (truncated % 2 != 0))     ? (truncated + 1) :     // Round to nearest even at 0.5
565                                                                         truncated;                                                                                              // Rounded down
566
567         return float(rounded);
568 }
569
570 class RoundEvenCase : public CommonFunctionCase
571 {
572 public:
573         RoundEvenCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
574                 : CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "roundEven", shaderType)
575         {
576                 m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
577                 m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision)));
578                 m_spec.source = "out0 = roundEven(in0);";
579         }
580
581         void getInputValues (int numValues, void* const* values) const
582         {
583                 const Vec2 ranges[] =
584                 {
585                         Vec2(-2.0f,             2.0f),  // lowp
586                         Vec2(-1e3f,             1e3f),  // mediump
587                         Vec2(-1e7f,             1e7f)   // highp
588                 };
589
590                 de::Random                              rnd                             (deStringHash(getName()) ^ 0xac23fu);
591                 const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
592                 const glu::Precision    precision               = m_spec.inputs[0].varType.getPrecision();
593                 const int                               scalarSize              = glu::getDataTypeScalarSize(type);
594                 int                                             numSpecialCases = 0;
595
596                 // Special cases.
597                 if (precision != glu::PRECISION_LOWP)
598                 {
599                         DE_ASSERT(numValues >= 20);
600                         for (int ndx = 0; ndx < 20; ndx++)
601                         {
602                                 const float v = de::clamp(float(ndx) - 10.5f, ranges[precision].x(), ranges[precision].y());
603                                 std::fill((float*)values[0], (float*)values[0] + scalarSize, v);
604                                 numSpecialCases += 1;
605                         }
606                 }
607
608                 // Random cases.
609                 fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), (float*)values[0] + numSpecialCases*scalarSize, (numValues-numSpecialCases)*scalarSize);
610
611                 // If precision is mediump, make sure values can be represented in fp16 exactly
612                 if (precision == glu::PRECISION_MEDIUMP)
613                 {
614                         for (int ndx = 0; ndx < numValues*scalarSize; ndx++)
615                                 ((float*)values[0])[ndx] = tcu::Float16(((float*)values[0])[ndx]).asFloat();
616                 }
617         }
618
619         bool compare (const void* const* inputs, const void* const* outputs)
620         {
621                 const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
622                 const glu::Precision    precision               = m_spec.inputs[0].varType.getPrecision();
623                 const bool                              hasSignedZero   = supportsSignedZero(precision);
624                 const int                               scalarSize              = glu::getDataTypeScalarSize(type);
625
626                 if (precision == glu::PRECISION_HIGHP || precision == glu::PRECISION_MEDIUMP)
627                 {
628                         // Require exact rounding result.
629                         for (int compNdx = 0; compNdx < scalarSize; compNdx++)
630                         {
631                                 const float             in0                     = ((const float*)inputs[0])[compNdx];
632                                 const float             out0            = ((const float*)outputs[0])[compNdx];
633                                 const float             ref                     = roundEven(in0);
634
635                                 const deUint32  ulpDiff         = hasSignedZero ? getUlpDiff(out0, ref) : getUlpDiffIgnoreZeroSign(out0, ref);
636
637                                 if (ulpDiff > 0)
638                                 {
639                                         m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref) << ", got ULP diff " << tcu::toHex(ulpDiff);
640                                         return false;
641                                 }
642                         }
643                 }
644                 else
645                 {
646                         const int               mantissaBits    = getMinMantissaBits(precision);
647                         const deUint32  maxUlpDiff              = getMaxUlpDiffFromBits(mantissaBits);  // ULP diff for rounded integer value.
648                         const float             eps                             = getEpsFromBits(1.0f, mantissaBits);   // epsilon for rounding bounds
649
650                         for (int compNdx = 0; compNdx < scalarSize; compNdx++)
651                         {
652                                 const float             in0                     = ((const float*)inputs[0])[compNdx];
653                                 const float             out0            = ((const float*)outputs[0])[compNdx];
654                                 const int               minRes          = int(roundEven(in0-eps));
655                                 const int               maxRes          = int(roundEven(in0+eps));
656                                 bool                    anyOk           = false;
657
658                                 for (int roundedVal = minRes; roundedVal <= maxRes; roundedVal++)
659                                 {
660                                         const deUint32 ulpDiff = getUlpDiffIgnoreZeroSign(out0, float(roundedVal));
661
662                                         if (ulpDiff <= maxUlpDiff)
663                                         {
664                                                 anyOk = true;
665                                                 break;
666                                         }
667                                 }
668
669                                 if (!anyOk)
670                                 {
671                                         m_failMsg << "Expected [" << compNdx << "] = [" << minRes << ", " << maxRes << "] with ULP threshold " << tcu::toHex(maxUlpDiff);
672                                         return false;
673                                 }
674                         }
675                 }
676
677                 return true;
678         }
679 };
680
681 class ModfCase : public CommonFunctionCase
682 {
683 public:
684         ModfCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
685                 : CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "modf", shaderType)
686         {
687                 m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
688                 m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision)));
689                 m_spec.outputs.push_back(Symbol("out1", glu::VarType(baseType, precision)));
690                 m_spec.source = "out0 = modf(in0, out1);";
691         }
692
693         void getInputValues (int numValues, void* const* values) const
694         {
695                 const Vec2 ranges[] =
696                 {
697                         Vec2(-2.0f,             2.0f),  // lowp
698                         Vec2(-1e3f,             1e3f),  // mediump
699                         Vec2(-1e7f,             1e7f)   // highp
700                 };
701
702                 de::Random                              rnd                     (deStringHash(getName()) ^ 0xac23fu);
703                 const glu::DataType             type            = m_spec.inputs[0].varType.getBasicType();
704                 const glu::Precision    precision       = m_spec.inputs[0].varType.getPrecision();
705                 const int                               scalarSize      = glu::getDataTypeScalarSize(type);
706
707                 fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), values[0], numValues*scalarSize);
708         }
709
710         bool compare (const void* const* inputs, const void* const* outputs)
711         {
712                 const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
713                 const glu::Precision    precision               = m_spec.inputs[0].varType.getPrecision();
714                 const bool                              hasZeroSign             = supportsSignedZero(precision);
715                 const int                               scalarSize              = glu::getDataTypeScalarSize(type);
716
717                 const int                               mantissaBits    = getMinMantissaBits(precision);
718
719                 for (int compNdx = 0; compNdx < scalarSize; compNdx++)
720                 {
721                         const float             in0                     = ((const float*)inputs[0])[compNdx];
722                         const float             out0            = ((const float*)outputs[0])[compNdx];
723                         const float             out1            = ((const float*)outputs[1])[compNdx];
724
725                         const float             refOut1         = float(int(in0));
726                         const float             refOut0         = in0 - refOut1;
727
728                         const int               bitsLost        = precision != glu::PRECISION_HIGHP ? numBitsLostInOp(in0, refOut0) : 0;
729                         const deUint32  maxUlpDiff      = getMaxUlpDiffFromBits(de::max(mantissaBits - bitsLost, 0));
730
731                         const float             resSum          = out0 + out1;
732
733                         const deUint32  ulpDiff         = hasZeroSign ? getUlpDiff(resSum, in0) : getUlpDiffIgnoreZeroSign(resSum, in0);
734
735                         if (ulpDiff > maxUlpDiff)
736                         {
737                                 m_failMsg << "Expected [" << compNdx << "] = (" << HexFloat(refOut0) << ") + (" << HexFloat(refOut1) << ") = " << HexFloat(in0) << " with ULP threshold "
738                                                         << tcu::toHex(maxUlpDiff) << ", got ULP diff " << tcu::toHex(ulpDiff);
739                                 return false;
740                         }
741                 }
742
743                 return true;
744         }
745 };
746
747 class IsnanCase : public CommonFunctionCase
748 {
749 public:
750         IsnanCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
751                 : CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "isnan", shaderType)
752         {
753                 DE_ASSERT(glu::isDataTypeFloatOrVec(baseType));
754
755                 const int                       vecSize         = glu::getDataTypeScalarSize(baseType);
756                 const glu::DataType     boolType        = vecSize > 1 ? glu::getDataTypeBoolVec(vecSize) : glu::TYPE_BOOL;
757
758                 m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
759                 m_spec.outputs.push_back(Symbol("out0", glu::VarType(boolType, glu::PRECISION_LAST)));
760                 m_spec.source = "out0 = isnan(in0);";
761         }
762
763         void getInputValues (int numValues, void* const* values) const
764         {
765                 de::Random                              rnd                             (deStringHash(getName()) ^ 0xc2a39fu);
766                 const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
767                 const glu::Precision    precision               = m_spec.inputs[0].varType.getPrecision();
768                 const int                               scalarSize              = glu::getDataTypeScalarSize(type);
769                 const int                               mantissaBits    = getMinMantissaBits(precision);
770                 const deUint32                  mantissaMask    = ~getMaxUlpDiffFromBits(mantissaBits) & ((1u<<23)-1u);
771
772                 for (int valNdx = 0; valNdx < numValues*scalarSize; valNdx++)
773                 {
774                         const bool              isNan           = rnd.getFloat() > 0.3f;
775                         const bool              isInf           = !isNan && rnd.getFloat() > 0.4f;
776                         const deUint32  mantissa        = !isInf ? ((1u<<22) | (rnd.getUint32() & mantissaMask)) : 0;
777                         const deUint32  exp                     = !isNan && !isInf ? (rnd.getUint32() & 0x7fu) : 0xffu;
778                         const deUint32  sign            = rnd.getUint32() & 0x1u;
779                         const deUint32  value           = (sign << 31) | (exp << 23) | mantissa;
780
781                         DE_ASSERT(tcu::Float32(value).isInf() == isInf && tcu::Float32(value).isNaN() == isNan);
782
783                         ((deUint32*)values[0])[valNdx] = value;
784                 }
785         }
786
787         bool compare (const void* const* inputs, const void* const* outputs)
788         {
789                 const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
790                 const glu::Precision    precision               = m_spec.inputs[0].varType.getPrecision();
791                 const int                               scalarSize              = glu::getDataTypeScalarSize(type);
792
793                 if (precision == glu::PRECISION_HIGHP)
794                 {
795                         // Only highp is required to support inf/nan
796                         for (int compNdx = 0; compNdx < scalarSize; compNdx++)
797                         {
798                                 const float             in0             = ((const float*)inputs[0])[compNdx];
799                                 const deUint32  out0    = ((const deUint32*)outputs[0])[compNdx];
800                                 const deUint32  ref             = tcu::Float32(in0).isNaN() ? 1u : 0u;
801
802                                 if (out0 != ref)
803                                 {
804                                         m_failMsg << "Expected [" << compNdx << "] = " << HexBool(ref);
805                                         return false;
806                                 }
807                         }
808                 }
809                 else
810                 {
811                         // Value can be either 0 or 1
812                         for (int compNdx = 0; compNdx < scalarSize; compNdx++)
813                         {
814                                 const int out0 = ((const int*)outputs[0])[compNdx];
815
816                                 if (out0 != 0 && out0 != 1)
817                                 {
818                                         m_failMsg << "Expected [" << compNdx << "] = 0 / 1";
819                                         return false;
820                                 }
821                         }
822                 }
823
824                 return true;
825         }
826 };
827
828 class IsinfCase : public CommonFunctionCase
829 {
830 public:
831         IsinfCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
832                 : CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "isinf", shaderType)
833         {
834                 DE_ASSERT(glu::isDataTypeFloatOrVec(baseType));
835
836                 const int                       vecSize         = glu::getDataTypeScalarSize(baseType);
837                 const glu::DataType     boolType        = vecSize > 1 ? glu::getDataTypeBoolVec(vecSize) : glu::TYPE_BOOL;
838
839                 m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
840                 m_spec.outputs.push_back(Symbol("out0", glu::VarType(boolType, glu::PRECISION_LAST)));
841                 m_spec.source = "out0 = isinf(in0);";
842         }
843
844         void getInputValues (int numValues, void* const* values) const
845         {
846                 de::Random                              rnd                             (deStringHash(getName()) ^ 0xc2a39fu);
847                 const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
848                 const glu::Precision    precision               = m_spec.inputs[0].varType.getPrecision();
849                 const int                               scalarSize              = glu::getDataTypeScalarSize(type);
850                 const int                               mantissaBits    = getMinMantissaBits(precision);
851                 const deUint32                  mantissaMask    = ~getMaxUlpDiffFromBits(mantissaBits) & ((1u<<23)-1u);
852
853                 for (int valNdx = 0; valNdx < numValues*scalarSize; valNdx++)
854                 {
855                         const bool              isInf           = rnd.getFloat() > 0.3f;
856                         const bool              isNan           = !isInf && rnd.getFloat() > 0.4f;
857                         const deUint32  mantissa        = !isInf ? ((1u<<22) | (rnd.getUint32() & mantissaMask)) : 0;
858                         const deUint32  exp                     = !isNan && !isInf ? (rnd.getUint32() & 0x7fu) : 0xffu;
859                         const deUint32  sign            = rnd.getUint32() & 0x1u;
860                         const deUint32  value           = (sign << 31) | (exp << 23) | mantissa;
861
862                         DE_ASSERT(tcu::Float32(value).isInf() == isInf && tcu::Float32(value).isNaN() == isNan);
863
864                         ((deUint32*)values[0])[valNdx] = value;
865                 }
866         }
867
868         bool compare (const void* const* inputs, const void* const* outputs)
869         {
870                 const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
871                 const glu::Precision    precision               = m_spec.inputs[0].varType.getPrecision();
872                 const int                               scalarSize              = glu::getDataTypeScalarSize(type);
873
874                 if (precision == glu::PRECISION_HIGHP)
875                 {
876                         // Only highp is required to support inf/nan
877                         for (int compNdx = 0; compNdx < scalarSize; compNdx++)
878                         {
879                                 const float             in0             = ((const float*)inputs[0])[compNdx];
880                                 const deUint32  out0    = ((const deUint32*)outputs[0])[compNdx];
881                                 const deUint32  ref             = tcu::Float32(in0).isInf() ? 1u : 0u;
882
883                                 if (out0 != ref)
884                                 {
885                                         m_failMsg << "Expected [" << compNdx << "] = " << HexBool(ref);
886                                         return false;
887                                 }
888                         }
889                 }
890                 else
891                 {
892                         // Value can be either 0 or 1
893                         for (int compNdx = 0; compNdx < scalarSize; compNdx++)
894                         {
895                                 const int out0 = ((const int*)outputs[0])[compNdx];
896
897                                 if (out0 != 0 && out0 != 1)
898                                 {
899                                         m_failMsg << "Expected [" << compNdx << "] = 0 / 1";
900                                         return false;
901                                 }
902                         }
903                 }
904
905                 return true;
906         }
907 };
908
909 class FloatBitsToUintIntCase : public CommonFunctionCase
910 {
911 public:
912         FloatBitsToUintIntCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType, bool outIsSigned)
913                 : CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), outIsSigned ? "floatBitsToInt" : "floatBitsToUint", shaderType)
914         {
915                 const int                       vecSize         = glu::getDataTypeScalarSize(baseType);
916                 const glu::DataType     intType         = outIsSigned ? (vecSize > 1 ? glu::getDataTypeIntVec(vecSize) : glu::TYPE_INT)
917                                                                                                           : (vecSize > 1 ? glu::getDataTypeUintVec(vecSize) : glu::TYPE_UINT);
918
919                 m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
920                 m_spec.outputs.push_back(Symbol("out0", glu::VarType(intType, glu::PRECISION_HIGHP)));
921                 m_spec.source = outIsSigned ? "out0 = floatBitsToInt(in0);" : "out0 = floatBitsToUint(in0);";
922         }
923
924         void getInputValues (int numValues, void* const* values) const
925         {
926                 const Vec2 ranges[] =
927                 {
928                         Vec2(-2.0f,             2.0f),  // lowp
929                         Vec2(-1e3f,             1e3f),  // mediump
930                         Vec2(-1e7f,             1e7f)   // highp
931                 };
932
933                 de::Random                              rnd                     (deStringHash(getName()) ^ 0x2790au);
934                 const glu::DataType             type            = m_spec.inputs[0].varType.getBasicType();
935                 const glu::Precision    precision       = m_spec.inputs[0].varType.getPrecision();
936                 const int                               scalarSize      = glu::getDataTypeScalarSize(type);
937
938                 fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), values[0], numValues*scalarSize);
939         }
940
941         bool compare (const void* const* inputs, const void* const* outputs)
942         {
943                 const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
944                 const glu::Precision    precision               = m_spec.inputs[0].varType.getPrecision();
945                 const int                               scalarSize              = glu::getDataTypeScalarSize(type);
946
947                 const int                               mantissaBits    = getMinMantissaBits(precision);
948                 const int                               maxUlpDiff              = getMaxUlpDiffFromBits(mantissaBits);
949
950                 for (int compNdx = 0; compNdx < scalarSize; compNdx++)
951                 {
952                         const float             in0                     = ((const float*)inputs[0])[compNdx];
953                         const deUint32  out0            = ((const deUint32*)outputs[0])[compNdx];
954                         const deUint32  refOut0         = tcu::Float32(in0).bits();
955                         const int               ulpDiff         = de::abs((int)out0 - (int)refOut0);
956
957                         if (ulpDiff > maxUlpDiff)
958                         {
959                                 m_failMsg << "Expected [" << compNdx << "] = " << tcu::toHex(refOut0) << " with threshold "
960                                                         << tcu::toHex(maxUlpDiff) << ", got diff " << tcu::toHex(ulpDiff);
961                                 return false;
962                         }
963                 }
964
965                 return true;
966         }
967 };
968
969 class FloatBitsToIntCase : public FloatBitsToUintIntCase
970 {
971 public:
972         FloatBitsToIntCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
973                 : FloatBitsToUintIntCase(context, baseType, precision, shaderType, true)
974         {
975         }
976 };
977
978 class FloatBitsToUintCase : public FloatBitsToUintIntCase
979 {
980 public:
981         FloatBitsToUintCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
982                 : FloatBitsToUintIntCase(context, baseType, precision, shaderType, false)
983         {
984         }
985 };
986
987 class BitsToFloatCase : public CommonFunctionCase
988 {
989 public:
990         BitsToFloatCase (Context& context, glu::DataType baseType, glu::ShaderType shaderType)
991                 : CommonFunctionCase(context, getCommonFuncCaseName(baseType, glu::PRECISION_HIGHP, shaderType).c_str(), glu::isDataTypeIntOrIVec(baseType) ? "intBitsToFloat" : "uintBitsToFloat", shaderType)
992         {
993                 const bool                      inIsSigned      = glu::isDataTypeIntOrIVec(baseType);
994                 const int                       vecSize         = glu::getDataTypeScalarSize(baseType);
995                 const glu::DataType     floatType       = vecSize > 1 ? glu::getDataTypeFloatVec(vecSize) : glu::TYPE_FLOAT;
996
997                 m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, glu::PRECISION_HIGHP)));
998                 m_spec.outputs.push_back(Symbol("out0", glu::VarType(floatType, glu::PRECISION_HIGHP)));
999                 m_spec.source = inIsSigned ? "out0 = intBitsToFloat(in0);" : "out0 = uintBitsToFloat(in0);";
1000         }
1001
1002         void getInputValues (int numValues, void* const* values) const
1003         {
1004                 de::Random                              rnd                     (deStringHash(getName()) ^ 0xbbb225u);
1005                 const glu::DataType             type            = m_spec.inputs[0].varType.getBasicType();
1006                 const int                               scalarSize      = glu::getDataTypeScalarSize(type);
1007                 const Vec2                              range           (-1e8f, +1e8f);
1008
1009                 // \note Filled as floats.
1010                 fillRandomScalars(rnd, range.x(), range.y(), values[0], numValues*scalarSize);
1011         }
1012
1013         bool compare (const void* const* inputs, const void* const* outputs)
1014         {
1015                 const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
1016                 const int                               scalarSize              = glu::getDataTypeScalarSize(type);
1017                 const deUint32                  maxUlpDiff              = 0;
1018
1019                 for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1020                 {
1021                         const float             in0                     = ((const float*)inputs[0])[compNdx];
1022                         const float             out0            = ((const float*)outputs[0])[compNdx];
1023                         const deUint32  ulpDiff         = getUlpDiff(in0, out0);
1024
1025                         if (ulpDiff > maxUlpDiff)
1026                         {
1027                                 m_failMsg << "Expected [" << compNdx << "] = " << tcu::toHex(tcu::Float32(in0).bits()) << " with ULP threshold "
1028                                                         << tcu::toHex(maxUlpDiff) << ", got ULP diff " << tcu::toHex(ulpDiff);
1029                                 return false;
1030                         }
1031                 }
1032
1033                 return true;
1034         }
1035 };
1036
1037 class FloorCase : public CommonFunctionCase
1038 {
1039 public:
1040         FloorCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
1041                 : CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "floor", shaderType)
1042         {
1043                 m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
1044                 m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision)));
1045                 m_spec.source = "out0 = floor(in0);";
1046         }
1047
1048         void getInputValues (int numValues, void* const* values) const
1049         {
1050                 const Vec2 ranges[] =
1051                 {
1052                         Vec2(-2.0f,             2.0f),  // lowp
1053                         Vec2(-1e3f,             1e3f),  // mediump
1054                         Vec2(-1e7f,             1e7f)   // highp
1055                 };
1056
1057                 de::Random                              rnd                     (deStringHash(getName()) ^ 0xac23fu);
1058                 const glu::DataType             type            = m_spec.inputs[0].varType.getBasicType();
1059                 const glu::Precision    precision       = m_spec.inputs[0].varType.getPrecision();
1060                 const int                               scalarSize      = glu::getDataTypeScalarSize(type);
1061                 // Random cases.
1062                 fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), (float*)values[0], numValues*scalarSize);
1063
1064                 // If precision is mediump, make sure values can be represented in fp16 exactly
1065                 if (precision == glu::PRECISION_MEDIUMP)
1066                 {
1067                         for (int ndx = 0; ndx < numValues*scalarSize; ndx++)
1068                                 ((float*)values[0])[ndx] = tcu::Float16(((float*)values[0])[ndx]).asFloat();
1069                 }
1070         }
1071
1072         bool compare (const void* const* inputs, const void* const* outputs)
1073         {
1074                 const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
1075                 const glu::Precision    precision               = m_spec.inputs[0].varType.getPrecision();
1076                 const int                               scalarSize              = glu::getDataTypeScalarSize(type);
1077
1078                 if (precision == glu::PRECISION_HIGHP || precision == glu::PRECISION_MEDIUMP)
1079                 {
1080                         // Require exact result.
1081                         for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1082                         {
1083                                 const float             in0                     = ((const float*)inputs[0])[compNdx];
1084                                 const float             out0            = ((const float*)outputs[0])[compNdx];
1085                                 const float             ref                     = deFloatFloor(in0);
1086
1087                                 const deUint32  ulpDiff         = getUlpDiff(out0, ref);
1088
1089                                 if (ulpDiff > 0)
1090                                 {
1091                                         m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref) << ", got ULP diff " << tcu::toHex(ulpDiff);
1092                                         return false;
1093                                 }
1094                         }
1095                 }
1096                 else
1097                 {
1098                         const int               mantissaBits    = getMinMantissaBits(precision);
1099                         const deUint32  maxUlpDiff              = getMaxUlpDiffFromBits(mantissaBits);  // ULP diff for rounded integer value.
1100                         const float             eps                             = getEpsFromBits(1.0f, mantissaBits);   // epsilon for rounding bounds
1101
1102                         for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1103                         {
1104                                 const float             in0                     = ((const float*)inputs[0])[compNdx];
1105                                 const float             out0            = ((const float*)outputs[0])[compNdx];
1106                                 const int               minRes          = int(deFloatFloor(in0-eps));
1107                                 const int               maxRes          = int(deFloatFloor(in0+eps));
1108                                 bool                    anyOk           = false;
1109
1110                                 for (int roundedVal = minRes; roundedVal <= maxRes; roundedVal++)
1111                                 {
1112                                         const deUint32 ulpDiff = getUlpDiff(out0, float(roundedVal));
1113
1114                                         if (ulpDiff <= maxUlpDiff)
1115                                         {
1116                                                 anyOk = true;
1117                                                 break;
1118                                         }
1119                                 }
1120
1121                                 if (!anyOk)
1122                                 {
1123                                         m_failMsg << "Expected [" << compNdx << "] = [" << minRes << ", " << maxRes << "] with ULP threshold " << tcu::toHex(maxUlpDiff);
1124                                         return false;
1125                                 }
1126                         }
1127                 }
1128
1129                 return true;
1130         }
1131 };
1132
1133 class TruncCase : public CommonFunctionCase
1134 {
1135 public:
1136         TruncCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
1137                 : CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "trunc", shaderType)
1138         {
1139                 m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
1140                 m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision)));
1141                 m_spec.source = "out0 = trunc(in0);";
1142         }
1143
1144         void getInputValues (int numValues, void* const* values) const
1145         {
1146                 const Vec2 ranges[] =
1147                 {
1148                         Vec2(-2.0f,             2.0f),  // lowp
1149                         Vec2(-1e3f,             1e3f),  // mediump
1150                         Vec2(-1e7f,             1e7f)   // highp
1151                 };
1152
1153                 de::Random                              rnd                             (deStringHash(getName()) ^ 0xac23fu);
1154                 const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
1155                 const glu::Precision    precision               = m_spec.inputs[0].varType.getPrecision();
1156                 const int                               scalarSize              = glu::getDataTypeScalarSize(type);
1157                 const float                             specialCases[]  = { 0.0f, -0.0f, -0.9f, 0.9f, 1.0f, -1.0f };
1158                 const int                               numSpecialCases = DE_LENGTH_OF_ARRAY(specialCases);
1159
1160                 // Special cases
1161                 for (int caseNdx = 0; caseNdx < numSpecialCases; caseNdx++)
1162                 {
1163                         for (int scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++)
1164                                 ((float*)values[0])[caseNdx*scalarSize + scalarNdx] = specialCases[caseNdx];
1165                 }
1166
1167                 // Random cases.
1168                 fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), (float*)values[0] + scalarSize*numSpecialCases, (numValues-numSpecialCases)*scalarSize);
1169
1170                 // If precision is mediump, make sure values can be represented in fp16 exactly
1171                 if (precision == glu::PRECISION_MEDIUMP)
1172                 {
1173                         for (int ndx = 0; ndx < numValues*scalarSize; ndx++)
1174                                 ((float*)values[0])[ndx] = tcu::Float16(((float*)values[0])[ndx]).asFloat();
1175                 }
1176         }
1177
1178         bool compare (const void* const* inputs, const void* const* outputs)
1179         {
1180                 const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
1181                 const glu::Precision    precision               = m_spec.inputs[0].varType.getPrecision();
1182                 const int                               scalarSize              = glu::getDataTypeScalarSize(type);
1183
1184                 if (precision == glu::PRECISION_HIGHP || precision == glu::PRECISION_MEDIUMP)
1185                 {
1186                         // Require exact result.
1187                         for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1188                         {
1189                                 const float             in0                     = ((const float*)inputs[0])[compNdx];
1190                                 const float             out0            = ((const float*)outputs[0])[compNdx];
1191                                 const bool              isNeg           = tcu::Float32(in0).sign() < 0;
1192                                 const float             ref                     = isNeg ? (-float(int(-in0))) : float(int(in0));
1193
1194                                 // \note: trunc() function definition is a bit broad on negative zeros. Ignore result sign if zero.
1195                                 const deUint32  ulpDiff         = getUlpDiffIgnoreZeroSign(out0, ref);
1196
1197                                 if (ulpDiff > 0)
1198                                 {
1199                                         m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref) << ", got ULP diff " << tcu::toHex(ulpDiff);
1200                                         return false;
1201                                 }
1202                         }
1203                 }
1204                 else
1205                 {
1206                         const int               mantissaBits    = getMinMantissaBits(precision);
1207                         const deUint32  maxUlpDiff              = getMaxUlpDiffFromBits(mantissaBits);  // ULP diff for rounded integer value.
1208                         const float             eps                             = getEpsFromBits(1.0f, mantissaBits);   // epsilon for rounding bounds
1209
1210                         for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1211                         {
1212                                 const float             in0                     = ((const float*)inputs[0])[compNdx];
1213                                 const float             out0            = ((const float*)outputs[0])[compNdx];
1214                                 const int               minRes          = int(in0-eps);
1215                                 const int               maxRes          = int(in0+eps);
1216                                 bool                    anyOk           = false;
1217
1218                                 for (int roundedVal = minRes; roundedVal <= maxRes; roundedVal++)
1219                                 {
1220                                         const deUint32 ulpDiff = getUlpDiffIgnoreZeroSign(out0, float(roundedVal));
1221
1222                                         if (ulpDiff <= maxUlpDiff)
1223                                         {
1224                                                 anyOk = true;
1225                                                 break;
1226                                         }
1227                                 }
1228
1229                                 if (!anyOk)
1230                                 {
1231                                         m_failMsg << "Expected [" << compNdx << "] = [" << minRes << ", " << maxRes << "] with ULP threshold " << tcu::toHex(maxUlpDiff);
1232                                         return false;
1233                                 }
1234                         }
1235                 }
1236
1237                 return true;
1238         }
1239 };
1240
1241 class RoundCase : public CommonFunctionCase
1242 {
1243 public:
1244         RoundCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
1245                 : CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "round", shaderType)
1246         {
1247                 m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
1248                 m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision)));
1249                 m_spec.source = "out0 = round(in0);";
1250         }
1251
1252         void getInputValues (int numValues, void* const* values) const
1253         {
1254                 const Vec2 ranges[] =
1255                 {
1256                         Vec2(-2.0f,             2.0f),  // lowp
1257                         Vec2(-1e3f,             1e3f),  // mediump
1258                         Vec2(-1e7f,             1e7f)   // highp
1259                 };
1260
1261                 de::Random                              rnd                             (deStringHash(getName()) ^ 0xac23fu);
1262                 const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
1263                 const glu::Precision    precision               = m_spec.inputs[0].varType.getPrecision();
1264                 const int                               scalarSize              = glu::getDataTypeScalarSize(type);
1265                 int                                             numSpecialCases = 0;
1266
1267                 // Special cases.
1268                 if (precision != glu::PRECISION_LOWP)
1269                 {
1270                         DE_ASSERT(numValues >= 10);
1271                         for (int ndx = 0; ndx < 10; ndx++)
1272                         {
1273                                 const float v = de::clamp(float(ndx) - 5.5f, ranges[precision].x(), ranges[precision].y());
1274                                 std::fill((float*)values[0], (float*)values[0] + scalarSize, v);
1275                                 numSpecialCases += 1;
1276                         }
1277                 }
1278
1279                 // Random cases.
1280                 fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), (float*)values[0] + numSpecialCases*scalarSize, (numValues-numSpecialCases)*scalarSize);
1281
1282                 // If precision is mediump, make sure values can be represented in fp16 exactly
1283                 if (precision == glu::PRECISION_MEDIUMP)
1284                 {
1285                         for (int ndx = 0; ndx < numValues*scalarSize; ndx++)
1286                                 ((float*)values[0])[ndx] = tcu::Float16(((float*)values[0])[ndx]).asFloat();
1287                 }
1288         }
1289
1290         bool compare (const void* const* inputs, const void* const* outputs)
1291         {
1292                 const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
1293                 const glu::Precision    precision               = m_spec.inputs[0].varType.getPrecision();
1294                 const bool                              hasZeroSign             = supportsSignedZero(precision);
1295                 const int                               scalarSize              = glu::getDataTypeScalarSize(type);
1296
1297                 if (precision == glu::PRECISION_HIGHP || precision == glu::PRECISION_MEDIUMP)
1298                 {
1299                         for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1300                         {
1301                                 const float             in0                     = ((const float*)inputs[0])[compNdx];
1302                                 const float             out0            = ((const float*)outputs[0])[compNdx];
1303
1304                                 if (deFloatFrac(in0) == 0.5f)
1305                                 {
1306                                         // Allow both ceil(in) and floor(in)
1307                                         const float             ref0            = deFloatFloor(in0);
1308                                         const float             ref1            = deFloatCeil(in0);
1309                                         const deUint32  ulpDiff0        = hasZeroSign ? getUlpDiff(out0, ref0) : getUlpDiffIgnoreZeroSign(out0, ref0);
1310                                         const deUint32  ulpDiff1        = hasZeroSign ? getUlpDiff(out0, ref1) : getUlpDiffIgnoreZeroSign(out0, ref1);
1311
1312                                         if (ulpDiff0 > 0 && ulpDiff1 > 0)
1313                                         {
1314                                                 m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref0) << " or " << HexFloat(ref1) << ", got ULP diff " << tcu::toHex(de::min(ulpDiff0, ulpDiff1));
1315                                                 return false;
1316                                         }
1317                                 }
1318                                 else
1319                                 {
1320                                         // Require exact result
1321                                         const float             ref             = roundEven(in0);
1322                                         const deUint32  ulpDiff = hasZeroSign ? getUlpDiff(out0, ref) : getUlpDiffIgnoreZeroSign(out0, ref);
1323
1324                                         if (ulpDiff > 0)
1325                                         {
1326                                                 m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref) << ", got ULP diff " << tcu::toHex(ulpDiff);
1327                                                 return false;
1328                                         }
1329                                 }
1330                         }
1331                 }
1332                 else
1333                 {
1334                         const int               mantissaBits    = getMinMantissaBits(precision);
1335                         const deUint32  maxUlpDiff              = getMaxUlpDiffFromBits(mantissaBits);  // ULP diff for rounded integer value.
1336                         const float             eps                             = getEpsFromBits(1.0f, mantissaBits);   // epsilon for rounding bounds
1337
1338                         for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1339                         {
1340                                 const float             in0                     = ((const float*)inputs[0])[compNdx];
1341                                 const float             out0            = ((const float*)outputs[0])[compNdx];
1342                                 const int               minRes          = int(roundEven(in0-eps));
1343                                 const int               maxRes          = int(roundEven(in0+eps));
1344                                 bool                    anyOk           = false;
1345
1346                                 for (int roundedVal = minRes; roundedVal <= maxRes; roundedVal++)
1347                                 {
1348                                         const deUint32 ulpDiff = getUlpDiffIgnoreZeroSign(out0, float(roundedVal));
1349
1350                                         if (ulpDiff <= maxUlpDiff)
1351                                         {
1352                                                 anyOk = true;
1353                                                 break;
1354                                         }
1355                                 }
1356
1357                                 if (!anyOk)
1358                                 {
1359                                         m_failMsg << "Expected [" << compNdx << "] = [" << minRes << ", " << maxRes << "] with ULP threshold " << tcu::toHex(maxUlpDiff);
1360                                         return false;
1361                                 }
1362                         }
1363                 }
1364
1365                 return true;
1366         }
1367 };
1368
1369 class CeilCase : public CommonFunctionCase
1370 {
1371 public:
1372         CeilCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
1373                 : CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "ceil", shaderType)
1374         {
1375                 m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
1376                 m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision)));
1377                 m_spec.source = "out0 = ceil(in0);";
1378         }
1379
1380         void getInputValues (int numValues, void* const* values) const
1381         {
1382                 const Vec2 ranges[] =
1383                 {
1384                         Vec2(-2.0f,             2.0f),  // lowp
1385                         Vec2(-1e3f,             1e3f),  // mediump
1386                         Vec2(-1e7f,             1e7f)   // highp
1387                 };
1388
1389                 de::Random                              rnd                     (deStringHash(getName()) ^ 0xac23fu);
1390                 const glu::DataType             type            = m_spec.inputs[0].varType.getBasicType();
1391                 const glu::Precision    precision       = m_spec.inputs[0].varType.getPrecision();
1392                 const int                               scalarSize      = glu::getDataTypeScalarSize(type);
1393
1394                 // Random cases.
1395                 fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), (float*)values[0], numValues*scalarSize);
1396
1397                 // If precision is mediump, make sure values can be represented in fp16 exactly
1398                 if (precision == glu::PRECISION_MEDIUMP)
1399                 {
1400                         for (int ndx = 0; ndx < numValues*scalarSize; ndx++)
1401                                 ((float*)values[0])[ndx] = tcu::Float16(((float*)values[0])[ndx]).asFloat();
1402                 }
1403         }
1404
1405         bool compare (const void* const* inputs, const void* const* outputs)
1406         {
1407                 const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
1408                 const glu::Precision    precision               = m_spec.inputs[0].varType.getPrecision();
1409                 const bool                              hasZeroSign             = supportsSignedZero(precision);
1410                 const int                               scalarSize              = glu::getDataTypeScalarSize(type);
1411
1412                 if (precision == glu::PRECISION_HIGHP || precision == glu::PRECISION_MEDIUMP)
1413                 {
1414                         // Require exact result.
1415                         for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1416                         {
1417                                 const float             in0                     = ((const float*)inputs[0])[compNdx];
1418                                 const float             out0            = ((const float*)outputs[0])[compNdx];
1419                                 const float             ref                     = deFloatCeil(in0);
1420
1421                                 const deUint32  ulpDiff         = hasZeroSign ? getUlpDiff(out0, ref) : getUlpDiffIgnoreZeroSign(out0, ref);
1422
1423                                 if (ulpDiff > 0)
1424                                 {
1425                                         m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref) << ", got ULP diff " << tcu::toHex(ulpDiff);
1426                                         return false;
1427                                 }
1428                         }
1429                 }
1430                 else
1431                 {
1432                         const int               mantissaBits    = getMinMantissaBits(precision);
1433                         const deUint32  maxUlpDiff              = getMaxUlpDiffFromBits(mantissaBits);  // ULP diff for rounded integer value.
1434                         const float             eps                             = getEpsFromBits(1.0f, mantissaBits);   // epsilon for rounding bounds
1435
1436                         for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1437                         {
1438                                 const float             in0                     = ((const float*)inputs[0])[compNdx];
1439                                 const float             out0            = ((const float*)outputs[0])[compNdx];
1440                                 const int               minRes          = int(deFloatCeil(in0-eps));
1441                                 const int               maxRes          = int(deFloatCeil(in0+eps));
1442                                 bool                    anyOk           = false;
1443
1444                                 for (int roundedVal = minRes; roundedVal <= maxRes; roundedVal++)
1445                                 {
1446                                         const deUint32 ulpDiff = getUlpDiffIgnoreZeroSign(out0, float(roundedVal));
1447
1448                                         if (ulpDiff <= maxUlpDiff)
1449                                         {
1450                                                 anyOk = true;
1451                                                 break;
1452                                         }
1453                                 }
1454
1455                                 if (!anyOk && de::inRange(0, minRes, maxRes))
1456                                 {
1457                                         // Allow -0 as well.
1458                                         const int ulpDiff = de::abs((int)tcu::Float32(out0).bits() - (int)0x80000000u);
1459                                         anyOk = ((deUint32)ulpDiff <= maxUlpDiff);
1460                                 }
1461
1462                                 if (!anyOk)
1463                                 {
1464                                         m_failMsg << "Expected [" << compNdx << "] = [" << minRes << ", " << maxRes << "] with ULP threshold " << tcu::toHex(maxUlpDiff);
1465                                         return false;
1466                                 }
1467                         }
1468                 }
1469
1470                 return true;
1471         }
1472 };
1473
1474 class FractCase : public CommonFunctionCase
1475 {
1476 public:
1477         FractCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
1478                 : CommonFunctionCase(context, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "fract", shaderType)
1479         {
1480                 m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
1481                 m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision)));
1482                 m_spec.source = "out0 = fract(in0);";
1483         }
1484
1485         void getInputValues (int numValues, void* const* values) const
1486         {
1487                 const Vec2 ranges[] =
1488                 {
1489                         Vec2(-2.0f,             2.0f),  // lowp
1490                         Vec2(-1e3f,             1e3f),  // mediump
1491                         Vec2(-1e7f,             1e7f)   // highp
1492                 };
1493
1494                 de::Random                              rnd                             (deStringHash(getName()) ^ 0xac23fu);
1495                 const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
1496                 const glu::Precision    precision               = m_spec.inputs[0].varType.getPrecision();
1497                 const int                               scalarSize              = glu::getDataTypeScalarSize(type);
1498                 int                                             numSpecialCases = 0;
1499
1500                 // Special cases.
1501                 if (precision != glu::PRECISION_LOWP)
1502                 {
1503                         DE_ASSERT(numValues >= 10);
1504                         for (int ndx = 0; ndx < 10; ndx++)
1505                         {
1506                                 const float v = de::clamp(float(ndx) - 5.5f, ranges[precision].x(), ranges[precision].y());
1507                                 std::fill((float*)values[0], (float*)values[0] + scalarSize, v);
1508                                 numSpecialCases += 1;
1509                         }
1510                 }
1511
1512                 // Random cases.
1513                 fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), (float*)values[0] + numSpecialCases*scalarSize, (numValues-numSpecialCases)*scalarSize);
1514
1515                 // If precision is mediump, make sure values can be represented in fp16 exactly
1516                 if (precision == glu::PRECISION_MEDIUMP)
1517                 {
1518                         for (int ndx = 0; ndx < numValues*scalarSize; ndx++)
1519                                 ((float*)values[0])[ndx] = tcu::Float16(((float*)values[0])[ndx]).asFloat();
1520                 }
1521         }
1522
1523         bool compare (const void* const* inputs, const void* const* outputs)
1524         {
1525                 const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
1526                 const glu::Precision    precision               = m_spec.inputs[0].varType.getPrecision();
1527                 const bool                              hasZeroSign             = supportsSignedZero(precision);
1528                 const int                               scalarSize              = glu::getDataTypeScalarSize(type);
1529
1530                 if (precision == glu::PRECISION_HIGHP || precision == glu::PRECISION_MEDIUMP)
1531                 {
1532                         // Require exact result.
1533                         for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1534                         {
1535                                 const float             in0                     = ((const float*)inputs[0])[compNdx];
1536                                 const float             out0            = ((const float*)outputs[0])[compNdx];
1537                                 const float             ref                     = deFloatFrac(in0);
1538
1539                                 const deUint32  ulpDiff         = hasZeroSign ? getUlpDiff(out0, ref) : getUlpDiffIgnoreZeroSign(out0, ref);
1540
1541                                 if (ulpDiff > 0)
1542                                 {
1543                                         m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref) << ", got ULP diff " << tcu::toHex(ulpDiff);
1544                                         return false;
1545                                 }
1546                         }
1547                 }
1548                 else
1549                 {
1550                         const int               mantissaBits    = getMinMantissaBits(precision);
1551                         const float             eps                             = getEpsFromBits(1.0f, mantissaBits);   // epsilon for rounding bounds
1552
1553                         for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1554                         {
1555                                 const float             in0                     = ((const float*)inputs[0])[compNdx];
1556                                 const float             out0            = ((const float*)outputs[0])[compNdx];
1557
1558                                 if (int(deFloatFloor(in0-eps)) == int(deFloatFloor(in0+eps)))
1559                                 {
1560                                         const float             ref                     = deFloatFrac(in0);
1561                                         const int               bitsLost        = numBitsLostInOp(in0, ref);
1562                                         const deUint32  maxUlpDiff      = getMaxUlpDiffFromBits(de::max(0, mantissaBits-bitsLost));     // ULP diff for rounded integer value.
1563                                         const deUint32  ulpDiff         = getUlpDiffIgnoreZeroSign(out0, ref);
1564
1565                                         if (ulpDiff > maxUlpDiff)
1566                                         {
1567                                                 m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref) << " with ULP threshold " << tcu::toHex(maxUlpDiff) << ", got diff " << tcu::toHex(ulpDiff);
1568                                                 return false;
1569                                         }
1570                                 }
1571                                 else
1572                                 {
1573                                         if (out0 >= 1.0f)
1574                                         {
1575                                                 m_failMsg << "Expected [" << compNdx << "] < 1.0";
1576                                                 return false;
1577                                         }
1578                                 }
1579                         }
1580                 }
1581
1582                 return true;
1583         }
1584 };
1585
1586 ShaderCommonFunctionTests::ShaderCommonFunctionTests (Context& context)
1587         : TestCaseGroup(context, "common", "Common function tests")
1588 {
1589 }
1590
1591 ShaderCommonFunctionTests::~ShaderCommonFunctionTests (void)
1592 {
1593 }
1594
1595 template<class TestClass>
1596 static void addFunctionCases (TestCaseGroup* parent, const char* functionName, bool floatTypes, bool intTypes, bool uintTypes)
1597 {
1598         tcu::TestCaseGroup* group = new tcu::TestCaseGroup(parent->getTestContext(), functionName, functionName);
1599         parent->addChild(group);
1600
1601         const glu::DataType scalarTypes[] =
1602         {
1603                 glu::TYPE_FLOAT,
1604                 glu::TYPE_INT,
1605                 glu::TYPE_UINT
1606         };
1607
1608         for (int scalarTypeNdx = 0; scalarTypeNdx < DE_LENGTH_OF_ARRAY(scalarTypes); scalarTypeNdx++)
1609         {
1610                 const glu::DataType scalarType = scalarTypes[scalarTypeNdx];
1611
1612                 if ((!floatTypes && scalarType == glu::TYPE_FLOAT)      ||
1613                         (!intTypes && scalarType == glu::TYPE_INT)              ||
1614                         (!uintTypes && scalarType == glu::TYPE_UINT))
1615                         continue;
1616
1617                 for (int vecSize = 1; vecSize <= 4; vecSize++)
1618                 {
1619                         for (int prec = glu::PRECISION_LOWP; prec <= glu::PRECISION_HIGHP; prec++)
1620                         {
1621                                 for (int shaderType = glu::SHADERTYPE_VERTEX; shaderType <= glu::SHADERTYPE_FRAGMENT; shaderType++)
1622                                         group->addChild(new TestClass(parent->getContext(), glu::DataType(scalarType + vecSize - 1), glu::Precision(prec), glu::ShaderType(shaderType)));
1623                         }
1624                 }
1625         }
1626 }
1627
1628 void ShaderCommonFunctionTests::init (void)
1629 {
1630         //                                                                                                                                      Float?  Int?    Uint?
1631         addFunctionCases<AbsCase>                               (this,  "abs",                          true,   true,   false);
1632         addFunctionCases<SignCase>                              (this,  "sign",                         true,   true,   false);
1633         addFunctionCases<FloorCase>                             (this,  "floor",                        true,   false,  false);
1634         addFunctionCases<TruncCase>                             (this,  "trunc",                        true,   false,  false);
1635         addFunctionCases<RoundCase>                             (this,  "round",                        true,   false,  false);
1636         addFunctionCases<RoundEvenCase>                 (this,  "roundeven",            true,   false,  false);
1637         addFunctionCases<CeilCase>                              (this,  "ceil",                         true,   false,  false);
1638         addFunctionCases<FractCase>                             (this,  "fract",                        true,   false,  false);
1639         // mod
1640         addFunctionCases<ModfCase>                              (this,  "modf",                         true,   false,  false);
1641         // min
1642         // max
1643         // clamp
1644         // mix
1645         // step
1646         // smoothstep
1647         addFunctionCases<IsnanCase>                             (this,  "isnan",                        true,   false,  false);
1648         addFunctionCases<IsinfCase>                             (this,  "isinf",                        true,   false,  false);
1649         addFunctionCases<FloatBitsToIntCase>    (this,  "floatbitstoint",       true,   false,  false);
1650         addFunctionCases<FloatBitsToUintCase>   (this,  "floatbitstouint",      true,   false,  false);
1651
1652         // (u)intBitsToFloat()
1653         {
1654                 tcu::TestCaseGroup* intGroup    = new tcu::TestCaseGroup(m_testCtx, "intbitstofloat",   "intBitsToFloat() Tests");
1655                 tcu::TestCaseGroup* uintGroup   = new tcu::TestCaseGroup(m_testCtx, "uintbitstofloat",  "uintBitsToFloat() Tests");
1656
1657                 addChild(intGroup);
1658                 addChild(uintGroup);
1659
1660                 for (int vecSize = 1; vecSize < 4; vecSize++)
1661                 {
1662                         const glu::DataType             intType         = vecSize > 1 ? glu::getDataTypeIntVec(vecSize) : glu::TYPE_INT;
1663                         const glu::DataType             uintType        = vecSize > 1 ? glu::getDataTypeUintVec(vecSize) : glu::TYPE_UINT;
1664
1665                         for (int shaderType = glu::SHADERTYPE_VERTEX; shaderType <= glu::SHADERTYPE_FRAGMENT; shaderType++)
1666                         {
1667                                 intGroup->addChild(new BitsToFloatCase(m_context, intType, glu::ShaderType(shaderType)));
1668                                 uintGroup->addChild(new BitsToFloatCase(m_context, uintType, glu::ShaderType(shaderType)));
1669                         }
1670                 }
1671         }
1672 }
1673
1674 } // Functional
1675 } // gles3
1676 } // deqp