Merge "Fix color change verification in dithering tests" into nougat-cts-dev am:...
[platform/upstream/VK-GL-CTS.git] / modules / gles3 / functional / es3fShaderPackingFunctionTests.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 Floating-point packing and unpacking function tests.
22  *//*--------------------------------------------------------------------*/
23
24 #include "es3fShaderPackingFunctionTests.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 gles3
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::GLSL_VERSION_300_ES;
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         };
140         DE_ASSERT(de::inBounds<int>(shaderType, 0, DE_LENGTH_OF_ARRAY(s_postfix)));
141         return s_postfix[shaderType];
142 }
143
144 class PackSnorm2x16Case : public ShaderPackingFunctionCase
145 {
146 public:
147         PackSnorm2x16Case (Context& context, glu::ShaderType shaderType, glu::Precision precision)
148                 : ShaderPackingFunctionCase     (context, (string("packsnorm2x16") + getPrecisionPostfix(precision) + getShaderTypePostfix(shaderType)).c_str(), "packSnorm2x16", shaderType)
149                 , m_precision                           (precision)
150         {
151                 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_FLOAT_VEC2, precision)));
152                 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
153
154                 m_spec.source = "out0 = packSnorm2x16(in0);";
155         }
156
157         IterateResult iterate (void)
158         {
159                 de::Random                                      rnd                     (deStringHash(getName()) ^ 0x776002);
160                 std::vector<tcu::Vec2>          inputs;
161                 std::vector<deUint32>           outputs;
162                 const int                                       maxDiff         = m_precision == glu::PRECISION_HIGHP   ? 1             :               // Rounding only.
163                                                                                                   m_precision == glu::PRECISION_MEDIUMP ? 33    :               // (2^-10) * (2^15) + 1
164                                                                                                   m_precision == glu::PRECISION_LOWP    ? 129   : 0;    // (2^-8) * (2^15) + 1
165
166                 // Special values to check.
167                 inputs.push_back(tcu::Vec2(0.0f, 0.0f));
168                 inputs.push_back(tcu::Vec2(-1.0f, 1.0f));
169                 inputs.push_back(tcu::Vec2(0.5f, -0.5f));
170                 inputs.push_back(tcu::Vec2(-1.5f, 1.5f));
171                 inputs.push_back(tcu::Vec2(0.25f, -0.75f));
172
173                 // Random values, mostly in range.
174                 for (int ndx = 0; ndx < 15; ndx++)
175                 {
176                         const float x = rnd.getFloat()*2.5f - 1.25f;
177                         const float y = rnd.getFloat()*2.5f - 1.25f;
178                         inputs.push_back(tcu::Vec2(x, y));
179                 }
180
181                 // Large random values.
182                 for (int ndx = 0; ndx < 80; ndx++)
183                 {
184                         const float x = rnd.getFloat()*1e6f - 0.5e6f;
185                         const float y = rnd.getFloat()*1e6f - 0.5e6f;
186                         inputs.push_back(tcu::Vec2(x, y));
187                 }
188
189                 outputs.resize(inputs.size());
190
191                 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
192
193                 {
194                         const void*     in      = &inputs[0];
195                         void*           out     = &outputs[0];
196
197                         m_executor->useProgram();
198                         m_executor->execute((int)inputs.size(), &in, &out);
199                 }
200
201                 // Verify
202                 {
203                         const int       numValues       = (int)inputs.size();
204                         const int       maxPrints       = 10;
205                         int                     numFailed       = 0;
206
207                         for (int valNdx = 0; valNdx < numValues; valNdx++)
208                         {
209                                 const deUint16  ref0    = (deUint16)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].x(), -1.0f, 1.0f) * 32767.0f), -(1<<15), (1<<15)-1);
210                                 const deUint16  ref1    = (deUint16)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].y(), -1.0f, 1.0f) * 32767.0f), -(1<<15), (1<<15)-1);
211                                 const deUint32  ref             = (ref1 << 16) | ref0;
212                                 const deUint32  res             = outputs[valNdx];
213                                 const deUint16  res0    = (deUint16)(res & 0xffff);
214                                 const deUint16  res1    = (deUint16)(res >> 16);
215                                 const int               diff0   = de::abs((int)ref0 - (int)res0);
216                                 const int               diff1   = de::abs((int)ref1 - (int)res1);
217
218                                 if (diff0 > maxDiff || diff1 > maxDiff)
219                                 {
220                                         if (numFailed < maxPrints)
221                                         {
222                                                 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx
223                                                                                                                            << ", expected packSnorm2x16(" << inputs[valNdx] << ") = " << tcu::toHex(ref)
224                                                                                                                            << ", got " << tcu::toHex(res)
225                                                                                                                            << "\n  diffs = (" << diff0 << ", " << diff1 << "), max diff = " << maxDiff
226                                                                                    << TestLog::EndMessage;
227                                         }
228                                         else if (numFailed == maxPrints)
229                                                 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
230
231                                         numFailed += 1;
232                                 }
233                         }
234
235                         m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
236
237                         m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS    : QP_TEST_RESULT_FAIL,
238                                                                         numFailed == 0 ? "Pass"                                 : "Result comparison failed");
239                 }
240
241                 return STOP;
242         }
243
244 private:
245         glu::Precision m_precision;
246 };
247
248 class UnpackSnorm2x16Case : public ShaderPackingFunctionCase
249 {
250 public:
251         UnpackSnorm2x16Case (Context& context, glu::ShaderType shaderType)
252                 : ShaderPackingFunctionCase(context, (string("unpacksnorm2x16") + getShaderTypePostfix(shaderType)).c_str(), "unpackSnorm2x16", shaderType)
253         {
254                 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
255                 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_FLOAT_VEC2, glu::PRECISION_HIGHP)));
256
257                 m_spec.source = "out0 = unpackSnorm2x16(in0);";
258         }
259
260         IterateResult iterate (void)
261         {
262                 const deUint32                          maxDiff         = 1; // Rounding error.
263                 de::Random                                      rnd                     (deStringHash(getName()) ^ 0x776002);
264                 std::vector<deUint32>           inputs;
265                 std::vector<tcu::Vec2>          outputs;
266
267                 inputs.push_back(0x00000000u);
268                 inputs.push_back(0x7fff8000u);
269                 inputs.push_back(0x80007fffu);
270                 inputs.push_back(0xffffffffu);
271                 inputs.push_back(0x0001fffeu);
272
273                 // Random values.
274                 for (int ndx = 0; ndx < 95; ndx++)
275                         inputs.push_back(rnd.getUint32());
276
277                 outputs.resize(inputs.size());
278
279                 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
280
281                 {
282                         const void*     in      = &inputs[0];
283                         void*           out     = &outputs[0];
284
285                         m_executor->useProgram();
286                         m_executor->execute((int)inputs.size(), &in, &out);
287                 }
288
289                 // Verify
290                 {
291                         const int       numValues       = (int)inputs.size();
292                         const int       maxPrints       = 10;
293                         int                     numFailed       = 0;
294
295                         for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
296                         {
297                                 const deInt16   in0                     = (deInt16)(deUint16)(inputs[valNdx] & 0xffff);
298                                 const deInt16   in1                     = (deInt16)(deUint16)(inputs[valNdx] >> 16);
299                                 const float             ref0            = de::clamp(float(in0) / 32767.f, -1.0f, 1.0f);
300                                 const float             ref1            = de::clamp(float(in1) / 32767.f, -1.0f, 1.0f);
301                                 const float             res0            = outputs[valNdx].x();
302                                 const float             res1            = outputs[valNdx].y();
303
304                                 const deUint32  diff0   = getUlpDiff(ref0, res0);
305                                 const deUint32  diff1   = getUlpDiff(ref1, res1);
306
307                                 if (diff0 > maxDiff || diff1 > maxDiff)
308                                 {
309                                         if (numFailed < maxPrints)
310                                         {
311                                                 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx << ",\n"
312                                                                                                                            << "  expected unpackSnorm2x16(" << tcu::toHex(inputs[valNdx]) << ") = "
313                                                                                                                            << "vec2(" << HexFloat(ref0) << ", " << HexFloat(ref1) << ")"
314                                                                                                                            << ", got vec2(" << HexFloat(res0) << ", " << HexFloat(res1) << ")"
315                                                                                                                            << "\n  ULP diffs = (" << diff0 << ", " << diff1 << "), max diff = " << maxDiff
316                                                                                    << TestLog::EndMessage;
317                                         }
318                                         else if (numFailed == maxPrints)
319                                                 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
320
321                                         numFailed += 1;
322                                 }
323                         }
324
325                         m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
326
327                         m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS    : QP_TEST_RESULT_FAIL,
328                                                                         numFailed == 0 ? "Pass"                                 : "Result comparison failed");
329                 }
330
331                 return STOP;
332         }
333 };
334
335 class PackUnorm2x16Case : public ShaderPackingFunctionCase
336 {
337 public:
338         PackUnorm2x16Case (Context& context, glu::ShaderType shaderType, glu::Precision precision)
339                 : ShaderPackingFunctionCase     (context, (string("packunorm2x16") + getPrecisionPostfix(precision) + getShaderTypePostfix(shaderType)).c_str(), "packUnorm2x16", shaderType)
340                 , m_precision                           (precision)
341         {
342                 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_FLOAT_VEC2, precision)));
343                 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
344
345                 m_spec.source = "out0 = packUnorm2x16(in0);";
346         }
347
348         IterateResult iterate (void)
349         {
350                 de::Random                                      rnd                     (deStringHash(getName()) ^ 0x776002);
351                 std::vector<tcu::Vec2>          inputs;
352                 std::vector<deUint32>           outputs;
353                 const int                                       maxDiff         = m_precision == glu::PRECISION_HIGHP   ? 1             :               // Rounding only.
354                                                                                                   m_precision == glu::PRECISION_MEDIUMP ? 65    :               // (2^-10) * (2^16) + 1
355                                                                                                   m_precision == glu::PRECISION_LOWP    ? 257   : 0;    // (2^-8) * (2^16) + 1
356
357                 // Special values to check.
358                 inputs.push_back(tcu::Vec2(0.0f, 0.0f));
359                 inputs.push_back(tcu::Vec2(0.5f, 1.0f));
360                 inputs.push_back(tcu::Vec2(1.0f, 0.5f));
361                 inputs.push_back(tcu::Vec2(-0.5f, 1.5f));
362                 inputs.push_back(tcu::Vec2(0.25f, 0.75f));
363
364                 // Random values, mostly in range.
365                 for (int ndx = 0; ndx < 15; ndx++)
366                 {
367                         const float x = rnd.getFloat()*1.25f;
368                         const float y = rnd.getFloat()*1.25f;
369                         inputs.push_back(tcu::Vec2(x, y));
370                 }
371
372                 // Large random values.
373                 for (int ndx = 0; ndx < 80; ndx++)
374                 {
375                         const float x = rnd.getFloat()*1e6f - 1e5f;
376                         const float y = rnd.getFloat()*1e6f - 1e5f;
377                         inputs.push_back(tcu::Vec2(x, y));
378                 }
379
380                 outputs.resize(inputs.size());
381
382                 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
383
384                 {
385                         const void*     in      = &inputs[0];
386                         void*           out     = &outputs[0];
387
388                         m_executor->useProgram();
389                         m_executor->execute((int)inputs.size(), &in, &out);
390                 }
391
392                 // Verify
393                 {
394                         const int       numValues       = (int)inputs.size();
395                         const int       maxPrints       = 10;
396                         int                     numFailed       = 0;
397
398                         for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
399                         {
400                                 const deUint16  ref0    = (deUint16)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].x(), 0.0f, 1.0f) * 65535.0f), 0, (1<<16)-1);
401                                 const deUint16  ref1    = (deUint16)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].y(), 0.0f, 1.0f) * 65535.0f), 0, (1<<16)-1);
402                                 const deUint32  ref             = (ref1 << 16) | ref0;
403                                 const deUint32  res             = outputs[valNdx];
404                                 const deUint16  res0    = (deUint16)(res & 0xffff);
405                                 const deUint16  res1    = (deUint16)(res >> 16);
406                                 const int               diff0   = de::abs((int)ref0 - (int)res0);
407                                 const int               diff1   = de::abs((int)ref1 - (int)res1);
408
409                                 if (diff0 > maxDiff || diff1 > maxDiff)
410                                 {
411                                         if (numFailed < maxPrints)
412                                         {
413                                                 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx
414                                                                                                                            << ", expected packUnorm2x16(" << inputs[valNdx] << ") = " << tcu::toHex(ref)
415                                                                                                                            << ", got " << tcu::toHex(res)
416                                                                                                                            << "\n  diffs = (" << diff0 << ", " << diff1 << "), max diff = " << maxDiff
417                                                                                    << TestLog::EndMessage;
418                                         }
419                                         else if (numFailed == maxPrints)
420                                                 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
421
422                                         numFailed += 1;
423                                 }
424                         }
425
426                         m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
427
428                         m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS    : QP_TEST_RESULT_FAIL,
429                                                                         numFailed == 0 ? "Pass"                                 : "Result comparison failed");
430                 }
431
432                 return STOP;
433         }
434
435 private:
436         glu::Precision m_precision;
437 };
438
439 class UnpackUnorm2x16Case : public ShaderPackingFunctionCase
440 {
441 public:
442         UnpackUnorm2x16Case (Context& context, glu::ShaderType shaderType)
443                 : ShaderPackingFunctionCase(context, (string("unpackunorm2x16") + getShaderTypePostfix(shaderType)).c_str(), "unpackUnorm2x16", shaderType)
444         {
445                 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
446                 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_FLOAT_VEC2, glu::PRECISION_HIGHP)));
447
448                 m_spec.source = "out0 = unpackUnorm2x16(in0);";
449         }
450
451         IterateResult iterate (void)
452         {
453                 const deUint32                          maxDiff         = 1; // Rounding error.
454                 de::Random                                      rnd                     (deStringHash(getName()) ^ 0x776002);
455                 std::vector<deUint32>           inputs;
456                 std::vector<tcu::Vec2>          outputs;
457
458                 inputs.push_back(0x00000000u);
459                 inputs.push_back(0x7fff8000u);
460                 inputs.push_back(0x80007fffu);
461                 inputs.push_back(0xffffffffu);
462                 inputs.push_back(0x0001fffeu);
463
464                 // Random values.
465                 for (int ndx = 0; ndx < 95; ndx++)
466                         inputs.push_back(rnd.getUint32());
467
468                 outputs.resize(inputs.size());
469
470                 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
471
472                 {
473                         const void*     in      = &inputs[0];
474                         void*           out     = &outputs[0];
475
476                         m_executor->useProgram();
477                         m_executor->execute((int)inputs.size(), &in, &out);
478                 }
479
480                 // Verify
481                 {
482                         const int       numValues       = (int)inputs.size();
483                         const int       maxPrints       = 10;
484                         int                     numFailed       = 0;
485
486                         for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
487                         {
488                                 const deUint16  in0                     = (deUint16)(inputs[valNdx] & 0xffff);
489                                 const deUint16  in1                     = (deUint16)(inputs[valNdx] >> 16);
490                                 const float             ref0            = float(in0) / 65535.0f;
491                                 const float             ref1            = float(in1) / 65535.0f;
492                                 const float             res0            = outputs[valNdx].x();
493                                 const float             res1            = outputs[valNdx].y();
494
495                                 const deUint32  diff0           = getUlpDiff(ref0, res0);
496                                 const deUint32  diff1           = getUlpDiff(ref1, res1);
497
498                                 if (diff0 > maxDiff || diff1 > maxDiff)
499                                 {
500                                         if (numFailed < maxPrints)
501                                         {
502                                                 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx << ",\n"
503                                                                                                                            << "  expected unpackUnorm2x16(" << tcu::toHex(inputs[valNdx]) << ") = "
504                                                                                                                            << "vec2(" << HexFloat(ref0) << ", " << HexFloat(ref1) << ")"
505                                                                                                                            << ", got vec2(" << HexFloat(res0) << ", " << HexFloat(res1) << ")"
506                                                                                                                            << "\n  ULP diffs = (" << diff0 << ", " << diff1 << "), max diff = " << maxDiff
507                                                                                    << TestLog::EndMessage;
508                                         }
509                                         else if (numFailed == maxPrints)
510                                                 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
511
512                                         numFailed += 1;
513                                 }
514                         }
515
516                         m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
517
518                         m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS    : QP_TEST_RESULT_FAIL,
519                                                                         numFailed == 0 ? "Pass"                                 : "Result comparison failed");
520                 }
521
522                 return STOP;
523         }
524 };
525
526 class PackHalf2x16Case : public ShaderPackingFunctionCase
527 {
528 public:
529         PackHalf2x16Case (Context& context, glu::ShaderType shaderType)
530                 : ShaderPackingFunctionCase(context, (string("packhalf2x16") + getShaderTypePostfix(shaderType)).c_str(), "packHalf2x16", shaderType)
531         {
532                 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_FLOAT_VEC2, glu::PRECISION_HIGHP)));
533                 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
534
535                 m_spec.source = "out0 = packHalf2x16(in0);";
536         }
537
538         IterateResult iterate (void)
539         {
540                 const int                                       maxDiff         = 0; // Values can be represented exactly in mediump.
541                 de::Random                                      rnd                     (deStringHash(getName()) ^ 0x776002);
542                 std::vector<tcu::Vec2>          inputs;
543                 std::vector<deUint32>           outputs;
544
545                 // Special values to check.
546                 inputs.push_back(tcu::Vec2(0.0f, 0.0f));
547                 inputs.push_back(tcu::Vec2(0.5f, 1.0f));
548                 inputs.push_back(tcu::Vec2(1.0f, 0.5f));
549                 inputs.push_back(tcu::Vec2(-0.5f, 1.5f));
550                 inputs.push_back(tcu::Vec2(0.25f, 0.75f));
551
552                 // Random values.
553                 {
554                         const int       minExp  = -14;
555                         const int       maxExp  = 15;
556
557                         for (int ndx = 0; ndx < 95; ndx++)
558                         {
559                                 tcu::Vec2 v;
560                                 for (int c = 0; c < 2; c++)
561                                 {
562                                         const int               s                       = rnd.getBool() ? 1 : -1;
563                                         const int               exp                     = rnd.getInt(minExp, maxExp);
564                                         const deUint32  mantissa        = rnd.getUint32() & ((1<<23)-1);
565
566                                         v[c] = tcu::Float32::construct(s, exp ? exp : 1 /* avoid denormals */, (1u<<23) | mantissa).asFloat();
567                                 }
568                                 inputs.push_back(v);
569                         }
570                 }
571
572                 // Convert input values to fp16 and back to make sure they can be represented exactly in mediump.
573                 for (std::vector<tcu::Vec2>::iterator inVal = inputs.begin(); inVal != inputs.end(); ++inVal)
574                         *inVal = tcu::Vec2(tcu::Float16(inVal->x()).asFloat(), tcu::Float16(inVal->y()).asFloat());
575
576                 outputs.resize(inputs.size());
577
578                 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
579
580                 {
581                         const void*     in      = &inputs[0];
582                         void*           out     = &outputs[0];
583
584                         m_executor->useProgram();
585                         m_executor->execute((int)inputs.size(), &in, &out);
586                 }
587
588                 // Verify
589                 {
590                         const int       numValues       = (int)inputs.size();
591                         const int       maxPrints       = 10;
592                         int                     numFailed       = 0;
593
594                         for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
595                         {
596                                 const deUint16  ref0    = (deUint16)tcu::Float16(inputs[valNdx].x()).bits();
597                                 const deUint16  ref1    = (deUint16)tcu::Float16(inputs[valNdx].y()).bits();
598                                 const deUint32  ref             = (ref1 << 16) | ref0;
599                                 const deUint32  res             = outputs[valNdx];
600                                 const deUint16  res0    = (deUint16)(res & 0xffff);
601                                 const deUint16  res1    = (deUint16)(res >> 16);
602                                 const int               diff0   = de::abs((int)ref0 - (int)res0);
603                                 const int               diff1   = de::abs((int)ref1 - (int)res1);
604
605                                 if (diff0 > maxDiff || diff1 > maxDiff)
606                                 {
607                                         if (numFailed < maxPrints)
608                                         {
609                                                 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx
610                                                                                                                            << ", expected packHalf2x16(" << inputs[valNdx] << ") = " << tcu::toHex(ref)
611                                                                                                                            << ", got " << tcu::toHex(res)
612                                                                                                                            << "\n  diffs = (" << diff0 << ", " << diff1 << "), max diff = " << maxDiff
613                                                                                    << TestLog::EndMessage;
614                                         }
615                                         else if (numFailed == maxPrints)
616                                                 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
617
618                                         numFailed += 1;
619                                 }
620                         }
621
622                         m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
623
624                         m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS    : QP_TEST_RESULT_FAIL,
625                                                                         numFailed == 0 ? "Pass"                                 : "Result comparison failed");
626                 }
627
628                 return STOP;
629         }
630 };
631
632 class UnpackHalf2x16Case : public ShaderPackingFunctionCase
633 {
634 public:
635         UnpackHalf2x16Case (Context& context, glu::ShaderType shaderType)
636                 : ShaderPackingFunctionCase(context, (string("unpackhalf2x16") + getShaderTypePostfix(shaderType)).c_str(), "unpackHalf2x16", shaderType)
637         {
638                 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
639                 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_FLOAT_VEC2, glu::PRECISION_MEDIUMP)));
640
641                 m_spec.source = "out0 = unpackHalf2x16(in0);";
642         }
643
644         IterateResult iterate (void)
645         {
646                 const int                                       maxDiff         = 0; // All bits must be accurate.
647                 de::Random                                      rnd                     (deStringHash(getName()) ^ 0x776002);
648                 std::vector<deUint32>           inputs;
649                 std::vector<tcu::Vec2>          outputs;
650
651                 // Special values.
652                 inputs.push_back((tcu::Float16( 0.0f).bits() << 16) | tcu::Float16( 1.0f).bits());
653                 inputs.push_back((tcu::Float16( 1.0f).bits() << 16) | tcu::Float16( 0.0f).bits());
654                 inputs.push_back((tcu::Float16(-1.0f).bits() << 16) | tcu::Float16( 0.5f).bits());
655                 inputs.push_back((tcu::Float16( 0.5f).bits() << 16) | tcu::Float16(-0.5f).bits());
656
657                 // Construct random values.
658                 {
659                         const int       minExp          = -14;
660                         const int       maxExp          = 15;
661                         const int       mantBits        = 10;
662
663                         for (int ndx = 0; ndx < 96; ndx++)
664                         {
665                                 deUint32 inVal = 0;
666                                 for (int c = 0; c < 2; c++)
667                                 {
668                                         const int               s                       = rnd.getBool() ? 1 : -1;
669                                         const int               exp                     = rnd.getInt(minExp, maxExp);
670                                         const deUint32  mantissa        = rnd.getUint32() & ((1<<mantBits)-1);
671                                         const deUint16  value           = tcu::Float16::construct(s, exp ? exp : 1 /* avoid denorm */, (deUint16)((1u<<10) | mantissa)).bits();
672
673                                         inVal |= value << (16*c);
674                                 }
675                                 inputs.push_back(inVal);
676                         }
677                 }
678
679                 outputs.resize(inputs.size());
680
681                 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
682
683                 {
684                         const void*     in      = &inputs[0];
685                         void*           out     = &outputs[0];
686
687                         m_executor->useProgram();
688                         m_executor->execute((int)inputs.size(), &in, &out);
689                 }
690
691                 // Verify
692                 {
693                         const int       numValues       = (int)inputs.size();
694                         const int       maxPrints       = 10;
695                         int                     numFailed       = 0;
696
697                         for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
698                         {
699                                 const deUint16  in0                     = (deUint16)(inputs[valNdx] & 0xffff);
700                                 const deUint16  in1                     = (deUint16)(inputs[valNdx] >> 16);
701                                 const float             ref0            = tcu::Float16(in0).asFloat();
702                                 const float             ref1            = tcu::Float16(in1).asFloat();
703                                 const float             res0            = outputs[valNdx].x();
704                                 const float             res1            = outputs[valNdx].y();
705
706                                 const deUint32  refBits0        = tcu::Float32(ref0).bits();
707                                 const deUint32  refBits1        = tcu::Float32(ref1).bits();
708                                 const deUint32  resBits0        = tcu::Float32(res0).bits();
709                                 const deUint32  resBits1        = tcu::Float32(res1).bits();
710
711                                 const int               diff0   = de::abs((int)refBits0 - (int)resBits0);
712                                 const int               diff1   = de::abs((int)refBits1 - (int)resBits1);
713
714                                 if (diff0 > maxDiff || diff1 > maxDiff)
715                                 {
716                                         if (numFailed < maxPrints)
717                                         {
718                                                 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx << ",\n"
719                                                                                                                            << "  expected unpackHalf2x16(" << tcu::toHex(inputs[valNdx]) << ") = "
720                                                                                                                            << "vec2(" << ref0 << " / " << tcu::toHex(refBits0) << ", " << ref1 << " / " << tcu::toHex(refBits1) << ")"
721                                                                                                                            << ", got vec2(" << res0 << " / " << tcu::toHex(resBits0) << ", " << res1 << " / " << tcu::toHex(resBits1) << ")"
722                                                                                                                            << "\n  ULP diffs = (" << diff0 << ", " << diff1 << "), max diff = " << maxDiff
723                                                                                    << TestLog::EndMessage;
724                                         }
725                                         else if (numFailed == maxPrints)
726                                                 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
727
728                                         numFailed += 1;
729                                 }
730                         }
731
732                         m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
733
734                         m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS    : QP_TEST_RESULT_FAIL,
735                                                                         numFailed == 0 ? "Pass"                                 : "Result comparison failed");
736                 }
737
738                 return STOP;
739         }
740 };
741
742 ShaderPackingFunctionTests::ShaderPackingFunctionTests (Context& context)
743         : TestCaseGroup(context, "pack_unpack", "Floating-point pack and unpack function tests")
744 {
745 }
746
747 ShaderPackingFunctionTests::~ShaderPackingFunctionTests (void)
748 {
749 }
750
751 void ShaderPackingFunctionTests::init (void)
752 {
753         addChild(new PackSnorm2x16Case  (m_context, glu::SHADERTYPE_VERTEX,             glu::PRECISION_LOWP));
754         addChild(new PackSnorm2x16Case  (m_context, glu::SHADERTYPE_FRAGMENT,   glu::PRECISION_LOWP));
755         addChild(new PackSnorm2x16Case  (m_context, glu::SHADERTYPE_VERTEX,             glu::PRECISION_MEDIUMP));
756         addChild(new PackSnorm2x16Case  (m_context, glu::SHADERTYPE_FRAGMENT,   glu::PRECISION_MEDIUMP));
757         addChild(new PackSnorm2x16Case  (m_context, glu::SHADERTYPE_VERTEX,             glu::PRECISION_HIGHP));
758         addChild(new PackSnorm2x16Case  (m_context, glu::SHADERTYPE_FRAGMENT,   glu::PRECISION_HIGHP));
759
760         addChild(new UnpackSnorm2x16Case(m_context, glu::SHADERTYPE_VERTEX));
761         addChild(new UnpackSnorm2x16Case(m_context, glu::SHADERTYPE_FRAGMENT));
762
763         addChild(new PackUnorm2x16Case  (m_context, glu::SHADERTYPE_VERTEX,             glu::PRECISION_LOWP));
764         addChild(new PackUnorm2x16Case  (m_context, glu::SHADERTYPE_FRAGMENT,   glu::PRECISION_LOWP));
765         addChild(new PackUnorm2x16Case  (m_context, glu::SHADERTYPE_VERTEX,             glu::PRECISION_MEDIUMP));
766         addChild(new PackUnorm2x16Case  (m_context, glu::SHADERTYPE_FRAGMENT,   glu::PRECISION_MEDIUMP));
767         addChild(new PackUnorm2x16Case  (m_context, glu::SHADERTYPE_VERTEX,             glu::PRECISION_HIGHP));
768         addChild(new PackUnorm2x16Case  (m_context, glu::SHADERTYPE_FRAGMENT,   glu::PRECISION_HIGHP));
769
770         addChild(new UnpackUnorm2x16Case(m_context, glu::SHADERTYPE_VERTEX));
771         addChild(new UnpackUnorm2x16Case(m_context, glu::SHADERTYPE_FRAGMENT));
772
773         addChild(new PackHalf2x16Case   (m_context, glu::SHADERTYPE_VERTEX));
774         addChild(new PackHalf2x16Case   (m_context, glu::SHADERTYPE_FRAGMENT));
775
776         addChild(new UnpackHalf2x16Case (m_context, glu::SHADERTYPE_VERTEX));
777         addChild(new UnpackHalf2x16Case (m_context, glu::SHADERTYPE_FRAGMENT));
778 }
779
780 } // Functional
781 } // gles3
782 } // deqp