1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 3.0 Module
3 * -------------------------------------------------
4 *
5 * Copyright 2014 The Android Open Source Project
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief Floating-point packing and unpacking function tests.
22 *//*--------------------------------------------------------------------*/
23
24 #include "es3fShaderPackingFunctionTests.hpp"
25 #include "glsShaderExecUtil.hpp"
26 #include "tcuTestLog.hpp"
27 #include "tcuFormatUtil.hpp"
28 #include "tcuFloat.hpp"
29 #include "deRandom.hpp"
30 #include "deMath.h"
31 #include "deString.h"
32
33 namespace deqp
34 {
35 namespace gles3
36 {
37 namespace Functional
38 {
39
40 using std::string;
41 using tcu::TestLog;
42 using namespace gls::ShaderExecUtil;
43
44 namespace
45 {
46
getUlpDiff(float a,float b)47 inline uint32_t getUlpDiff(float a, float b)
48 {
49 const uint32_t aBits = tcu::Float32(a).bits();
50 const uint32_t bBits = tcu::Float32(b).bits();
51 return aBits > bBits ? aBits - bBits : bBits - aBits;
52 }
53
54 struct HexFloat
55 {
56 const float value;
HexFloatdeqp::gles3::Functional::__anone8a9cc660111::HexFloat57 HexFloat(const float value_) : value(value_)
58 {
59 }
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
67 } // namespace
68
69 // ShaderPackingFunctionCase
70
71 class ShaderPackingFunctionCase : public TestCase
72 {
73 public:
74 ShaderPackingFunctionCase(Context &context, const char *name, const char *description, glu::ShaderType shaderType);
75 ~ShaderPackingFunctionCase(void);
76
77 void init(void);
78 void deinit(void);
79
80 protected:
81 glu::ShaderType m_shaderType;
82 ShaderSpec m_spec;
83 ShaderExecutor *m_executor;
84
85 private:
86 ShaderPackingFunctionCase(const ShaderPackingFunctionCase &other);
87 ShaderPackingFunctionCase &operator=(const ShaderPackingFunctionCase &other);
88 };
89
ShaderPackingFunctionCase(Context & context,const char * name,const char * description,glu::ShaderType shaderType)90 ShaderPackingFunctionCase::ShaderPackingFunctionCase(Context &context, const char *name, const char *description,
91 glu::ShaderType shaderType)
92 : TestCase(context, name, description)
93 , m_shaderType(shaderType)
94 , m_executor(DE_NULL)
95 {
96 m_spec.version = glu::GLSL_VERSION_300_ES;
97 }
98
~ShaderPackingFunctionCase(void)99 ShaderPackingFunctionCase::~ShaderPackingFunctionCase(void)
100 {
101 ShaderPackingFunctionCase::deinit();
102 }
103
init(void)104 void ShaderPackingFunctionCase::init(void)
105 {
106 DE_ASSERT(!m_executor);
107
108 m_executor = createExecutor(m_context.getRenderContext(), m_shaderType, m_spec);
109 m_testCtx.getLog() << m_executor;
110
111 if (!m_executor->isOk())
112 throw tcu::TestError("Compile failed");
113 }
114
deinit(void)115 void ShaderPackingFunctionCase::deinit(void)
116 {
117 delete m_executor;
118 m_executor = DE_NULL;
119 }
120
121 // Test cases
122
123 class PackSnorm2x16Case : public ShaderPackingFunctionCase
124 {
125 public:
PackSnorm2x16Case(Context & context,glu::ShaderType shaderType,glu::Precision precision)126 PackSnorm2x16Case(Context &context, glu::ShaderType shaderType, glu::Precision precision)
127 : ShaderPackingFunctionCase(
128 context,
129 (string("packsnorm2x16") + getPrecisionPostfix(precision) + getShaderTypePostfix(shaderType)).c_str(),
130 "packSnorm2x16", shaderType)
131 , m_precision(precision)
132 {
133 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_FLOAT_VEC2, precision)));
134 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
135
136 m_spec.source = "out0 = packSnorm2x16(in0);";
137 }
138
iterate(void)139 IterateResult iterate(void)
140 {
141 de::Random rnd(deStringHash(getName()) ^ 0x776002);
142 std::vector<tcu::Vec2> inputs;
143 std::vector<uint32_t> outputs;
144 const int maxDiff = m_precision == glu::PRECISION_HIGHP ? 1 : // Rounding only.
145 m_precision == glu::PRECISION_MEDIUMP ? 33 : // (2^-10) * (2^15) + 1
146 m_precision == glu::PRECISION_LOWP ? 129 : 0; // (2^-8) * (2^15) + 1
147
148 // Special values to check.
149 inputs.push_back(tcu::Vec2(0.0f, 0.0f));
150 inputs.push_back(tcu::Vec2(-1.0f, 1.0f));
151 inputs.push_back(tcu::Vec2(0.5f, -0.5f));
152 inputs.push_back(tcu::Vec2(-1.5f, 1.5f));
153 inputs.push_back(tcu::Vec2(0.25f, -0.75f));
154
155 // Random values, mostly in range.
156 for (int ndx = 0; ndx < 15; ndx++)
157 {
158 const float x = rnd.getFloat() * 2.5f - 1.25f;
159 const float y = rnd.getFloat() * 2.5f - 1.25f;
160 inputs.push_back(tcu::Vec2(x, y));
161 }
162
163 // Large random values.
164 for (int ndx = 0; ndx < 80; ndx++)
165 {
166 const float x = rnd.getFloat() * 1e6f - 0.5e6f;
167 const float y = rnd.getFloat() * 1e6f - 0.5e6f;
168 inputs.push_back(tcu::Vec2(x, y));
169 }
170
171 outputs.resize(inputs.size());
172
173 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values"
174 << tcu::TestLog::EndMessage;
175
176 {
177 const void *in = &inputs[0];
178 void *out = &outputs[0];
179
180 m_executor->useProgram();
181 m_executor->execute((int)inputs.size(), &in, &out);
182 }
183
184 // Verify
185 {
186 const int numValues = (int)inputs.size();
187 const int maxPrints = 10;
188 int numFailed = 0;
189
190 for (int valNdx = 0; valNdx < numValues; valNdx++)
191 {
192 const uint16_t ref0 =
193 (uint16_t)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].x(), -1.0f, 1.0f) * 32767.0f),
194 -(1 << 15), (1 << 15) - 1);
195 const uint16_t ref1 =
196 (uint16_t)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].y(), -1.0f, 1.0f) * 32767.0f),
197 -(1 << 15), (1 << 15) - 1);
198 const uint32_t ref = (ref1 << 16) | ref0;
199 const uint32_t res = outputs[valNdx];
200 const uint16_t res0 = (uint16_t)(res & 0xffff);
201 const uint16_t res1 = (uint16_t)(res >> 16);
202 const int diff0 = de::abs((int)ref0 - (int)res0);
203 const int diff1 = de::abs((int)ref1 - (int)res1);
204
205 if (diff0 > maxDiff || diff1 > maxDiff)
206 {
207 if (numFailed < maxPrints)
208 {
209 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx
210 << ", expected packSnorm2x16(" << inputs[valNdx] << ") = " << tcu::toHex(ref)
211 << ", got " << tcu::toHex(res) << "\n diffs = (" << diff0 << ", " << diff1
212 << "), max diff = " << maxDiff << TestLog::EndMessage;
213 }
214 else if (numFailed == maxPrints)
215 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
216
217 numFailed += 1;
218 }
219 }
220
221 m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed"
222 << TestLog::EndMessage;
223
224 m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL,
225 numFailed == 0 ? "Pass" : "Result comparison failed");
226 }
227
228 return STOP;
229 }
230
231 private:
232 glu::Precision m_precision;
233 };
234
235 class UnpackSnorm2x16Case : public ShaderPackingFunctionCase
236 {
237 public:
UnpackSnorm2x16Case(Context & context,glu::ShaderType shaderType)238 UnpackSnorm2x16Case(Context &context, glu::ShaderType shaderType)
239 : ShaderPackingFunctionCase(context, (string("unpacksnorm2x16") + getShaderTypePostfix(shaderType)).c_str(),
240 "unpackSnorm2x16", shaderType)
241 {
242 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
243 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_FLOAT_VEC2, glu::PRECISION_HIGHP)));
244
245 m_spec.source = "out0 = unpackSnorm2x16(in0);";
246 }
247
iterate(void)248 IterateResult iterate(void)
249 {
250 const uint32_t maxDiff = 1; // Rounding error.
251 de::Random rnd(deStringHash(getName()) ^ 0x776002);
252 std::vector<uint32_t> inputs;
253 std::vector<tcu::Vec2> outputs;
254
255 inputs.push_back(0x00000000u);
256 inputs.push_back(0x7fff8000u);
257 inputs.push_back(0x80007fffu);
258 inputs.push_back(0xffffffffu);
259 inputs.push_back(0x0001fffeu);
260
261 // Random values.
262 for (int ndx = 0; ndx < 95; ndx++)
263 inputs.push_back(rnd.getUint32());
264
265 outputs.resize(inputs.size());
266
267 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values"
268 << tcu::TestLog::EndMessage;
269
270 {
271 const void *in = &inputs[0];
272 void *out = &outputs[0];
273
274 m_executor->useProgram();
275 m_executor->execute((int)inputs.size(), &in, &out);
276 }
277
278 // Verify
279 {
280 const int numValues = (int)inputs.size();
281 const int maxPrints = 10;
282 int numFailed = 0;
283
284 for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
285 {
286 const int16_t in0 = (int16_t)(uint16_t)(inputs[valNdx] & 0xffff);
287 const int16_t in1 = (int16_t)(uint16_t)(inputs[valNdx] >> 16);
288 const float ref0 = de::clamp(float(in0) / 32767.f, -1.0f, 1.0f);
289 const float ref1 = de::clamp(float(in1) / 32767.f, -1.0f, 1.0f);
290 const float res0 = outputs[valNdx].x();
291 const float res1 = outputs[valNdx].y();
292
293 const uint32_t diff0 = getUlpDiff(ref0, res0);
294 const uint32_t diff1 = getUlpDiff(ref1, res1);
295
296 if (diff0 > maxDiff || diff1 > maxDiff)
297 {
298 if (numFailed < maxPrints)
299 {
300 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx << ",\n"
301 << " expected unpackSnorm2x16(" << tcu::toHex(inputs[valNdx]) << ") = "
302 << "vec2(" << HexFloat(ref0) << ", " << HexFloat(ref1) << ")"
303 << ", got vec2(" << HexFloat(res0) << ", " << HexFloat(res1) << ")"
304 << "\n ULP diffs = (" << diff0 << ", " << diff1
305 << "), max diff = " << maxDiff << TestLog::EndMessage;
306 }
307 else if (numFailed == maxPrints)
308 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
309
310 numFailed += 1;
311 }
312 }
313
314 m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed"
315 << TestLog::EndMessage;
316
317 m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL,
318 numFailed == 0 ? "Pass" : "Result comparison failed");
319 }
320
321 return STOP;
322 }
323 };
324
325 class PackUnorm2x16Case : public ShaderPackingFunctionCase
326 {
327 public:
PackUnorm2x16Case(Context & context,glu::ShaderType shaderType,glu::Precision precision)328 PackUnorm2x16Case(Context &context, glu::ShaderType shaderType, glu::Precision precision)
329 : ShaderPackingFunctionCase(
330 context,
331 (string("packunorm2x16") + getPrecisionPostfix(precision) + getShaderTypePostfix(shaderType)).c_str(),
332 "packUnorm2x16", shaderType)
333 , m_precision(precision)
334 {
335 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_FLOAT_VEC2, precision)));
336 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
337
338 m_spec.source = "out0 = packUnorm2x16(in0);";
339 }
340
iterate(void)341 IterateResult iterate(void)
342 {
343 de::Random rnd(deStringHash(getName()) ^ 0x776002);
344 std::vector<tcu::Vec2> inputs;
345 std::vector<uint32_t> outputs;
346 const int maxDiff = m_precision == glu::PRECISION_HIGHP ? 1 : // Rounding only.
347 m_precision == glu::PRECISION_MEDIUMP ? 65 : // (2^-10) * (2^16) + 1
348 m_precision == glu::PRECISION_LOWP ? 257 : 0; // (2^-8) * (2^16) + 1
349
350 // Special values to check.
351 inputs.push_back(tcu::Vec2(0.0f, 0.0f));
352 inputs.push_back(tcu::Vec2(0.5f, 1.0f));
353 inputs.push_back(tcu::Vec2(1.0f, 0.5f));
354 inputs.push_back(tcu::Vec2(-0.5f, 1.5f));
355 inputs.push_back(tcu::Vec2(0.25f, 0.75f));
356
357 // Random values, mostly in range.
358 for (int ndx = 0; ndx < 15; ndx++)
359 {
360 const float x = rnd.getFloat() * 1.25f;
361 const float y = rnd.getFloat() * 1.25f;
362 inputs.push_back(tcu::Vec2(x, y));
363 }
364
365 // Large random values.
366 for (int ndx = 0; ndx < 80; ndx++)
367 {
368 const float x = rnd.getFloat() * 1e6f - 1e5f;
369 const float y = rnd.getFloat() * 1e6f - 1e5f;
370 inputs.push_back(tcu::Vec2(x, y));
371 }
372
373 outputs.resize(inputs.size());
374
375 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values"
376 << tcu::TestLog::EndMessage;
377
378 {
379 const void *in = &inputs[0];
380 void *out = &outputs[0];
381
382 m_executor->useProgram();
383 m_executor->execute((int)inputs.size(), &in, &out);
384 }
385
386 // Verify
387 {
388 const int numValues = (int)inputs.size();
389 const int maxPrints = 10;
390 int numFailed = 0;
391
392 for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
393 {
394 const uint16_t ref0 = (uint16_t)de::clamp(
395 deRoundFloatToInt32(de::clamp(inputs[valNdx].x(), 0.0f, 1.0f) * 65535.0f), 0, (1 << 16) - 1);
396 const uint16_t ref1 = (uint16_t)de::clamp(
397 deRoundFloatToInt32(de::clamp(inputs[valNdx].y(), 0.0f, 1.0f) * 65535.0f), 0, (1 << 16) - 1);
398 const uint32_t ref = (ref1 << 16) | ref0;
399 const uint32_t res = outputs[valNdx];
400 const uint16_t res0 = (uint16_t)(res & 0xffff);
401 const uint16_t res1 = (uint16_t)(res >> 16);
402 const int diff0 = de::abs((int)ref0 - (int)res0);
403 const int diff1 = de::abs((int)ref1 - (int)res1);
404
405 if (diff0 > maxDiff || diff1 > maxDiff)
406 {
407 if (numFailed < maxPrints)
408 {
409 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx
410 << ", expected packUnorm2x16(" << inputs[valNdx] << ") = " << tcu::toHex(ref)
411 << ", got " << tcu::toHex(res) << "\n diffs = (" << diff0 << ", " << diff1
412 << "), max diff = " << maxDiff << TestLog::EndMessage;
413 }
414 else if (numFailed == maxPrints)
415 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
416
417 numFailed += 1;
418 }
419 }
420
421 m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed"
422 << TestLog::EndMessage;
423
424 m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL,
425 numFailed == 0 ? "Pass" : "Result comparison failed");
426 }
427
428 return STOP;
429 }
430
431 private:
432 glu::Precision m_precision;
433 };
434
435 class UnpackUnorm2x16Case : public ShaderPackingFunctionCase
436 {
437 public:
UnpackUnorm2x16Case(Context & context,glu::ShaderType shaderType)438 UnpackUnorm2x16Case(Context &context, glu::ShaderType shaderType)
439 : ShaderPackingFunctionCase(context, (string("unpackunorm2x16") + getShaderTypePostfix(shaderType)).c_str(),
440 "unpackUnorm2x16", shaderType)
441 {
442 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
443 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_FLOAT_VEC2, glu::PRECISION_HIGHP)));
444
445 m_spec.source = "out0 = unpackUnorm2x16(in0);";
446 }
447
iterate(void)448 IterateResult iterate(void)
449 {
450 const uint32_t maxDiff = 1; // Rounding error.
451 de::Random rnd(deStringHash(getName()) ^ 0x776002);
452 std::vector<uint32_t> inputs;
453 std::vector<tcu::Vec2> outputs;
454
455 inputs.push_back(0x00000000u);
456 inputs.push_back(0x7fff8000u);
457 inputs.push_back(0x80007fffu);
458 inputs.push_back(0xffffffffu);
459 inputs.push_back(0x0001fffeu);
460
461 // Random values.
462 for (int ndx = 0; ndx < 95; ndx++)
463 inputs.push_back(rnd.getUint32());
464
465 outputs.resize(inputs.size());
466
467 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values"
468 << tcu::TestLog::EndMessage;
469
470 {
471 const void *in = &inputs[0];
472 void *out = &outputs[0];
473
474 m_executor->useProgram();
475 m_executor->execute((int)inputs.size(), &in, &out);
476 }
477
478 // Verify
479 {
480 const int numValues = (int)inputs.size();
481 const int maxPrints = 10;
482 int numFailed = 0;
483
484 for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
485 {
486 const uint16_t in0 = (uint16_t)(inputs[valNdx] & 0xffff);
487 const uint16_t in1 = (uint16_t)(inputs[valNdx] >> 16);
488 const float ref0 = float(in0) / 65535.0f;
489 const float ref1 = float(in1) / 65535.0f;
490 const float res0 = outputs[valNdx].x();
491 const float res1 = outputs[valNdx].y();
492
493 const uint32_t diff0 = getUlpDiff(ref0, res0);
494 const uint32_t diff1 = getUlpDiff(ref1, res1);
495
496 if (diff0 > maxDiff || diff1 > maxDiff)
497 {
498 if (numFailed < maxPrints)
499 {
500 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx << ",\n"
501 << " expected unpackUnorm2x16(" << tcu::toHex(inputs[valNdx]) << ") = "
502 << "vec2(" << HexFloat(ref0) << ", " << HexFloat(ref1) << ")"
503 << ", got vec2(" << HexFloat(res0) << ", " << HexFloat(res1) << ")"
504 << "\n ULP diffs = (" << diff0 << ", " << diff1
505 << "), max diff = " << maxDiff << TestLog::EndMessage;
506 }
507 else if (numFailed == maxPrints)
508 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
509
510 numFailed += 1;
511 }
512 }
513
514 m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed"
515 << TestLog::EndMessage;
516
517 m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL,
518 numFailed == 0 ? "Pass" : "Result comparison failed");
519 }
520
521 return STOP;
522 }
523 };
524
525 class PackHalf2x16Case : public ShaderPackingFunctionCase
526 {
527 public:
PackHalf2x16Case(Context & context,glu::ShaderType shaderType)528 PackHalf2x16Case(Context &context, glu::ShaderType shaderType)
529 : ShaderPackingFunctionCase(context, (string("packhalf2x16") + getShaderTypePostfix(shaderType)).c_str(),
530 "packHalf2x16", shaderType)
531 {
532 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_FLOAT_VEC2, glu::PRECISION_HIGHP)));
533 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
534
535 m_spec.source = "out0 = packHalf2x16(in0);";
536 }
537
iterate(void)538 IterateResult iterate(void)
539 {
540 const int maxDiff = 0; // Values can be represented exactly in mediump.
541 de::Random rnd(deStringHash(getName()) ^ 0x776002);
542 std::vector<tcu::Vec2> inputs;
543 std::vector<uint32_t> outputs;
544
545 // Special values to check.
546 inputs.push_back(tcu::Vec2(0.0f, 0.0f));
547 inputs.push_back(tcu::Vec2(0.5f, 1.0f));
548 inputs.push_back(tcu::Vec2(1.0f, 0.5f));
549 inputs.push_back(tcu::Vec2(-0.5f, 1.5f));
550 inputs.push_back(tcu::Vec2(0.25f, 0.75f));
551
552 // Random values.
553 {
554 const int minExp = -14;
555 const int maxExp = 15;
556
557 for (int ndx = 0; ndx < 95; ndx++)
558 {
559 tcu::Vec2 v;
560 for (int c = 0; c < 2; c++)
561 {
562 const int s = rnd.getBool() ? 1 : -1;
563 const int exp = rnd.getInt(minExp, maxExp);
564 const uint32_t mantissa = rnd.getUint32() & ((1 << 23) - 1);
565
566 v[c] = tcu::Float32::construct(s, exp ? exp : 1 /* avoid denormals */, (1u << 23) | mantissa)
567 .asFloat();
568 }
569 inputs.push_back(v);
570 }
571 }
572
573 // Convert input values to fp16 and back to make sure they can be represented exactly in mediump.
574 for (std::vector<tcu::Vec2>::iterator inVal = inputs.begin(); inVal != inputs.end(); ++inVal)
575 *inVal = tcu::Vec2(tcu::Float16(inVal->x()).asFloat(), tcu::Float16(inVal->y()).asFloat());
576
577 outputs.resize(inputs.size());
578
579 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values"
580 << tcu::TestLog::EndMessage;
581
582 {
583 const void *in = &inputs[0];
584 void *out = &outputs[0];
585
586 m_executor->useProgram();
587 m_executor->execute((int)inputs.size(), &in, &out);
588 }
589
590 // Verify
591 {
592 const int numValues = (int)inputs.size();
593 const int maxPrints = 10;
594 int numFailed = 0;
595
596 for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
597 {
598 const uint16_t ref0 = (uint16_t)tcu::Float16(inputs[valNdx].x()).bits();
599 const uint16_t ref1 = (uint16_t)tcu::Float16(inputs[valNdx].y()).bits();
600 const uint32_t ref = (ref1 << 16) | ref0;
601 const uint32_t res = outputs[valNdx];
602 const uint16_t res0 = (uint16_t)(res & 0xffff);
603 const uint16_t res1 = (uint16_t)(res >> 16);
604 const int diff0 = de::abs((int)ref0 - (int)res0);
605 const int diff1 = de::abs((int)ref1 - (int)res1);
606
607 if (diff0 > maxDiff || diff1 > maxDiff)
608 {
609 if (numFailed < maxPrints)
610 {
611 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx
612 << ", expected packHalf2x16(" << inputs[valNdx] << ") = " << tcu::toHex(ref)
613 << ", got " << tcu::toHex(res) << "\n diffs = (" << diff0 << ", " << diff1
614 << "), max diff = " << maxDiff << TestLog::EndMessage;
615 }
616 else if (numFailed == maxPrints)
617 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
618
619 numFailed += 1;
620 }
621 }
622
623 m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed"
624 << TestLog::EndMessage;
625
626 m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL,
627 numFailed == 0 ? "Pass" : "Result comparison failed");
628 }
629
630 return STOP;
631 }
632 };
633
634 class UnpackHalf2x16Case : public ShaderPackingFunctionCase
635 {
636 public:
UnpackHalf2x16Case(Context & context,glu::ShaderType shaderType)637 UnpackHalf2x16Case(Context &context, glu::ShaderType shaderType)
638 : ShaderPackingFunctionCase(context, (string("unpackhalf2x16") + getShaderTypePostfix(shaderType)).c_str(),
639 "unpackHalf2x16", shaderType)
640 {
641 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
642 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_FLOAT_VEC2, glu::PRECISION_MEDIUMP)));
643
644 m_spec.source = "out0 = unpackHalf2x16(in0);";
645 }
646
iterate(void)647 IterateResult iterate(void)
648 {
649 const int maxDiff = 0; // All bits must be accurate.
650 de::Random rnd(deStringHash(getName()) ^ 0x776002);
651 std::vector<uint32_t> inputs;
652 std::vector<tcu::Vec2> outputs;
653
654 // Special values.
655 inputs.push_back((tcu::Float16(0.0f).bits() << 16) | tcu::Float16(1.0f).bits());
656 inputs.push_back((tcu::Float16(1.0f).bits() << 16) | tcu::Float16(0.0f).bits());
657 inputs.push_back((tcu::Float16(-1.0f).bits() << 16) | tcu::Float16(0.5f).bits());
658 inputs.push_back((tcu::Float16(0.5f).bits() << 16) | tcu::Float16(-0.5f).bits());
659
660 // Construct random values.
661 {
662 const int minExp = -14;
663 const int maxExp = 15;
664 const int mantBits = 10;
665
666 for (int ndx = 0; ndx < 96; ndx++)
667 {
668 uint32_t inVal = 0;
669 for (int c = 0; c < 2; c++)
670 {
671 const int s = rnd.getBool() ? 1 : -1;
672 const int exp = rnd.getInt(minExp, maxExp);
673 const uint32_t mantissa = rnd.getUint32() & ((1 << mantBits) - 1);
674 const uint16_t value =
675 tcu::Float16::construct(s, exp ? exp : 1 /* avoid denorm */, (uint16_t)((1u << 10) | mantissa))
676 .bits();
677
678 inVal |= value << (16 * c);
679 }
680 inputs.push_back(inVal);
681 }
682 }
683
684 outputs.resize(inputs.size());
685
686 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values"
687 << tcu::TestLog::EndMessage;
688
689 {
690 const void *in = &inputs[0];
691 void *out = &outputs[0];
692
693 m_executor->useProgram();
694 m_executor->execute((int)inputs.size(), &in, &out);
695 }
696
697 // Verify
698 {
699 const int numValues = (int)inputs.size();
700 const int maxPrints = 10;
701 int numFailed = 0;
702
703 for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
704 {
705 const uint16_t in0 = (uint16_t)(inputs[valNdx] & 0xffff);
706 const uint16_t in1 = (uint16_t)(inputs[valNdx] >> 16);
707 const float ref0 = tcu::Float16(in0).asFloat();
708 const float ref1 = tcu::Float16(in1).asFloat();
709 const float res0 = outputs[valNdx].x();
710 const float res1 = outputs[valNdx].y();
711
712 const uint32_t refBits0 = tcu::Float32(ref0).bits();
713 const uint32_t refBits1 = tcu::Float32(ref1).bits();
714 const uint32_t resBits0 = tcu::Float32(res0).bits();
715 const uint32_t resBits1 = tcu::Float32(res1).bits();
716
717 const int diff0 = de::abs((int)refBits0 - (int)resBits0);
718 const int diff1 = de::abs((int)refBits1 - (int)resBits1);
719
720 if (diff0 > maxDiff || diff1 > maxDiff)
721 {
722 if (numFailed < maxPrints)
723 {
724 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx << ",\n"
725 << " expected unpackHalf2x16(" << tcu::toHex(inputs[valNdx]) << ") = "
726 << "vec2(" << ref0 << " / " << tcu::toHex(refBits0) << ", " << ref1 << " / "
727 << tcu::toHex(refBits1) << ")"
728 << ", got vec2(" << res0 << " / " << tcu::toHex(resBits0) << ", " << res1
729 << " / " << tcu::toHex(resBits1) << ")"
730 << "\n ULP diffs = (" << diff0 << ", " << diff1
731 << "), max diff = " << maxDiff << TestLog::EndMessage;
732 }
733 else if (numFailed == maxPrints)
734 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
735
736 numFailed += 1;
737 }
738 }
739
740 m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed"
741 << TestLog::EndMessage;
742
743 m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL,
744 numFailed == 0 ? "Pass" : "Result comparison failed");
745 }
746
747 return STOP;
748 }
749 };
750
ShaderPackingFunctionTests(Context & context)751 ShaderPackingFunctionTests::ShaderPackingFunctionTests(Context &context)
752 : TestCaseGroup(context, "pack_unpack", "Floating-point pack and unpack function tests")
753 {
754 }
755
~ShaderPackingFunctionTests(void)756 ShaderPackingFunctionTests::~ShaderPackingFunctionTests(void)
757 {
758 }
759
init(void)760 void ShaderPackingFunctionTests::init(void)
761 {
762 addChild(new PackSnorm2x16Case(m_context, glu::SHADERTYPE_VERTEX, glu::PRECISION_LOWP));
763 addChild(new PackSnorm2x16Case(m_context, glu::SHADERTYPE_FRAGMENT, glu::PRECISION_LOWP));
764 addChild(new PackSnorm2x16Case(m_context, glu::SHADERTYPE_VERTEX, glu::PRECISION_MEDIUMP));
765 addChild(new PackSnorm2x16Case(m_context, glu::SHADERTYPE_FRAGMENT, glu::PRECISION_MEDIUMP));
766 addChild(new PackSnorm2x16Case(m_context, glu::SHADERTYPE_VERTEX, glu::PRECISION_HIGHP));
767 addChild(new PackSnorm2x16Case(m_context, glu::SHADERTYPE_FRAGMENT, glu::PRECISION_HIGHP));
768
769 addChild(new UnpackSnorm2x16Case(m_context, glu::SHADERTYPE_VERTEX));
770 addChild(new UnpackSnorm2x16Case(m_context, glu::SHADERTYPE_FRAGMENT));
771
772 addChild(new PackUnorm2x16Case(m_context, glu::SHADERTYPE_VERTEX, glu::PRECISION_LOWP));
773 addChild(new PackUnorm2x16Case(m_context, glu::SHADERTYPE_FRAGMENT, glu::PRECISION_LOWP));
774 addChild(new PackUnorm2x16Case(m_context, glu::SHADERTYPE_VERTEX, glu::PRECISION_MEDIUMP));
775 addChild(new PackUnorm2x16Case(m_context, glu::SHADERTYPE_FRAGMENT, glu::PRECISION_MEDIUMP));
776 addChild(new PackUnorm2x16Case(m_context, glu::SHADERTYPE_VERTEX, glu::PRECISION_HIGHP));
777 addChild(new PackUnorm2x16Case(m_context, glu::SHADERTYPE_FRAGMENT, glu::PRECISION_HIGHP));
778
779 addChild(new UnpackUnorm2x16Case(m_context, glu::SHADERTYPE_VERTEX));
780 addChild(new UnpackUnorm2x16Case(m_context, glu::SHADERTYPE_FRAGMENT));
781
782 addChild(new PackHalf2x16Case(m_context, glu::SHADERTYPE_VERTEX));
783 addChild(new PackHalf2x16Case(m_context, glu::SHADERTYPE_FRAGMENT));
784
785 addChild(new UnpackHalf2x16Case(m_context, glu::SHADERTYPE_VERTEX));
786 addChild(new UnpackHalf2x16Case(m_context, glu::SHADERTYPE_FRAGMENT));
787 }
788
789 } // namespace Functional
790 } // namespace gles3
791 } // namespace deqp
792