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
getUlpDiff(float a,float b)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;
HexFloatvkt::shaderexecutor::__anonb002ca150111::HexFloat59 HexFloat (const float value_) : value(value_) {}
60 };
61
operator <<(std::ostream & str,const HexFloat & v)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
getPrecisionPostfix(glu::Precision precision)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
getShaderTypePostfix(glu::ShaderType shaderType)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
initPrograms(vk::SourceCollections & programCollection) const105 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
ShaderPackingFunctionCase(tcu::TestContext & testCtx,const char * name,const char * description,glu::ShaderType shaderType)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
~ShaderPackingFunctionCase(void)125 ShaderPackingFunctionCase::~ShaderPackingFunctionCase (void)
126 {
127 }
128
129 // ShaderPackingFunctionTestInstance
130
131 class ShaderPackingFunctionTestInstance : public TestInstance
132 {
133 public:
ShaderPackingFunctionTestInstance(Context & context,glu::ShaderType shaderType,const ShaderSpec & spec,const char * name)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:
PackSnorm2x16CaseInstance(Context & context,glu::ShaderType shaderType,const ShaderSpec & spec,glu::Precision precision,const char * name)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
iterate(void)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:
PackSnorm2x16Case(tcu::TestContext & testCtx,glu::ShaderType shaderType,glu::Precision precision)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
createInstance(Context & ctx) const267 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:
UnpackSnorm2x16CaseInstance(Context & context,glu::ShaderType shaderType,const ShaderSpec & spec,const char * name)279 UnpackSnorm2x16CaseInstance (Context& context, glu::ShaderType shaderType, const ShaderSpec& spec, const char* name)
280 : ShaderPackingFunctionTestInstance (context, shaderType, spec, name)
281 {
282 }
283
iterate(void)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:
UnpackSnorm2x16Case(tcu::TestContext & testCtx,glu::ShaderType shaderType)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
createInstance(Context & ctx) const371 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:
PackUnorm2x16CaseInstance(Context & context,glu::ShaderType shaderType,const ShaderSpec & spec,glu::Precision precision,const char * name)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
iterate(void)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:
PackUnorm2x16Case(tcu::TestContext & testCtx,glu::ShaderType shaderType,glu::Precision precision)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
createInstance(Context & ctx) const490 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:
UnpackUnorm2x16CaseInstance(Context & context,glu::ShaderType shaderType,const ShaderSpec & spec,const char * name)502 UnpackUnorm2x16CaseInstance (Context& context, glu::ShaderType shaderType, const ShaderSpec& spec, const char* name)
503 : ShaderPackingFunctionTestInstance (context, shaderType, spec, name)
504 {
505 }
506
iterate(void)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:
UnpackUnorm2x16Case(tcu::TestContext & testCtx,glu::ShaderType shaderType)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
createInstance(Context & ctx) const595 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:
PackHalf2x16CaseInstance(Context & context,glu::ShaderType shaderType,const ShaderSpec & spec,const char * name)605 PackHalf2x16CaseInstance (Context& context, glu::ShaderType shaderType, const ShaderSpec& spec, const char* name)
606 : ShaderPackingFunctionTestInstance (context, shaderType, spec, name)
607 {
608 }
609
iterate(void)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:
PackHalf2x16Case(tcu::TestContext & testCtx,glu::ShaderType shaderType)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
createInstance(Context & ctx) const716 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 public:
UnpackHalf2x16CaseInstance(Context & context,glu::ShaderType shaderType,const ShaderSpec & spec,const char * name)726 UnpackHalf2x16CaseInstance (Context& context, glu::ShaderType shaderType, const ShaderSpec& spec, const char* name)
727 : ShaderPackingFunctionTestInstance (context, shaderType, spec, name)
728 {
729 }
730
iterate(void)731 tcu::TestStatus iterate (void)
732 {
733 const int maxDiff = 0; // All bits must be accurate.
734 de::Random rnd (deStringHash(m_name) ^ 0x776002);
735 std::vector<deUint32> inputs;
736 std::vector<tcu::Vec2> outputs;
737
738 // Special values.
739 inputs.push_back((tcu::Float16( 0.0f).bits() << 16) | tcu::Float16( 1.0f).bits());
740 inputs.push_back((tcu::Float16( 1.0f).bits() << 16) | tcu::Float16( 0.0f).bits());
741 inputs.push_back((tcu::Float16(-1.0f).bits() << 16) | tcu::Float16( 0.5f).bits());
742 inputs.push_back((tcu::Float16( 0.5f).bits() << 16) | tcu::Float16(-0.5f).bits());
743
744 // Construct random values.
745 {
746 const int minExp = -14;
747 const int maxExp = 15;
748 const int mantBits = 10;
749
750 for (int ndx = 0; ndx < 96; ndx++)
751 {
752 deUint32 inVal = 0;
753 for (int c = 0; c < 2; c++)
754 {
755 const int s = rnd.getBool() ? 1 : -1;
756 const int exp = rnd.getInt(minExp, maxExp);
757 const deUint32 mantissa = rnd.getUint32() & ((1<<mantBits)-1);
758 const deUint16 value = tcu::Float16::construct(s, exp ? exp : 1 /* avoid denorm */, (deUint16)((1u<<10) | mantissa)).bits();
759
760 inVal |= value << (16*c);
761 }
762 inputs.push_back(inVal);
763 }
764 }
765
766 outputs.resize(inputs.size());
767
768 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
769
770 {
771 const void* in = &inputs[0];
772 void* out = &outputs[0];
773
774 m_executor->execute((int)inputs.size(), &in, &out);
775 }
776
777 // Verify
778 {
779 const int numValues = (int)inputs.size();
780 const int maxPrints = 10;
781 int numFailed = 0;
782
783 for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
784 {
785 const deUint16 in0 = (deUint16)(inputs[valNdx] & 0xffff);
786 const deUint16 in1 = (deUint16)(inputs[valNdx] >> 16);
787 const float ref0 = tcu::Float16(in0).asFloat();
788 const float ref1 = tcu::Float16(in1).asFloat();
789 const float res0 = outputs[valNdx].x();
790 const float res1 = outputs[valNdx].y();
791
792 const deUint32 refBits0 = tcu::Float32(ref0).bits();
793 const deUint32 refBits1 = tcu::Float32(ref1).bits();
794 const deUint32 resBits0 = tcu::Float32(res0).bits();
795 const deUint32 resBits1 = tcu::Float32(res1).bits();
796
797 const int diff0 = de::abs((int)refBits0 - (int)resBits0);
798 const int diff1 = de::abs((int)refBits1 - (int)resBits1);
799
800 if (diff0 > maxDiff || diff1 > maxDiff)
801 {
802 if (numFailed < maxPrints)
803 {
804 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx << ",\n"
805 << " expected unpackHalf2x16(" << tcu::toHex(inputs[valNdx]) << ") = "
806 << "vec2(" << ref0 << " / " << tcu::toHex(refBits0) << ", " << ref1 << " / " << tcu::toHex(refBits1) << ")"
807 << ", got vec2(" << res0 << " / " << tcu::toHex(resBits0) << ", " << res1 << " / " << tcu::toHex(resBits1) << ")"
808 << "\n ULP diffs = (" << diff0 << ", " << diff1 << "), max diff = " << maxDiff
809 << TestLog::EndMessage;
810 }
811 else if (numFailed == maxPrints)
812 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
813
814 numFailed += 1;
815 }
816 }
817
818 m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
819
820 if (numFailed == 0)
821 return tcu::TestStatus::pass("Pass");
822 else
823 return tcu::TestStatus::fail("Result comparison failed");
824
825 }
826 }
827 };
828
829 class UnpackHalf2x16Case : public ShaderPackingFunctionCase
830 {
831 public:
UnpackHalf2x16Case(tcu::TestContext & testCtx,glu::ShaderType shaderType)832 UnpackHalf2x16Case (tcu::TestContext& testCtx, glu::ShaderType shaderType)
833 : ShaderPackingFunctionCase (testCtx, (string("unpackhalf2x16") + getShaderTypePostfix(shaderType)).c_str(), "unpackHalf2x16", shaderType)
834 {
835 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
836 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_FLOAT_VEC2, glu::PRECISION_MEDIUMP)));
837
838 m_spec.source = "out0 = unpackHalf2x16(in0);";
839 }
840
createInstance(Context & ctx) const841 TestInstance* createInstance (Context& ctx) const
842 {
843 return new UnpackHalf2x16CaseInstance(ctx, m_shaderType, m_spec, getName());
844 }
845
846 };
847
848 class PackSnorm4x8CaseInstance : public ShaderPackingFunctionTestInstance
849 {
850 public:
PackSnorm4x8CaseInstance(Context & context,glu::ShaderType shaderType,const ShaderSpec & spec,glu::Precision precision,const char * name)851 PackSnorm4x8CaseInstance (Context& context, glu::ShaderType shaderType, const ShaderSpec& spec, glu::Precision precision, const char* name)
852 : ShaderPackingFunctionTestInstance (context, shaderType, spec, name)
853 , m_precision (precision)
854 {
855 }
856
iterate(void)857 tcu::TestStatus iterate (void)
858 {
859 de::Random rnd (deStringHash(m_name) ^ 0x42f2c0);
860 std::vector<tcu::Vec4> inputs;
861 std::vector<deUint32> outputs;
862 const int maxDiff = m_precision == glu::PRECISION_HIGHP ? 1 : // Rounding only.
863 m_precision == glu::PRECISION_MEDIUMP ? 1 : // (2^-10) * (2^7) + 1
864 m_precision == glu::PRECISION_LOWP ? 2 : 0; // (2^-8) * (2^7) + 1
865
866 // Special values to check.
867 inputs.push_back(tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f));
868 inputs.push_back(tcu::Vec4(-1.0f, 1.0f, -1.0f, 1.0f));
869 inputs.push_back(tcu::Vec4(0.5f, -0.5f, -0.5f, 0.5f));
870 inputs.push_back(tcu::Vec4(-1.5f, 1.5f, -1.5f, 1.5f));
871 inputs.push_back(tcu::Vec4(0.25f, -0.75f, -0.25f, 0.75f));
872
873 // Random values, mostly in range.
874 for (int ndx = 0; ndx < 15; ndx++)
875 {
876 const float x = rnd.getFloat()*2.5f - 1.25f;
877 const float y = rnd.getFloat()*2.5f - 1.25f;
878 const float z = rnd.getFloat()*2.5f - 1.25f;
879 const float w = rnd.getFloat()*2.5f - 1.25f;
880 inputs.push_back(tcu::Vec4(x, y, z, w));
881 }
882
883 // Large random values.
884 for (int ndx = 0; ndx < 80; ndx++)
885 {
886 const float x = rnd.getFloat()*1e6f - 0.5e6f;
887 const float y = rnd.getFloat()*1e6f - 0.5e6f;
888 const float z = rnd.getFloat()*1e6f - 0.5e6f;
889 const float w = rnd.getFloat()*1e6f - 0.5e6f;
890 inputs.push_back(tcu::Vec4(x, y, z, w));
891 }
892
893 outputs.resize(inputs.size());
894
895 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
896
897 {
898 const void* in = &inputs[0];
899 void* out = &outputs[0];
900
901 m_executor->execute((int)inputs.size(), &in, &out);
902 }
903
904 // Verify
905 {
906 const int numValues = (int)inputs.size();
907 const int maxPrints = 10;
908 int numFailed = 0;
909
910 for (int valNdx = 0; valNdx < numValues; valNdx++)
911 {
912 const deUint16 ref0 = (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].x(), -1.0f, 1.0f) * 127.0f), -(1<<7), (1<<7)-1);
913 const deUint16 ref1 = (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].y(), -1.0f, 1.0f) * 127.0f), -(1<<7), (1<<7)-1);
914 const deUint16 ref2 = (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].z(), -1.0f, 1.0f) * 127.0f), -(1<<7), (1<<7)-1);
915 const deUint16 ref3 = (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].w(), -1.0f, 1.0f) * 127.0f), -(1<<7), (1<<7)-1);
916 const deUint32 ref = (deUint32(ref3) << 24) | (deUint32(ref2) << 16) | (deUint32(ref1) << 8) | deUint32(ref0);
917 const deUint32 res = outputs[valNdx];
918 const deUint16 res0 = (deUint8)(res & 0xff);
919 const deUint16 res1 = (deUint8)((res >> 8) & 0xff);
920 const deUint16 res2 = (deUint8)((res >> 16) & 0xff);
921 const deUint16 res3 = (deUint8)((res >> 24) & 0xff);
922 const int diff0 = de::abs((int)ref0 - (int)res0);
923 const int diff1 = de::abs((int)ref1 - (int)res1);
924 const int diff2 = de::abs((int)ref2 - (int)res2);
925 const int diff3 = de::abs((int)ref3 - (int)res3);
926
927 if (diff0 > maxDiff || diff1 > maxDiff || diff2 > maxDiff || diff3 > maxDiff)
928 {
929 if (numFailed < maxPrints)
930 {
931 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx
932 << ", expected packSnorm4x8(" << inputs[valNdx] << ") = " << tcu::toHex(ref)
933 << ", got " << tcu::toHex(res)
934 << "\n diffs = " << tcu::IVec4(diff0, diff1, diff2, diff3) << ", max diff = " << maxDiff
935 << TestLog::EndMessage;
936 }
937 else if (numFailed == maxPrints)
938 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
939
940 numFailed += 1;
941 }
942 }
943
944 m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
945
946 if (numFailed == 0)
947 return tcu::TestStatus::pass("Pass");
948 else
949 return tcu::TestStatus::fail("Result comparison failed");
950
951 }
952 }
953
954 private:
955 const glu::Precision m_precision;
956 };
957
958 class PackSnorm4x8Case : public ShaderPackingFunctionCase
959 {
960 public:
PackSnorm4x8Case(tcu::TestContext & testCtx,glu::ShaderType shaderType,glu::Precision precision)961 PackSnorm4x8Case (tcu::TestContext& testCtx, glu::ShaderType shaderType, glu::Precision precision)
962 : ShaderPackingFunctionCase (testCtx, (string("packsnorm4x8") + getPrecisionPostfix(precision) + getShaderTypePostfix(shaderType)).c_str(), "packSnorm4x8", shaderType)
963 , m_precision (precision)
964 {
965 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_FLOAT_VEC4, precision)));
966 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
967
968 m_spec.source = "out0 = packSnorm4x8(in0);";
969 }
970
createInstance(Context & ctx) const971 TestInstance* createInstance (Context& ctx) const
972 {
973 return new PackSnorm4x8CaseInstance(ctx, m_shaderType, m_spec, m_precision, getName());
974 }
975
976 private:
977 const glu::Precision m_precision;
978 };
979
980 class UnpackSnorm4x8CaseInstance : public ShaderPackingFunctionTestInstance
981 {
982 public:
UnpackSnorm4x8CaseInstance(Context & context,glu::ShaderType shaderType,const ShaderSpec & spec,const char * name)983 UnpackSnorm4x8CaseInstance (Context& context, glu::ShaderType shaderType, const ShaderSpec& spec, const char* name)
984 : ShaderPackingFunctionTestInstance (context, shaderType, spec, name)
985 {
986 }
987
iterate(void)988 tcu::TestStatus iterate (void)
989 {
990 const deUint32 maxDiff = 1; // Rounding error.
991 de::Random rnd (deStringHash(m_name) ^ 0x776002);
992 std::vector<deUint32> inputs;
993 std::vector<tcu::Vec4> outputs;
994
995 inputs.push_back(0x00000000u);
996 inputs.push_back(0x7fff8000u);
997 inputs.push_back(0x80007fffu);
998 inputs.push_back(0xffffffffu);
999 inputs.push_back(0x0001fffeu);
1000
1001 // Random values.
1002 for (int ndx = 0; ndx < 95; ndx++)
1003 inputs.push_back(rnd.getUint32());
1004
1005 outputs.resize(inputs.size());
1006
1007 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
1008
1009 {
1010 const void* in = &inputs[0];
1011 void* out = &outputs[0];
1012
1013 m_executor->execute((int)inputs.size(), &in, &out);
1014 }
1015
1016 // Verify
1017 {
1018 const int numValues = (int)inputs.size();
1019 const int maxPrints = 10;
1020 int numFailed = 0;
1021
1022 for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
1023 {
1024 const deInt8 in0 = (deInt8)(deUint8)(inputs[valNdx] & 0xff);
1025 const deInt8 in1 = (deInt8)(deUint8)((inputs[valNdx] >> 8) & 0xff);
1026 const deInt8 in2 = (deInt8)(deUint8)((inputs[valNdx] >> 16) & 0xff);
1027 const deInt8 in3 = (deInt8)(deUint8)(inputs[valNdx] >> 24);
1028 const float ref0 = de::clamp(float(in0) / 127.f, -1.0f, 1.0f);
1029 const float ref1 = de::clamp(float(in1) / 127.f, -1.0f, 1.0f);
1030 const float ref2 = de::clamp(float(in2) / 127.f, -1.0f, 1.0f);
1031 const float ref3 = de::clamp(float(in3) / 127.f, -1.0f, 1.0f);
1032 const float res0 = outputs[valNdx].x();
1033 const float res1 = outputs[valNdx].y();
1034 const float res2 = outputs[valNdx].z();
1035 const float res3 = outputs[valNdx].w();
1036
1037 const deUint32 diff0 = getUlpDiff(ref0, res0);
1038 const deUint32 diff1 = getUlpDiff(ref1, res1);
1039 const deUint32 diff2 = getUlpDiff(ref2, res2);
1040 const deUint32 diff3 = getUlpDiff(ref3, res3);
1041
1042 if (diff0 > maxDiff || diff1 > maxDiff || diff2 > maxDiff || diff3 > maxDiff)
1043 {
1044 if (numFailed < maxPrints)
1045 {
1046 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx << ",\n"
1047 << " expected unpackSnorm4x8(" << tcu::toHex(inputs[valNdx]) << ") = "
1048 << "vec4(" << HexFloat(ref0) << ", " << HexFloat(ref1) << ", " << HexFloat(ref2) << ", " << HexFloat(ref3) << ")"
1049 << ", got vec4(" << HexFloat(res0) << ", " << HexFloat(res1) << ", " << HexFloat(res2) << ", " << HexFloat(res3) << ")"
1050 << "\n ULP diffs = (" << diff0 << ", " << diff1 << ", " << diff2 << ", " << diff3 << "), max diff = " << maxDiff
1051 << TestLog::EndMessage;
1052 }
1053 else if (numFailed == maxPrints)
1054 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
1055
1056 numFailed += 1;
1057 }
1058 }
1059
1060 m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
1061
1062 if (numFailed == 0)
1063 return tcu::TestStatus::pass("Pass");
1064 else
1065 return tcu::TestStatus::fail("Result comparison failed");
1066
1067 }
1068 }
1069 };
1070
1071
1072 class UnpackSnorm4x8Case : public ShaderPackingFunctionCase
1073 {
1074 public:
UnpackSnorm4x8Case(tcu::TestContext & testCtx,glu::ShaderType shaderType)1075 UnpackSnorm4x8Case (tcu::TestContext& testCtx, glu::ShaderType shaderType)
1076 : ShaderPackingFunctionCase (testCtx, (string("unpacksnorm4x8") + getShaderTypePostfix(shaderType)).c_str(), "unpackSnorm4x8", shaderType)
1077 {
1078 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
1079 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP)));
1080
1081 m_spec.source = "out0 = unpackSnorm4x8(in0);";
1082 }
1083
createInstance(Context & ctx) const1084 TestInstance* createInstance (Context& ctx) const
1085 {
1086 return new UnpackSnorm4x8CaseInstance(ctx, m_shaderType, m_spec, getName());
1087 }
1088
1089 };
1090
1091 class PackUnorm4x8CaseInstance : public ShaderPackingFunctionTestInstance
1092 {
1093 public:
PackUnorm4x8CaseInstance(Context & context,glu::ShaderType shaderType,const ShaderSpec & spec,glu::Precision precision,const char * name)1094 PackUnorm4x8CaseInstance (Context& context, glu::ShaderType shaderType, const ShaderSpec& spec, glu::Precision precision, const char* name)
1095 : ShaderPackingFunctionTestInstance (context, shaderType, spec, name)
1096 , m_precision (precision)
1097 {
1098 }
1099
iterate(void)1100 tcu::TestStatus iterate (void)
1101 {
1102 de::Random rnd (deStringHash(m_name) ^ 0x776002);
1103 std::vector<tcu::Vec4> inputs;
1104 std::vector<deUint32> outputs;
1105 const int maxDiff = m_precision == glu::PRECISION_HIGHP ? 1 : // Rounding only.
1106 m_precision == glu::PRECISION_MEDIUMP ? 1 : // (2^-10) * (2^8) + 1
1107 m_precision == glu::PRECISION_LOWP ? 2 : 0; // (2^-8) * (2^8) + 1
1108
1109 // Special values to check.
1110 inputs.push_back(tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f));
1111 inputs.push_back(tcu::Vec4(-1.0f, 1.0f, -1.0f, 1.0f));
1112 inputs.push_back(tcu::Vec4(0.5f, -0.5f, -0.5f, 0.5f));
1113 inputs.push_back(tcu::Vec4(-1.5f, 1.5f, -1.5f, 1.5f));
1114 inputs.push_back(tcu::Vec4(0.25f, -0.75f, -0.25f, 0.75f));
1115
1116 // Random values, mostly in range.
1117 for (int ndx = 0; ndx < 15; ndx++)
1118 {
1119 const float x = rnd.getFloat()*1.25f - 0.125f;
1120 const float y = rnd.getFloat()*1.25f - 0.125f;
1121 const float z = rnd.getFloat()*1.25f - 0.125f;
1122 const float w = rnd.getFloat()*1.25f - 0.125f;
1123 inputs.push_back(tcu::Vec4(x, y, z, w));
1124 }
1125
1126 // Large random values.
1127 for (int ndx = 0; ndx < 80; ndx++)
1128 {
1129 const float x = rnd.getFloat()*1e6f - 1e5f;
1130 const float y = rnd.getFloat()*1e6f - 1e5f;
1131 const float z = rnd.getFloat()*1e6f - 1e5f;
1132 const float w = rnd.getFloat()*1e6f - 1e5f;
1133 inputs.push_back(tcu::Vec4(x, y, z, w));
1134 }
1135
1136 outputs.resize(inputs.size());
1137
1138 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
1139
1140 {
1141 const void* in = &inputs[0];
1142 void* out = &outputs[0];
1143
1144 m_executor->execute((int)inputs.size(), &in, &out);
1145 }
1146
1147 // Verify
1148 {
1149 const int numValues = (int)inputs.size();
1150 const int maxPrints = 10;
1151 int numFailed = 0;
1152
1153 for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
1154 {
1155 const deUint16 ref0 = (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].x(), 0.0f, 1.0f) * 255.0f), 0, (1<<8)-1);
1156 const deUint16 ref1 = (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].y(), 0.0f, 1.0f) * 255.0f), 0, (1<<8)-1);
1157 const deUint16 ref2 = (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].z(), 0.0f, 1.0f) * 255.0f), 0, (1<<8)-1);
1158 const deUint16 ref3 = (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].w(), 0.0f, 1.0f) * 255.0f), 0, (1<<8)-1);
1159 const deUint32 ref = (deUint32(ref3) << 24) | (deUint32(ref2) << 16) | (deUint32(ref1) << 8) | deUint32(ref0);
1160 const deUint32 res = outputs[valNdx];
1161 const deUint16 res0 = (deUint8)(res & 0xff);
1162 const deUint16 res1 = (deUint8)((res >> 8) & 0xff);
1163 const deUint16 res2 = (deUint8)((res >> 16) & 0xff);
1164 const deUint16 res3 = (deUint8)((res >> 24) & 0xff);
1165 const int diff0 = de::abs((int)ref0 - (int)res0);
1166 const int diff1 = de::abs((int)ref1 - (int)res1);
1167 const int diff2 = de::abs((int)ref2 - (int)res2);
1168 const int diff3 = de::abs((int)ref3 - (int)res3);
1169
1170 if (diff0 > maxDiff || diff1 > maxDiff || diff2 > maxDiff || diff3 > maxDiff)
1171 {
1172 if (numFailed < maxPrints)
1173 {
1174 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx
1175 << ", expected packUnorm4x8(" << inputs[valNdx] << ") = " << tcu::toHex(ref)
1176 << ", got " << tcu::toHex(res)
1177 << "\n diffs = " << tcu::IVec4(diff0, diff1, diff2, diff3) << ", max diff = " << maxDiff
1178 << TestLog::EndMessage;
1179 }
1180 else if (numFailed == maxPrints)
1181 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
1182
1183 numFailed += 1;
1184 }
1185 }
1186
1187 m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
1188
1189 if (numFailed == 0)
1190 return tcu::TestStatus::pass("Pass");
1191 else
1192 return tcu::TestStatus::fail("Result comparison failed");
1193
1194 }
1195 }
1196
1197 private:
1198 const glu::Precision m_precision;
1199 };
1200
1201 class PackUnorm4x8Case : public ShaderPackingFunctionCase
1202 {
1203 public:
PackUnorm4x8Case(tcu::TestContext & testCtx,glu::ShaderType shaderType,glu::Precision precision)1204 PackUnorm4x8Case (tcu::TestContext& testCtx, glu::ShaderType shaderType, glu::Precision precision)
1205 : ShaderPackingFunctionCase (testCtx, (string("packunorm4x8") + getPrecisionPostfix(precision) + getShaderTypePostfix(shaderType)).c_str(), "packUnorm4x8", shaderType)
1206 , m_precision (precision)
1207 {
1208 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_FLOAT_VEC4, precision)));
1209 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
1210
1211 m_spec.source = "out0 = packUnorm4x8(in0);";
1212 }
1213
createInstance(Context & ctx) const1214 TestInstance* createInstance (Context& ctx) const
1215 {
1216 return new PackUnorm4x8CaseInstance(ctx, m_shaderType, m_spec, m_precision, getName());
1217 }
1218
1219 private:
1220 const glu::Precision m_precision;
1221 };
1222
1223 class UnpackUnorm4x8CaseInstance : public ShaderPackingFunctionTestInstance
1224 {
1225 public:
UnpackUnorm4x8CaseInstance(Context & context,glu::ShaderType shaderType,const ShaderSpec & spec,const char * name)1226 UnpackUnorm4x8CaseInstance (Context& context, glu::ShaderType shaderType, const ShaderSpec& spec, const char* name)
1227 : ShaderPackingFunctionTestInstance (context, shaderType, spec, name)
1228 {
1229 }
1230
iterate(void)1231 tcu::TestStatus iterate (void)
1232 {
1233 const deUint32 maxDiff = 1; // Rounding error.
1234 de::Random rnd (deStringHash(m_name) ^ 0x776002);
1235 std::vector<deUint32> inputs;
1236 std::vector<tcu::Vec4> outputs;
1237
1238 inputs.push_back(0x00000000u);
1239 inputs.push_back(0x7fff8000u);
1240 inputs.push_back(0x80007fffu);
1241 inputs.push_back(0xffffffffu);
1242 inputs.push_back(0x0001fffeu);
1243
1244 // Random values.
1245 for (int ndx = 0; ndx < 95; ndx++)
1246 inputs.push_back(rnd.getUint32());
1247
1248 outputs.resize(inputs.size());
1249
1250 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
1251
1252 {
1253 const void* in = &inputs[0];
1254 void* out = &outputs[0];
1255
1256 m_executor->execute((int)inputs.size(), &in, &out);
1257 }
1258
1259 // Verify
1260 {
1261 const int numValues = (int)inputs.size();
1262 const int maxPrints = 10;
1263 int numFailed = 0;
1264
1265 for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
1266 {
1267 const deUint8 in0 = (deUint8)(inputs[valNdx] & 0xff);
1268 const deUint8 in1 = (deUint8)((inputs[valNdx] >> 8) & 0xff);
1269 const deUint8 in2 = (deUint8)((inputs[valNdx] >> 16) & 0xff);
1270 const deUint8 in3 = (deUint8)(inputs[valNdx] >> 24);
1271 const float ref0 = de::clamp(float(in0) / 255.f, 0.0f, 1.0f);
1272 const float ref1 = de::clamp(float(in1) / 255.f, 0.0f, 1.0f);
1273 const float ref2 = de::clamp(float(in2) / 255.f, 0.0f, 1.0f);
1274 const float ref3 = de::clamp(float(in3) / 255.f, 0.0f, 1.0f);
1275 const float res0 = outputs[valNdx].x();
1276 const float res1 = outputs[valNdx].y();
1277 const float res2 = outputs[valNdx].z();
1278 const float res3 = outputs[valNdx].w();
1279
1280 const deUint32 diff0 = getUlpDiff(ref0, res0);
1281 const deUint32 diff1 = getUlpDiff(ref1, res1);
1282 const deUint32 diff2 = getUlpDiff(ref2, res2);
1283 const deUint32 diff3 = getUlpDiff(ref3, res3);
1284
1285 if (diff0 > maxDiff || diff1 > maxDiff || diff2 > maxDiff || diff3 > maxDiff)
1286 {
1287 if (numFailed < maxPrints)
1288 {
1289 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx << ",\n"
1290 << " expected unpackUnorm4x8(" << tcu::toHex(inputs[valNdx]) << ") = "
1291 << "vec4(" << HexFloat(ref0) << ", " << HexFloat(ref1) << ", " << HexFloat(ref2) << ", " << HexFloat(ref3) << ")"
1292 << ", got vec4(" << HexFloat(res0) << ", " << HexFloat(res1) << ", " << HexFloat(res2) << ", " << HexFloat(res3) << ")"
1293 << "\n ULP diffs = (" << diff0 << ", " << diff1 << ", " << diff2 << ", " << diff3 << "), max diff = " << maxDiff
1294 << TestLog::EndMessage;
1295 }
1296 else if (numFailed == maxPrints)
1297 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
1298
1299 numFailed += 1;
1300 }
1301 }
1302
1303 m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
1304
1305 if (numFailed == 0)
1306 return tcu::TestStatus::pass("Pass");
1307 else
1308 return tcu::TestStatus::fail("Result comparison failed");
1309
1310 }
1311 }
1312 };
1313
1314 class UnpackUnorm4x8Case : public ShaderPackingFunctionCase
1315 {
1316 public:
UnpackUnorm4x8Case(tcu::TestContext & testCtx,glu::ShaderType shaderType)1317 UnpackUnorm4x8Case (tcu::TestContext& testCtx, glu::ShaderType shaderType)
1318 : ShaderPackingFunctionCase (testCtx, (string("unpackunorm4x8") + getShaderTypePostfix(shaderType)).c_str(), "unpackUnorm4x8", shaderType)
1319 {
1320 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
1321 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP)));
1322
1323 m_spec.source = "out0 = unpackUnorm4x8(in0);";
1324 }
1325
createInstance(Context & ctx) const1326 TestInstance* createInstance (Context& ctx) const
1327 {
1328 return new UnpackUnorm4x8CaseInstance(ctx, m_shaderType, m_spec, getName());
1329 }
1330
1331 };
1332
ShaderPackingFunctionTests(tcu::TestContext & testCtx)1333 ShaderPackingFunctionTests::ShaderPackingFunctionTests (tcu::TestContext& testCtx)
1334 : tcu::TestCaseGroup (testCtx, "pack_unpack", "Floating-point pack and unpack function tests")
1335 {
1336 }
1337
~ShaderPackingFunctionTests(void)1338 ShaderPackingFunctionTests::~ShaderPackingFunctionTests (void)
1339 {
1340 }
1341
init(void)1342 void ShaderPackingFunctionTests::init (void)
1343 {
1344 // New built-in functions in GLES 3.1
1345 {
1346 const glu::ShaderType allShaderTypes[] =
1347 {
1348 glu::SHADERTYPE_VERTEX,
1349 glu::SHADERTYPE_TESSELLATION_CONTROL,
1350 glu::SHADERTYPE_TESSELLATION_EVALUATION,
1351 glu::SHADERTYPE_GEOMETRY,
1352 glu::SHADERTYPE_FRAGMENT,
1353 glu::SHADERTYPE_COMPUTE
1354 };
1355
1356 // packSnorm4x8
1357 for (int prec = glu::PRECISION_MEDIUMP; prec < glu::PRECISION_LAST; prec++)
1358 {
1359 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(allShaderTypes); shaderTypeNdx++)
1360 addChild(new PackSnorm4x8Case(m_testCtx, allShaderTypes[shaderTypeNdx], glu::Precision(prec)));
1361 }
1362
1363 // unpackSnorm4x8
1364 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(allShaderTypes); shaderTypeNdx++)
1365 addChild(new UnpackSnorm4x8Case(m_testCtx, allShaderTypes[shaderTypeNdx]));
1366
1367 // packUnorm4x8
1368 for (int prec = glu::PRECISION_MEDIUMP; prec < glu::PRECISION_LAST; prec++)
1369 {
1370 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(allShaderTypes); shaderTypeNdx++)
1371 addChild(new PackUnorm4x8Case(m_testCtx, allShaderTypes[shaderTypeNdx], glu::Precision(prec)));
1372 }
1373
1374 // unpackUnorm4x8
1375 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(allShaderTypes); shaderTypeNdx++)
1376 addChild(new UnpackUnorm4x8Case(m_testCtx, allShaderTypes[shaderTypeNdx]));
1377 }
1378
1379 // GLES 3 functions in new shader types.
1380 {
1381 const glu::ShaderType newShaderTypes[] =
1382 {
1383 glu::SHADERTYPE_GEOMETRY,
1384 glu::SHADERTYPE_COMPUTE
1385 };
1386
1387 // packSnorm2x16
1388 for (int prec = glu::PRECISION_MEDIUMP; prec < glu::PRECISION_LAST; prec++)
1389 {
1390 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(newShaderTypes); shaderTypeNdx++)
1391 addChild(new PackSnorm2x16Case(m_testCtx, newShaderTypes[shaderTypeNdx], glu::Precision(prec)));
1392 }
1393
1394 // unpackSnorm2x16
1395 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(newShaderTypes); shaderTypeNdx++)
1396 addChild(new UnpackSnorm2x16Case(m_testCtx, newShaderTypes[shaderTypeNdx]));
1397
1398 // packUnorm2x16
1399 for (int prec = glu::PRECISION_MEDIUMP; prec < glu::PRECISION_LAST; prec++)
1400 {
1401 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(newShaderTypes); shaderTypeNdx++)
1402 addChild(new PackUnorm2x16Case(m_testCtx, newShaderTypes[shaderTypeNdx], glu::Precision(prec)));
1403 }
1404
1405 // unpackUnorm2x16
1406 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(newShaderTypes); shaderTypeNdx++)
1407 addChild(new UnpackUnorm2x16Case(m_testCtx, newShaderTypes[shaderTypeNdx]));
1408
1409 // packHalf2x16
1410 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(newShaderTypes); shaderTypeNdx++)
1411 addChild(new PackHalf2x16Case(m_testCtx, newShaderTypes[shaderTypeNdx]));
1412
1413 // unpackHalf2x16
1414 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(newShaderTypes); shaderTypeNdx++)
1415 addChild(new UnpackHalf2x16Case(m_testCtx, newShaderTypes[shaderTypeNdx]));
1416 }
1417 }
1418
1419 } // shaderexecutor
1420 } // vkt
1421