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