Fix PIPELINE_STAGE_TOP_OF_PIPE_BIT usage in api tests
[platform/upstream/VK-GL-CTS.git] / modules / gles31 / functional / es31fShaderPackingFunctionTests.cpp
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES 3.1 Module
3  * -------------------------------------------------
4  *
5  * Copyright 2014 The Android Open Source Project
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Floating-point packing and unpacking function tests.
22  *//*--------------------------------------------------------------------*/
23
24 #include "es31fShaderPackingFunctionTests.hpp"
25 #include "glsShaderExecUtil.hpp"
26 #include "tcuTestLog.hpp"
27 #include "tcuFormatUtil.hpp"
28 #include "tcuFloat.hpp"
29 #include "deRandom.hpp"
30 #include "deMath.h"
31 #include "deString.h"
32
33 namespace deqp
34 {
35 namespace gles31
36 {
37 namespace Functional
38 {
39
40 using std::string;
41 using tcu::TestLog;
42 using namespace gls::ShaderExecUtil;
43
44 namespace
45 {
46
47 inline deUint32 getUlpDiff (float a, float b)
48 {
49         const deUint32  aBits   = tcu::Float32(a).bits();
50         const deUint32  bBits   = tcu::Float32(b).bits();
51         return aBits > bBits ? aBits - bBits : bBits - aBits;
52 }
53
54 struct HexFloat
55 {
56         const float value;
57         HexFloat (const float value_) : value(value_) {}
58 };
59
60 std::ostream& operator<< (std::ostream& str, const HexFloat& v)
61 {
62         return str << v.value << " / " << tcu::toHex(tcu::Float32(v.value).bits());
63 }
64
65 } // anonymous
66
67 // ShaderPackingFunctionCase
68
69 class ShaderPackingFunctionCase : public TestCase
70 {
71 public:
72                                                                 ShaderPackingFunctionCase       (Context& context, const char* name, const char* description, glu::ShaderType shaderType);
73                                                                 ~ShaderPackingFunctionCase      (void);
74
75         void                                            init                                            (void);
76         void                                            deinit                                          (void);
77
78 protected:
79         glu::ShaderType                         m_shaderType;
80         ShaderSpec                                      m_spec;
81         ShaderExecutor*                         m_executor;
82
83 private:
84                                                                 ShaderPackingFunctionCase       (const ShaderPackingFunctionCase& other);
85         ShaderPackingFunctionCase&      operator=                                       (const ShaderPackingFunctionCase& other);
86 };
87
88 ShaderPackingFunctionCase::ShaderPackingFunctionCase (Context& context, const char* name, const char* description, glu::ShaderType shaderType)
89         : TestCase              (context, name, description)
90         , m_shaderType  (shaderType)
91         , m_executor    (DE_NULL)
92 {
93         m_spec.version = glu::getContextTypeGLSLVersion(context.getRenderContext().getType());
94 }
95
96 ShaderPackingFunctionCase::~ShaderPackingFunctionCase (void)
97 {
98         ShaderPackingFunctionCase::deinit();
99 }
100
101 void ShaderPackingFunctionCase::init (void)
102 {
103         DE_ASSERT(!m_executor);
104
105         m_executor = createExecutor(m_context.getRenderContext(), m_shaderType, m_spec);
106         m_testCtx.getLog() << m_executor;
107
108         if (!m_executor->isOk())
109                 throw tcu::TestError("Compile failed");
110 }
111
112 void ShaderPackingFunctionCase::deinit (void)
113 {
114         delete m_executor;
115         m_executor = DE_NULL;
116 }
117
118 // Test cases
119
120 static const char* getPrecisionPostfix (glu::Precision precision)
121 {
122         static const char* s_postfix[] =
123         {
124                 "_lowp",
125                 "_mediump",
126                 "_highp"
127         };
128         DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_postfix) == glu::PRECISION_LAST);
129         DE_ASSERT(de::inBounds<int>(precision, 0, DE_LENGTH_OF_ARRAY(s_postfix)));
130         return s_postfix[precision];
131 }
132
133 static const char* getShaderTypePostfix (glu::ShaderType shaderType)
134 {
135         static const char* s_postfix[] =
136         {
137                 "_vertex",
138                 "_fragment",
139                 "_geometry",
140                 "_tess_control",
141                 "_tess_eval",
142                 "_compute"
143         };
144         DE_ASSERT(de::inBounds<int>(shaderType, 0, DE_LENGTH_OF_ARRAY(s_postfix)));
145         return s_postfix[shaderType];
146 }
147
148 class PackSnorm2x16Case : public ShaderPackingFunctionCase
149 {
150 public:
151         PackSnorm2x16Case (Context& context, glu::ShaderType shaderType, glu::Precision precision)
152                 : ShaderPackingFunctionCase     (context, (string("packsnorm2x16") + getPrecisionPostfix(precision) + getShaderTypePostfix(shaderType)).c_str(), "packSnorm2x16", shaderType)
153                 , m_precision                           (precision)
154         {
155                 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_FLOAT_VEC2, precision)));
156                 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
157
158                 m_spec.source = "out0 = packSnorm2x16(in0);";
159         }
160
161         IterateResult iterate (void)
162         {
163                 de::Random                                      rnd                     (deStringHash(getName()) ^ 0x776002);
164                 std::vector<tcu::Vec2>          inputs;
165                 std::vector<deUint32>           outputs;
166                 const int                                       maxDiff         = m_precision == glu::PRECISION_HIGHP   ? 1             :               // Rounding only.
167                                                                                                   m_precision == glu::PRECISION_MEDIUMP ? 33    :               // (2^-10) * (2^15) + 1
168                                                                                                   m_precision == glu::PRECISION_LOWP    ? 129   : 0;    // (2^-8) * (2^15) + 1
169
170                 // Special values to check.
171                 inputs.push_back(tcu::Vec2(0.0f, 0.0f));
172                 inputs.push_back(tcu::Vec2(-1.0f, 1.0f));
173                 inputs.push_back(tcu::Vec2(0.5f, -0.5f));
174                 inputs.push_back(tcu::Vec2(-1.5f, 1.5f));
175                 inputs.push_back(tcu::Vec2(0.25f, -0.75f));
176
177                 // Random values, mostly in range.
178                 for (int ndx = 0; ndx < 15; ndx++)
179                 {
180                         const float x = rnd.getFloat()*2.5f - 1.25f;
181                         const float y = rnd.getFloat()*2.5f - 1.25f;
182                         inputs.push_back(tcu::Vec2(x, y));
183                 }
184
185                 // Large random values.
186                 for (int ndx = 0; ndx < 80; ndx++)
187                 {
188                         const float x = rnd.getFloat()*1e6f - 0.5e6f;
189                         const float y = rnd.getFloat()*1e6f - 0.5e6f;
190                         inputs.push_back(tcu::Vec2(x, y));
191                 }
192
193                 outputs.resize(inputs.size());
194
195                 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
196
197                 {
198                         const void*     in      = &inputs[0];
199                         void*           out     = &outputs[0];
200
201                         m_executor->useProgram();
202                         m_executor->execute((int)inputs.size(), &in, &out);
203                 }
204
205                 // Verify
206                 {
207                         const int       numValues       = (int)inputs.size();
208                         const int       maxPrints       = 10;
209                         int                     numFailed       = 0;
210
211                         for (int valNdx = 0; valNdx < numValues; valNdx++)
212                         {
213                                 const deUint16  ref0    = (deUint16)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].x(), -1.0f, 1.0f) * 32767.0f), -(1<<15), (1<<15)-1);
214                                 const deUint16  ref1    = (deUint16)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].y(), -1.0f, 1.0f) * 32767.0f), -(1<<15), (1<<15)-1);
215                                 const deUint32  ref             = (ref1 << 16) | ref0;
216                                 const deUint32  res             = outputs[valNdx];
217                                 const deUint16  res0    = (deUint16)(res & 0xffff);
218                                 const deUint16  res1    = (deUint16)(res >> 16);
219                                 const int               diff0   = de::abs((int)ref0 - (int)res0);
220                                 const int               diff1   = de::abs((int)ref1 - (int)res1);
221
222                                 if (diff0 > maxDiff || diff1 > maxDiff)
223                                 {
224                                         if (numFailed < maxPrints)
225                                         {
226                                                 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx
227                                                                                                                            << ", expected packSnorm2x16(" << inputs[valNdx] << ") = " << tcu::toHex(ref)
228                                                                                                                            << ", got " << tcu::toHex(res)
229                                                                                                                            << "\n  diffs = (" << diff0 << ", " << diff1 << "), max diff = " << maxDiff
230                                                                                    << TestLog::EndMessage;
231                                         }
232                                         else if (numFailed == maxPrints)
233                                                 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
234
235                                         numFailed += 1;
236                                 }
237                         }
238
239                         m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
240
241                         m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS    : QP_TEST_RESULT_FAIL,
242                                                                         numFailed == 0 ? "Pass"                                 : "Result comparison failed");
243                 }
244
245                 return STOP;
246         }
247
248 private:
249         glu::Precision m_precision;
250 };
251
252 class UnpackSnorm2x16Case : public ShaderPackingFunctionCase
253 {
254 public:
255         UnpackSnorm2x16Case (Context& context, glu::ShaderType shaderType)
256                 : ShaderPackingFunctionCase(context, (string("unpacksnorm2x16") + getShaderTypePostfix(shaderType)).c_str(), "unpackSnorm2x16", shaderType)
257         {
258                 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
259                 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_FLOAT_VEC2, glu::PRECISION_HIGHP)));
260
261                 m_spec.source = "out0 = unpackSnorm2x16(in0);";
262         }
263
264         IterateResult iterate (void)
265         {
266                 const deUint32                          maxDiff         = 1; // Rounding error.
267                 de::Random                                      rnd                     (deStringHash(getName()) ^ 0x776002);
268                 std::vector<deUint32>           inputs;
269                 std::vector<tcu::Vec2>          outputs;
270
271                 inputs.push_back(0x00000000u);
272                 inputs.push_back(0x7fff8000u);
273                 inputs.push_back(0x80007fffu);
274                 inputs.push_back(0xffffffffu);
275                 inputs.push_back(0x0001fffeu);
276
277                 // Random values.
278                 for (int ndx = 0; ndx < 95; ndx++)
279                         inputs.push_back(rnd.getUint32());
280
281                 outputs.resize(inputs.size());
282
283                 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
284
285                 {
286                         const void*     in      = &inputs[0];
287                         void*           out     = &outputs[0];
288
289                         m_executor->useProgram();
290                         m_executor->execute((int)inputs.size(), &in, &out);
291                 }
292
293                 // Verify
294                 {
295                         const int       numValues       = (int)inputs.size();
296                         const int       maxPrints       = 10;
297                         int                     numFailed       = 0;
298
299                         for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
300                         {
301                                 const deInt16   in0                     = (deInt16)(deUint16)(inputs[valNdx] & 0xffff);
302                                 const deInt16   in1                     = (deInt16)(deUint16)(inputs[valNdx] >> 16);
303                                 const float             ref0            = de::clamp(float(in0) / 32767.f, -1.0f, 1.0f);
304                                 const float             ref1            = de::clamp(float(in1) / 32767.f, -1.0f, 1.0f);
305                                 const float             res0            = outputs[valNdx].x();
306                                 const float             res1            = outputs[valNdx].y();
307
308                                 const deUint32  diff0   = getUlpDiff(ref0, res0);
309                                 const deUint32  diff1   = getUlpDiff(ref1, res1);
310
311                                 if (diff0 > maxDiff || diff1 > maxDiff)
312                                 {
313                                         if (numFailed < maxPrints)
314                                         {
315                                                 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx << ",\n"
316                                                                                                                            << "  expected unpackSnorm2x16(" << tcu::toHex(inputs[valNdx]) << ") = "
317                                                                                                                            << "vec2(" << HexFloat(ref0) << ", " << HexFloat(ref1) << ")"
318                                                                                                                            << ", got vec2(" << HexFloat(res0) << ", " << HexFloat(res1) << ")"
319                                                                                                                            << "\n  ULP diffs = (" << diff0 << ", " << diff1 << "), max diff = " << maxDiff
320                                                                                    << TestLog::EndMessage;
321                                         }
322                                         else if (numFailed == maxPrints)
323                                                 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
324
325                                         numFailed += 1;
326                                 }
327                         }
328
329                         m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
330
331                         m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS    : QP_TEST_RESULT_FAIL,
332                                                                         numFailed == 0 ? "Pass"                                 : "Result comparison failed");
333                 }
334
335                 return STOP;
336         }
337 };
338
339 class PackUnorm2x16Case : public ShaderPackingFunctionCase
340 {
341 public:
342         PackUnorm2x16Case (Context& context, glu::ShaderType shaderType, glu::Precision precision)
343                 : ShaderPackingFunctionCase     (context, (string("packunorm2x16") + getPrecisionPostfix(precision) + getShaderTypePostfix(shaderType)).c_str(), "packUnorm2x16", shaderType)
344                 , m_precision                           (precision)
345         {
346                 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_FLOAT_VEC2, precision)));
347                 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
348
349                 m_spec.source = "out0 = packUnorm2x16(in0);";
350         }
351
352         IterateResult iterate (void)
353         {
354                 de::Random                                      rnd                     (deStringHash(getName()) ^ 0x776002);
355                 std::vector<tcu::Vec2>          inputs;
356                 std::vector<deUint32>           outputs;
357                 const int                                       maxDiff         = m_precision == glu::PRECISION_HIGHP   ? 1             :               // Rounding only.
358                                                                                                   m_precision == glu::PRECISION_MEDIUMP ? 65    :               // (2^-10) * (2^16) + 1
359                                                                                                   m_precision == glu::PRECISION_LOWP    ? 257   : 0;    // (2^-8) * (2^16) + 1
360
361                 // Special values to check.
362                 inputs.push_back(tcu::Vec2(0.0f, 0.0f));
363                 inputs.push_back(tcu::Vec2(0.5f, 1.0f));
364                 inputs.push_back(tcu::Vec2(1.0f, 0.5f));
365                 inputs.push_back(tcu::Vec2(-0.5f, 1.5f));
366                 inputs.push_back(tcu::Vec2(0.25f, 0.75f));
367
368                 // Random values, mostly in range.
369                 for (int ndx = 0; ndx < 15; ndx++)
370                 {
371                         const float x = rnd.getFloat()*1.25f;
372                         const float y = rnd.getFloat()*1.25f;
373                         inputs.push_back(tcu::Vec2(x, y));
374                 }
375
376                 // Large random values.
377                 for (int ndx = 0; ndx < 80; ndx++)
378                 {
379                         const float x = rnd.getFloat()*1e6f - 1e5f;
380                         const float y = rnd.getFloat()*1e6f - 1e5f;
381                         inputs.push_back(tcu::Vec2(x, y));
382                 }
383
384                 outputs.resize(inputs.size());
385
386                 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
387
388                 {
389                         const void*     in      = &inputs[0];
390                         void*           out     = &outputs[0];
391
392                         m_executor->useProgram();
393                         m_executor->execute((int)inputs.size(), &in, &out);
394                 }
395
396                 // Verify
397                 {
398                         const int       numValues       = (int)inputs.size();
399                         const int       maxPrints       = 10;
400                         int                     numFailed       = 0;
401
402                         for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
403                         {
404                                 const deUint16  ref0    = (deUint16)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].x(), 0.0f, 1.0f) * 65535.0f), 0, (1<<16)-1);
405                                 const deUint16  ref1    = (deUint16)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].y(), 0.0f, 1.0f) * 65535.0f), 0, (1<<16)-1);
406                                 const deUint32  ref             = (ref1 << 16) | ref0;
407                                 const deUint32  res             = outputs[valNdx];
408                                 const deUint16  res0    = (deUint16)(res & 0xffff);
409                                 const deUint16  res1    = (deUint16)(res >> 16);
410                                 const int               diff0   = de::abs((int)ref0 - (int)res0);
411                                 const int               diff1   = de::abs((int)ref1 - (int)res1);
412
413                                 if (diff0 > maxDiff || diff1 > maxDiff)
414                                 {
415                                         if (numFailed < maxPrints)
416                                         {
417                                                 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx
418                                                                                                                            << ", expected packUnorm2x16(" << inputs[valNdx] << ") = " << tcu::toHex(ref)
419                                                                                                                            << ", got " << tcu::toHex(res)
420                                                                                                                            << "\n  diffs = (" << diff0 << ", " << diff1 << "), max diff = " << maxDiff
421                                                                                    << TestLog::EndMessage;
422                                         }
423                                         else if (numFailed == maxPrints)
424                                                 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
425
426                                         numFailed += 1;
427                                 }
428                         }
429
430                         m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
431
432                         m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS    : QP_TEST_RESULT_FAIL,
433                                                                         numFailed == 0 ? "Pass"                                 : "Result comparison failed");
434                 }
435
436                 return STOP;
437         }
438
439 private:
440         glu::Precision m_precision;
441 };
442
443 class UnpackUnorm2x16Case : public ShaderPackingFunctionCase
444 {
445 public:
446         UnpackUnorm2x16Case (Context& context, glu::ShaderType shaderType)
447                 : ShaderPackingFunctionCase(context, (string("unpackunorm2x16") + getShaderTypePostfix(shaderType)).c_str(), "unpackUnorm2x16", shaderType)
448         {
449                 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
450                 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_FLOAT_VEC2, glu::PRECISION_HIGHP)));
451
452                 m_spec.source = "out0 = unpackUnorm2x16(in0);";
453         }
454
455         IterateResult iterate (void)
456         {
457                 const deUint32                          maxDiff         = 1; // Rounding error.
458                 de::Random                                      rnd                     (deStringHash(getName()) ^ 0x776002);
459                 std::vector<deUint32>           inputs;
460                 std::vector<tcu::Vec2>          outputs;
461
462                 inputs.push_back(0x00000000u);
463                 inputs.push_back(0x7fff8000u);
464                 inputs.push_back(0x80007fffu);
465                 inputs.push_back(0xffffffffu);
466                 inputs.push_back(0x0001fffeu);
467
468                 // Random values.
469                 for (int ndx = 0; ndx < 95; ndx++)
470                         inputs.push_back(rnd.getUint32());
471
472                 outputs.resize(inputs.size());
473
474                 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
475
476                 {
477                         const void*     in      = &inputs[0];
478                         void*           out     = &outputs[0];
479
480                         m_executor->useProgram();
481                         m_executor->execute((int)inputs.size(), &in, &out);
482                 }
483
484                 // Verify
485                 {
486                         const int       numValues       = (int)inputs.size();
487                         const int       maxPrints       = 10;
488                         int                     numFailed       = 0;
489
490                         for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
491                         {
492                                 const deUint16  in0                     = (deUint16)(inputs[valNdx] & 0xffff);
493                                 const deUint16  in1                     = (deUint16)(inputs[valNdx] >> 16);
494                                 const float             ref0            = float(in0) / 65535.0f;
495                                 const float             ref1            = float(in1) / 65535.0f;
496                                 const float             res0            = outputs[valNdx].x();
497                                 const float             res1            = outputs[valNdx].y();
498
499                                 const deUint32  diff0           = getUlpDiff(ref0, res0);
500                                 const deUint32  diff1           = getUlpDiff(ref1, res1);
501
502                                 if (diff0 > maxDiff || diff1 > maxDiff)
503                                 {
504                                         if (numFailed < maxPrints)
505                                         {
506                                                 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx << ",\n"
507                                                                                                                            << "  expected unpackUnorm2x16(" << tcu::toHex(inputs[valNdx]) << ") = "
508                                                                                                                            << "vec2(" << HexFloat(ref0) << ", " << HexFloat(ref1) << ")"
509                                                                                                                            << ", got vec2(" << HexFloat(res0) << ", " << HexFloat(res1) << ")"
510                                                                                                                            << "\n  ULP diffs = (" << diff0 << ", " << diff1 << "), max diff = " << maxDiff
511                                                                                    << TestLog::EndMessage;
512                                         }
513                                         else if (numFailed == maxPrints)
514                                                 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
515
516                                         numFailed += 1;
517                                 }
518                         }
519
520                         m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
521
522                         m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS    : QP_TEST_RESULT_FAIL,
523                                                                         numFailed == 0 ? "Pass"                                 : "Result comparison failed");
524                 }
525
526                 return STOP;
527         }
528 };
529
530 class PackHalf2x16Case : public ShaderPackingFunctionCase
531 {
532 public:
533         PackHalf2x16Case (Context& context, glu::ShaderType shaderType)
534                 : ShaderPackingFunctionCase(context, (string("packhalf2x16") + getShaderTypePostfix(shaderType)).c_str(), "packHalf2x16", shaderType)
535         {
536                 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_FLOAT_VEC2, glu::PRECISION_HIGHP)));
537                 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
538
539                 m_spec.source = "out0 = packHalf2x16(in0);";
540         }
541
542         IterateResult iterate (void)
543         {
544                 const int                                       maxDiff         = 0; // Values can be represented exactly in mediump.
545                 de::Random                                      rnd                     (deStringHash(getName()) ^ 0x776002);
546                 std::vector<tcu::Vec2>          inputs;
547                 std::vector<deUint32>           outputs;
548
549                 // Special values to check.
550                 inputs.push_back(tcu::Vec2(0.0f, 0.0f));
551                 inputs.push_back(tcu::Vec2(0.5f, 1.0f));
552                 inputs.push_back(tcu::Vec2(1.0f, 0.5f));
553                 inputs.push_back(tcu::Vec2(-0.5f, 1.5f));
554                 inputs.push_back(tcu::Vec2(0.25f, 0.75f));
555
556                 // Random values.
557                 {
558                         const int       minExp  = -14;
559                         const int       maxExp  = 15;
560
561                         for (int ndx = 0; ndx < 95; ndx++)
562                         {
563                                 tcu::Vec2 v;
564                                 for (int c = 0; c < 2; c++)
565                                 {
566                                         const int               s                       = rnd.getBool() ? 1 : -1;
567                                         const int               exp                     = rnd.getInt(minExp, maxExp);
568                                         const deUint32  mantissa        = rnd.getUint32() & ((1<<23)-1);
569
570                                         v[c] = tcu::Float32::construct(s, exp ? exp : 1 /* avoid denormals */, (1u<<23) | mantissa).asFloat();
571                                 }
572                                 inputs.push_back(v);
573                         }
574                 }
575
576                 // Convert input values to fp16 and back to make sure they can be represented exactly in mediump.
577                 for (std::vector<tcu::Vec2>::iterator inVal = inputs.begin(); inVal != inputs.end(); ++inVal)
578                         *inVal = tcu::Vec2(tcu::Float16(inVal->x()).asFloat(), tcu::Float16(inVal->y()).asFloat());
579
580                 outputs.resize(inputs.size());
581
582                 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
583
584                 {
585                         const void*     in      = &inputs[0];
586                         void*           out     = &outputs[0];
587
588                         m_executor->useProgram();
589                         m_executor->execute((int)inputs.size(), &in, &out);
590                 }
591
592                 // Verify
593                 {
594                         const int       numValues       = (int)inputs.size();
595                         const int       maxPrints       = 10;
596                         int                     numFailed       = 0;
597
598                         for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
599                         {
600                                 const deUint16  ref0    = (deUint16)tcu::Float16(inputs[valNdx].x()).bits();
601                                 const deUint16  ref1    = (deUint16)tcu::Float16(inputs[valNdx].y()).bits();
602                                 const deUint32  ref             = (ref1 << 16) | ref0;
603                                 const deUint32  res             = outputs[valNdx];
604                                 const deUint16  res0    = (deUint16)(res & 0xffff);
605                                 const deUint16  res1    = (deUint16)(res >> 16);
606                                 const int               diff0   = de::abs((int)ref0 - (int)res0);
607                                 const int               diff1   = de::abs((int)ref1 - (int)res1);
608
609                                 if (diff0 > maxDiff || diff1 > maxDiff)
610                                 {
611                                         if (numFailed < maxPrints)
612                                         {
613                                                 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx
614                                                                                                                            << ", expected packHalf2x16(" << inputs[valNdx] << ") = " << tcu::toHex(ref)
615                                                                                                                            << ", got " << tcu::toHex(res)
616                                                                                                                            << "\n  diffs = (" << diff0 << ", " << diff1 << "), max diff = " << maxDiff
617                                                                                    << TestLog::EndMessage;
618                                         }
619                                         else if (numFailed == maxPrints)
620                                                 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
621
622                                         numFailed += 1;
623                                 }
624                         }
625
626                         m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
627
628                         m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS    : QP_TEST_RESULT_FAIL,
629                                                                         numFailed == 0 ? "Pass"                                 : "Result comparison failed");
630                 }
631
632                 return STOP;
633         }
634 };
635
636 class UnpackHalf2x16Case : public ShaderPackingFunctionCase
637 {
638 public:
639         UnpackHalf2x16Case (Context& context, glu::ShaderType shaderType)
640                 : ShaderPackingFunctionCase(context, (string("unpackhalf2x16") + getShaderTypePostfix(shaderType)).c_str(), "unpackHalf2x16", shaderType)
641         {
642                 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
643                 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_FLOAT_VEC2, glu::PRECISION_MEDIUMP)));
644
645                 m_spec.source = "out0 = unpackHalf2x16(in0);";
646         }
647
648         IterateResult iterate (void)
649         {
650                 const int                                       maxDiff         = 0; // All bits must be accurate.
651                 de::Random                                      rnd                     (deStringHash(getName()) ^ 0x776002);
652                 std::vector<deUint32>           inputs;
653                 std::vector<tcu::Vec2>          outputs;
654
655                 // Special values.
656                 inputs.push_back((tcu::Float16( 0.0f).bits() << 16) | tcu::Float16( 1.0f).bits());
657                 inputs.push_back((tcu::Float16( 1.0f).bits() << 16) | tcu::Float16( 0.0f).bits());
658                 inputs.push_back((tcu::Float16(-1.0f).bits() << 16) | tcu::Float16( 0.5f).bits());
659                 inputs.push_back((tcu::Float16( 0.5f).bits() << 16) | tcu::Float16(-0.5f).bits());
660
661                 // Construct random values.
662                 {
663                         const int       minExp          = -14;
664                         const int       maxExp          = 15;
665                         const int       mantBits        = 10;
666
667                         for (int ndx = 0; ndx < 96; ndx++)
668                         {
669                                 deUint32 inVal = 0;
670                                 for (int c = 0; c < 2; c++)
671                                 {
672                                         const int               s                       = rnd.getBool() ? 1 : -1;
673                                         const int               exp                     = rnd.getInt(minExp, maxExp);
674                                         const deUint32  mantissa        = rnd.getUint32() & ((1<<mantBits)-1);
675                                         const deUint16  value           = tcu::Float16::construct(s, exp ? exp : 1 /* avoid denorm */, (deUint16)((1u<<10) | mantissa)).bits();
676
677                                         inVal |= value << (16*c);
678                                 }
679                                 inputs.push_back(inVal);
680                         }
681                 }
682
683                 outputs.resize(inputs.size());
684
685                 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
686
687                 {
688                         const void*     in      = &inputs[0];
689                         void*           out     = &outputs[0];
690
691                         m_executor->useProgram();
692                         m_executor->execute((int)inputs.size(), &in, &out);
693                 }
694
695                 // Verify
696                 {
697                         const int       numValues       = (int)inputs.size();
698                         const int       maxPrints       = 10;
699                         int                     numFailed       = 0;
700
701                         for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
702                         {
703                                 const deUint16  in0                     = (deUint16)(inputs[valNdx] & 0xffff);
704                                 const deUint16  in1                     = (deUint16)(inputs[valNdx] >> 16);
705                                 const float             ref0            = tcu::Float16(in0).asFloat();
706                                 const float             ref1            = tcu::Float16(in1).asFloat();
707                                 const float             res0            = outputs[valNdx].x();
708                                 const float             res1            = outputs[valNdx].y();
709
710                                 const deUint32  refBits0        = tcu::Float32(ref0).bits();
711                                 const deUint32  refBits1        = tcu::Float32(ref1).bits();
712                                 const deUint32  resBits0        = tcu::Float32(res0).bits();
713                                 const deUint32  resBits1        = tcu::Float32(res1).bits();
714
715                                 const int               diff0   = de::abs((int)refBits0 - (int)resBits0);
716                                 const int               diff1   = de::abs((int)refBits1 - (int)resBits1);
717
718                                 if (diff0 > maxDiff || diff1 > maxDiff)
719                                 {
720                                         if (numFailed < maxPrints)
721                                         {
722                                                 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx << ",\n"
723                                                                                                                            << "  expected unpackHalf2x16(" << tcu::toHex(inputs[valNdx]) << ") = "
724                                                                                                                            << "vec2(" << ref0 << " / " << tcu::toHex(refBits0) << ", " << ref1 << " / " << tcu::toHex(refBits1) << ")"
725                                                                                                                            << ", got vec2(" << res0 << " / " << tcu::toHex(resBits0) << ", " << res1 << " / " << tcu::toHex(resBits1) << ")"
726                                                                                                                            << "\n  ULP diffs = (" << diff0 << ", " << diff1 << "), max diff = " << maxDiff
727                                                                                    << TestLog::EndMessage;
728                                         }
729                                         else if (numFailed == maxPrints)
730                                                 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
731
732                                         numFailed += 1;
733                                 }
734                         }
735
736                         m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
737
738                         m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS    : QP_TEST_RESULT_FAIL,
739                                                                         numFailed == 0 ? "Pass"                                 : "Result comparison failed");
740                 }
741
742                 return STOP;
743         }
744 };
745
746 class PackSnorm4x8Case : public ShaderPackingFunctionCase
747 {
748 public:
749         PackSnorm4x8Case (Context& context, glu::ShaderType shaderType, glu::Precision precision)
750                 : ShaderPackingFunctionCase     (context, (string("packsnorm4x8") + getPrecisionPostfix(precision) + getShaderTypePostfix(shaderType)).c_str(), "packSnorm4x8", shaderType)
751                 , m_precision                           (precision)
752         {
753                 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_FLOAT_VEC4, precision)));
754                 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
755
756                 m_spec.source = "out0 = packSnorm4x8(in0);";
757         }
758
759         IterateResult iterate (void)
760         {
761                 de::Random                                      rnd                     (deStringHash(getName()) ^ 0x42f2c0);
762                 std::vector<tcu::Vec4>          inputs;
763                 std::vector<deUint32>           outputs;
764                 const int                                       maxDiff         = m_precision == glu::PRECISION_HIGHP   ? 1     :               // Rounding only.
765                                                                                                   m_precision == glu::PRECISION_MEDIUMP ? 1     :               // (2^-10) * (2^7) + 1
766                                                                                                   m_precision == glu::PRECISION_LOWP    ? 2     : 0;    // (2^-8) * (2^7) + 1
767
768                 // Special values to check.
769                 inputs.push_back(tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f));
770                 inputs.push_back(tcu::Vec4(-1.0f, 1.0f, -1.0f, 1.0f));
771                 inputs.push_back(tcu::Vec4(0.5f, -0.5f, -0.5f, 0.5f));
772                 inputs.push_back(tcu::Vec4(-1.5f, 1.5f, -1.5f, 1.5f));
773                 inputs.push_back(tcu::Vec4(0.25f, -0.75f, -0.25f, 0.75f));
774
775                 // Random values, mostly in range.
776                 for (int ndx = 0; ndx < 15; ndx++)
777                 {
778                         const float x = rnd.getFloat()*2.5f - 1.25f;
779                         const float y = rnd.getFloat()*2.5f - 1.25f;
780                         const float z = rnd.getFloat()*2.5f - 1.25f;
781                         const float w = rnd.getFloat()*2.5f - 1.25f;
782                         inputs.push_back(tcu::Vec4(x, y, z, w));
783                 }
784
785                 // Large random values.
786                 for (int ndx = 0; ndx < 80; ndx++)
787                 {
788                         const float x = rnd.getFloat()*1e6f - 0.5e6f;
789                         const float y = rnd.getFloat()*1e6f - 0.5e6f;
790                         const float z = rnd.getFloat()*1e6f - 0.5e6f;
791                         const float w = rnd.getFloat()*1e6f - 0.5e6f;
792                         inputs.push_back(tcu::Vec4(x, y, z, w));
793                 }
794
795                 outputs.resize(inputs.size());
796
797                 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
798
799                 {
800                         const void*     in      = &inputs[0];
801                         void*           out     = &outputs[0];
802
803                         m_executor->useProgram();
804                         m_executor->execute((int)inputs.size(), &in, &out);
805                 }
806
807                 // Verify
808                 {
809                         const int       numValues       = (int)inputs.size();
810                         const int       maxPrints       = 10;
811                         int                     numFailed       = 0;
812
813                         for (int valNdx = 0; valNdx < numValues; valNdx++)
814                         {
815                                 const deUint16  ref0    = (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].x(), -1.0f, 1.0f) * 127.0f), -(1<<7), (1<<7)-1);
816                                 const deUint16  ref1    = (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].y(), -1.0f, 1.0f) * 127.0f), -(1<<7), (1<<7)-1);
817                                 const deUint16  ref2    = (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].z(), -1.0f, 1.0f) * 127.0f), -(1<<7), (1<<7)-1);
818                                 const deUint16  ref3    = (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].w(), -1.0f, 1.0f) * 127.0f), -(1<<7), (1<<7)-1);
819                                 const deUint32  ref             = (deUint32(ref3) << 24) | (deUint32(ref2) << 16) | (deUint32(ref1) << 8) | deUint32(ref0);
820                                 const deUint32  res             = outputs[valNdx];
821                                 const deUint16  res0    = (deUint8)(res & 0xff);
822                                 const deUint16  res1    = (deUint8)((res >> 8) & 0xff);
823                                 const deUint16  res2    = (deUint8)((res >> 16) & 0xff);
824                                 const deUint16  res3    = (deUint8)((res >> 24) & 0xff);
825                                 const int               diff0   = de::abs((int)ref0 - (int)res0);
826                                 const int               diff1   = de::abs((int)ref1 - (int)res1);
827                                 const int               diff2   = de::abs((int)ref2 - (int)res2);
828                                 const int               diff3   = de::abs((int)ref3 - (int)res3);
829
830                                 if (diff0 > maxDiff || diff1 > maxDiff || diff2 > maxDiff || diff3 > maxDiff)
831                                 {
832                                         if (numFailed < maxPrints)
833                                         {
834                                                 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx
835                                                                                                                            << ", expected packSnorm4x8(" << inputs[valNdx] << ") = " << tcu::toHex(ref)
836                                                                                                                            << ", got " << tcu::toHex(res)
837                                                                                                                            << "\n  diffs = " << tcu::IVec4(diff0, diff1, diff2, diff3) << ", max diff = " << maxDiff
838                                                                                    << TestLog::EndMessage;
839                                         }
840                                         else if (numFailed == maxPrints)
841                                                 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
842
843                                         numFailed += 1;
844                                 }
845                         }
846
847                         m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
848
849                         m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS    : QP_TEST_RESULT_FAIL,
850                                                                         numFailed == 0 ? "Pass"                                 : "Result comparison failed");
851                 }
852
853                 return STOP;
854         }
855
856 private:
857         glu::Precision m_precision;
858 };
859
860 class UnpackSnorm4x8Case : public ShaderPackingFunctionCase
861 {
862 public:
863         UnpackSnorm4x8Case (Context& context, glu::ShaderType shaderType)
864                 : ShaderPackingFunctionCase(context, (string("unpacksnorm4x8") + getShaderTypePostfix(shaderType)).c_str(), "unpackSnorm4x8", shaderType)
865         {
866                 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
867                 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP)));
868
869                 m_spec.source = "out0 = unpackSnorm4x8(in0);";
870         }
871
872         IterateResult iterate (void)
873         {
874                 const deUint32                          maxDiff         = 1; // Rounding error.
875                 de::Random                                      rnd                     (deStringHash(getName()) ^ 0x776002);
876                 std::vector<deUint32>           inputs;
877                 std::vector<tcu::Vec4>          outputs;
878
879                 inputs.push_back(0x00000000u);
880                 inputs.push_back(0x7fff8000u);
881                 inputs.push_back(0x80007fffu);
882                 inputs.push_back(0xffffffffu);
883                 inputs.push_back(0x0001fffeu);
884
885                 // Random values.
886                 for (int ndx = 0; ndx < 95; ndx++)
887                         inputs.push_back(rnd.getUint32());
888
889                 outputs.resize(inputs.size());
890
891                 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
892
893                 {
894                         const void*     in      = &inputs[0];
895                         void*           out     = &outputs[0];
896
897                         m_executor->useProgram();
898                         m_executor->execute((int)inputs.size(), &in, &out);
899                 }
900
901                 // Verify
902                 {
903                         const int       numValues       = (int)inputs.size();
904                         const int       maxPrints       = 10;
905                         int                     numFailed       = 0;
906
907                         for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
908                         {
909                                 const deInt8    in0             = (deInt8)(deUint8)(inputs[valNdx] & 0xff);
910                                 const deInt8    in1             = (deInt8)(deUint8)((inputs[valNdx] >> 8) & 0xff);
911                                 const deInt8    in2             = (deInt8)(deUint8)((inputs[valNdx] >> 16) & 0xff);
912                                 const deInt8    in3             = (deInt8)(deUint8)(inputs[valNdx] >> 24);
913                                 const float             ref0    = de::clamp(float(in0) / 127.f, -1.0f, 1.0f);
914                                 const float             ref1    = de::clamp(float(in1) / 127.f, -1.0f, 1.0f);
915                                 const float             ref2    = de::clamp(float(in2) / 127.f, -1.0f, 1.0f);
916                                 const float             ref3    = de::clamp(float(in3) / 127.f, -1.0f, 1.0f);
917                                 const float             res0    = outputs[valNdx].x();
918                                 const float             res1    = outputs[valNdx].y();
919                                 const float             res2    = outputs[valNdx].z();
920                                 const float             res3    = outputs[valNdx].w();
921
922                                 const deUint32  diff0   = getUlpDiff(ref0, res0);
923                                 const deUint32  diff1   = getUlpDiff(ref1, res1);
924                                 const deUint32  diff2   = getUlpDiff(ref2, res2);
925                                 const deUint32  diff3   = getUlpDiff(ref3, res3);
926
927                                 if (diff0 > maxDiff || diff1 > maxDiff || diff2 > maxDiff || diff3 > maxDiff)
928                                 {
929                                         if (numFailed < maxPrints)
930                                         {
931                                                 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx << ",\n"
932                                                                                                                            << "  expected unpackSnorm4x8(" << tcu::toHex(inputs[valNdx]) << ") = "
933                                                                                                                            << "vec4(" << HexFloat(ref0) << ", " << HexFloat(ref1) << ", " << HexFloat(ref2) << ", " << HexFloat(ref3) << ")"
934                                                                                                                            << ", got vec4(" << HexFloat(res0) << ", " << HexFloat(res1) << ", " << HexFloat(res2) << ", " << HexFloat(res3) << ")"
935                                                                                                                            << "\n  ULP diffs = (" << diff0 << ", " << diff1 << ", " << diff2 << ", " << diff3 << "), max diff = " << maxDiff
936                                                                                    << TestLog::EndMessage;
937                                         }
938                                         else if (numFailed == maxPrints)
939                                                 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
940
941                                         numFailed += 1;
942                                 }
943                         }
944
945                         m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
946
947                         m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS    : QP_TEST_RESULT_FAIL,
948                                                                         numFailed == 0 ? "Pass"                                 : "Result comparison failed");
949                 }
950
951                 return STOP;
952         }
953 };
954
955 class PackUnorm4x8Case : public ShaderPackingFunctionCase
956 {
957 public:
958         PackUnorm4x8Case (Context& context, glu::ShaderType shaderType, glu::Precision precision)
959                 : ShaderPackingFunctionCase     (context, (string("packunorm4x8") + getPrecisionPostfix(precision) + getShaderTypePostfix(shaderType)).c_str(), "packUnorm4x8", shaderType)
960                 , m_precision                           (precision)
961         {
962                 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_FLOAT_VEC4, precision)));
963                 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
964
965                 m_spec.source = "out0 = packUnorm4x8(in0);";
966         }
967
968         IterateResult iterate (void)
969         {
970                 de::Random                                      rnd                     (deStringHash(getName()) ^ 0x776002);
971                 std::vector<tcu::Vec4>          inputs;
972                 std::vector<deUint32>           outputs;
973                 const int                                       maxDiff         = m_precision == glu::PRECISION_HIGHP   ? 1     :               // Rounding only.
974                                                                                                   m_precision == glu::PRECISION_MEDIUMP ? 1     :               // (2^-10) * (2^8) + 1
975                                                                                                   m_precision == glu::PRECISION_LOWP    ? 2     : 0;    // (2^-8) * (2^8) + 1
976
977                 // Special values to check.
978                 inputs.push_back(tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f));
979                 inputs.push_back(tcu::Vec4(-1.0f, 1.0f, -1.0f, 1.0f));
980                 inputs.push_back(tcu::Vec4(0.5f, -0.5f, -0.5f, 0.5f));
981                 inputs.push_back(tcu::Vec4(-1.5f, 1.5f, -1.5f, 1.5f));
982                 inputs.push_back(tcu::Vec4(0.25f, -0.75f, -0.25f, 0.75f));
983
984                 // Random values, mostly in range.
985                 for (int ndx = 0; ndx < 15; ndx++)
986                 {
987                         const float x = rnd.getFloat()*1.25f - 0.125f;
988                         const float y = rnd.getFloat()*1.25f - 0.125f;
989                         const float z = rnd.getFloat()*1.25f - 0.125f;
990                         const float w = rnd.getFloat()*1.25f - 0.125f;
991                         inputs.push_back(tcu::Vec4(x, y, z, w));
992                 }
993
994                 // Large random values.
995                 for (int ndx = 0; ndx < 80; ndx++)
996                 {
997                         const float x = rnd.getFloat()*1e6f - 1e5f;
998                         const float y = rnd.getFloat()*1e6f - 1e5f;
999                         const float z = rnd.getFloat()*1e6f - 1e5f;
1000                         const float w = rnd.getFloat()*1e6f - 1e5f;
1001                         inputs.push_back(tcu::Vec4(x, y, z, w));
1002                 }
1003
1004                 outputs.resize(inputs.size());
1005
1006                 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
1007
1008                 {
1009                         const void*     in      = &inputs[0];
1010                         void*           out     = &outputs[0];
1011
1012                         m_executor->useProgram();
1013                         m_executor->execute((int)inputs.size(), &in, &out);
1014                 }
1015
1016                 // Verify
1017                 {
1018                         const int       numValues       = (int)inputs.size();
1019                         const int       maxPrints       = 10;
1020                         int                     numFailed       = 0;
1021
1022                         for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
1023                         {
1024                                 const deUint16  ref0    = (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].x(), 0.0f, 1.0f) * 255.0f), 0, (1<<8)-1);
1025                                 const deUint16  ref1    = (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].y(), 0.0f, 1.0f) * 255.0f), 0, (1<<8)-1);
1026                                 const deUint16  ref2    = (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].z(), 0.0f, 1.0f) * 255.0f), 0, (1<<8)-1);
1027                                 const deUint16  ref3    = (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].w(), 0.0f, 1.0f) * 255.0f), 0, (1<<8)-1);
1028                                 const deUint32  ref             = (deUint32(ref3) << 24) | (deUint32(ref2) << 16) | (deUint32(ref1) << 8) | deUint32(ref0);
1029                                 const deUint32  res             = outputs[valNdx];
1030                                 const deUint16  res0    = (deUint8)(res & 0xff);
1031                                 const deUint16  res1    = (deUint8)((res >> 8) & 0xff);
1032                                 const deUint16  res2    = (deUint8)((res >> 16) & 0xff);
1033                                 const deUint16  res3    = (deUint8)((res >> 24) & 0xff);
1034                                 const int               diff0   = de::abs((int)ref0 - (int)res0);
1035                                 const int               diff1   = de::abs((int)ref1 - (int)res1);
1036                                 const int               diff2   = de::abs((int)ref2 - (int)res2);
1037                                 const int               diff3   = de::abs((int)ref3 - (int)res3);
1038
1039                                 if (diff0 > maxDiff || diff1 > maxDiff || diff2 > maxDiff || diff3 > maxDiff)
1040                                 {
1041                                         if (numFailed < maxPrints)
1042                                         {
1043                                                 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx
1044                                                                                                                            << ", expected packUnorm4x8(" << inputs[valNdx] << ") = " << tcu::toHex(ref)
1045                                                                                                                            << ", got " << tcu::toHex(res)
1046                                                                                                                            << "\n  diffs = " << tcu::IVec4(diff0, diff1, diff2, diff3) << ", max diff = " << maxDiff
1047                                                                                    << TestLog::EndMessage;
1048                                         }
1049                                         else if (numFailed == maxPrints)
1050                                                 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
1051
1052                                         numFailed += 1;
1053                                 }
1054                         }
1055
1056                         m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
1057
1058                         m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS    : QP_TEST_RESULT_FAIL,
1059                                                                         numFailed == 0 ? "Pass"                                 : "Result comparison failed");
1060                 }
1061
1062                 return STOP;
1063         }
1064
1065 private:
1066         glu::Precision m_precision;
1067 };
1068
1069 class UnpackUnorm4x8Case : public ShaderPackingFunctionCase
1070 {
1071 public:
1072         UnpackUnorm4x8Case (Context& context, glu::ShaderType shaderType)
1073                 : ShaderPackingFunctionCase(context, (string("unpackunorm4x8") + getShaderTypePostfix(shaderType)).c_str(), "unpackUnorm4x8", shaderType)
1074         {
1075                 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
1076                 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP)));
1077
1078                 m_spec.source = "out0 = unpackUnorm4x8(in0);";
1079         }
1080
1081         IterateResult iterate (void)
1082         {
1083                 const deUint32                          maxDiff         = 1; // Rounding error.
1084                 de::Random                                      rnd                     (deStringHash(getName()) ^ 0x776002);
1085                 std::vector<deUint32>           inputs;
1086                 std::vector<tcu::Vec4>          outputs;
1087
1088                 inputs.push_back(0x00000000u);
1089                 inputs.push_back(0x7fff8000u);
1090                 inputs.push_back(0x80007fffu);
1091                 inputs.push_back(0xffffffffu);
1092                 inputs.push_back(0x0001fffeu);
1093
1094                 // Random values.
1095                 for (int ndx = 0; ndx < 95; ndx++)
1096                         inputs.push_back(rnd.getUint32());
1097
1098                 outputs.resize(inputs.size());
1099
1100                 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
1101
1102                 {
1103                         const void*     in      = &inputs[0];
1104                         void*           out     = &outputs[0];
1105
1106                         m_executor->useProgram();
1107                         m_executor->execute((int)inputs.size(), &in, &out);
1108                 }
1109
1110                 // Verify
1111                 {
1112                         const int       numValues       = (int)inputs.size();
1113                         const int       maxPrints       = 10;
1114                         int                     numFailed       = 0;
1115
1116                         for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
1117                         {
1118                                 const deUint8   in0             = (deUint8)(inputs[valNdx] & 0xff);
1119                                 const deUint8   in1             = (deUint8)((inputs[valNdx] >> 8) & 0xff);
1120                                 const deUint8   in2             = (deUint8)((inputs[valNdx] >> 16) & 0xff);
1121                                 const deUint8   in3             = (deUint8)(inputs[valNdx] >> 24);
1122                                 const float             ref0    = de::clamp(float(in0) / 255.f, 0.0f, 1.0f);
1123                                 const float             ref1    = de::clamp(float(in1) / 255.f, 0.0f, 1.0f);
1124                                 const float             ref2    = de::clamp(float(in2) / 255.f, 0.0f, 1.0f);
1125                                 const float             ref3    = de::clamp(float(in3) / 255.f, 0.0f, 1.0f);
1126                                 const float             res0    = outputs[valNdx].x();
1127                                 const float             res1    = outputs[valNdx].y();
1128                                 const float             res2    = outputs[valNdx].z();
1129                                 const float             res3    = outputs[valNdx].w();
1130
1131                                 const deUint32  diff0   = getUlpDiff(ref0, res0);
1132                                 const deUint32  diff1   = getUlpDiff(ref1, res1);
1133                                 const deUint32  diff2   = getUlpDiff(ref2, res2);
1134                                 const deUint32  diff3   = getUlpDiff(ref3, res3);
1135
1136                                 if (diff0 > maxDiff || diff1 > maxDiff || diff2 > maxDiff || diff3 > maxDiff)
1137                                 {
1138                                         if (numFailed < maxPrints)
1139                                         {
1140                                                 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx << ",\n"
1141                                                                                                                            << "  expected unpackUnorm4x8(" << tcu::toHex(inputs[valNdx]) << ") = "
1142                                                                                                                            << "vec4(" << HexFloat(ref0) << ", " << HexFloat(ref1) << ", " << HexFloat(ref2) << ", " << HexFloat(ref3) << ")"
1143                                                                                                                            << ", got vec4(" << HexFloat(res0) << ", " << HexFloat(res1) << ", " << HexFloat(res2) << ", " << HexFloat(res3) << ")"
1144                                                                                                                            << "\n  ULP diffs = (" << diff0 << ", " << diff1 << ", " << diff2 << ", " << diff3 << "), max diff = " << maxDiff
1145                                                                                    << TestLog::EndMessage;
1146                                         }
1147                                         else if (numFailed == maxPrints)
1148                                                 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
1149
1150                                         numFailed += 1;
1151                                 }
1152                         }
1153
1154                         m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
1155
1156                         m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS    : QP_TEST_RESULT_FAIL,
1157                                                                         numFailed == 0 ? "Pass"                                 : "Result comparison failed");
1158                 }
1159
1160                 return STOP;
1161         }
1162 };
1163
1164 ShaderPackingFunctionTests::ShaderPackingFunctionTests (Context& context)
1165         : TestCaseGroup(context, "pack_unpack", "Floating-point pack and unpack function tests")
1166 {
1167 }
1168
1169 ShaderPackingFunctionTests::~ShaderPackingFunctionTests (void)
1170 {
1171 }
1172
1173 void ShaderPackingFunctionTests::init (void)
1174 {
1175         // New built-in functions in GLES 3.1
1176         {
1177                 const glu::ShaderType allShaderTypes[] =
1178                 {
1179                         glu::SHADERTYPE_VERTEX,
1180                         glu::SHADERTYPE_TESSELLATION_CONTROL,
1181                         glu::SHADERTYPE_TESSELLATION_EVALUATION,
1182                         glu::SHADERTYPE_GEOMETRY,
1183                         glu::SHADERTYPE_FRAGMENT,
1184                         glu::SHADERTYPE_COMPUTE
1185                 };
1186
1187                 // packSnorm4x8
1188                 for (int prec = 0; prec < glu::PRECISION_LAST; prec++)
1189                 {
1190                         for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(allShaderTypes); shaderTypeNdx++)
1191                                 addChild(new PackSnorm4x8Case(m_context, allShaderTypes[shaderTypeNdx], glu::Precision(prec)));
1192                 }
1193
1194                 // unpackSnorm4x8
1195                 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(allShaderTypes); shaderTypeNdx++)
1196                         addChild(new UnpackSnorm4x8Case(m_context, allShaderTypes[shaderTypeNdx]));
1197
1198                 // packUnorm4x8
1199                 for (int prec = 0; prec < glu::PRECISION_LAST; prec++)
1200                 {
1201                         for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(allShaderTypes); shaderTypeNdx++)
1202                                 addChild(new PackUnorm4x8Case(m_context, allShaderTypes[shaderTypeNdx], glu::Precision(prec)));
1203                 }
1204
1205                 // unpackUnorm4x8
1206                 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(allShaderTypes); shaderTypeNdx++)
1207                         addChild(new UnpackUnorm4x8Case(m_context, allShaderTypes[shaderTypeNdx]));
1208         }
1209
1210         // GLES 3 functions in new shader types.
1211         {
1212                 const glu::ShaderType newShaderTypes[] =
1213                 {
1214                         glu::SHADERTYPE_GEOMETRY,
1215                         glu::SHADERTYPE_COMPUTE
1216                 };
1217
1218                 // packSnorm2x16
1219                 for (int prec = 0; prec < glu::PRECISION_LAST; prec++)
1220                 {
1221                         for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(newShaderTypes); shaderTypeNdx++)
1222                                 addChild(new PackSnorm2x16Case(m_context, newShaderTypes[shaderTypeNdx], glu::Precision(prec)));
1223                 }
1224
1225                 // unpackSnorm2x16
1226                 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(newShaderTypes); shaderTypeNdx++)
1227                         addChild(new UnpackSnorm2x16Case(m_context, newShaderTypes[shaderTypeNdx]));
1228
1229                 // packUnorm2x16
1230                 for (int prec = 0; prec < glu::PRECISION_LAST; prec++)
1231                 {
1232                         for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(newShaderTypes); shaderTypeNdx++)
1233                                 addChild(new PackUnorm2x16Case(m_context, newShaderTypes[shaderTypeNdx], glu::Precision(prec)));
1234                 }
1235
1236                 // unpackUnorm2x16
1237                 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(newShaderTypes); shaderTypeNdx++)
1238                         addChild(new UnpackUnorm2x16Case(m_context, newShaderTypes[shaderTypeNdx]));
1239
1240                 // packHalf2x16
1241                 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(newShaderTypes); shaderTypeNdx++)
1242                         addChild(new PackHalf2x16Case(m_context, newShaderTypes[shaderTypeNdx]));
1243
1244                 // unpackHalf2x16
1245                 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(newShaderTypes); shaderTypeNdx++)
1246                         addChild(new UnpackHalf2x16Case(m_context, newShaderTypes[shaderTypeNdx]));
1247         }
1248 }
1249
1250 } // Functional
1251 } // gles31
1252 } // deqp