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