1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 3.1 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 "es31fShaderPackingFunctionTests.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 gles31
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::gles31::Functional::__anonf0671f880111::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::getContextTypeGLSLVersion(context.getRenderContext().getType());
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
751 class PackSnorm4x8Case : public ShaderPackingFunctionCase
752 {
753 public:
PackSnorm4x8Case(Context & context,glu::ShaderType shaderType,glu::Precision precision)754 PackSnorm4x8Case(Context &context, glu::ShaderType shaderType, glu::Precision precision)
755 : ShaderPackingFunctionCase(
756 context,
757 (string("packsnorm4x8") + getPrecisionPostfix(precision) + getShaderTypePostfix(shaderType)).c_str(),
758 "packSnorm4x8", shaderType)
759 , m_precision(precision)
760 {
761 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_FLOAT_VEC4, precision)));
762 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
763
764 m_spec.source = "out0 = packSnorm4x8(in0);";
765 }
766
iterate(void)767 IterateResult iterate(void)
768 {
769 de::Random rnd(deStringHash(getName()) ^ 0x42f2c0);
770 std::vector<tcu::Vec4> inputs;
771 std::vector<uint32_t> outputs;
772 const int maxDiff = m_precision == glu::PRECISION_HIGHP ? 1 : // Rounding only.
773 m_precision == glu::PRECISION_MEDIUMP ? 1 : // (2^-10) * (2^7) + 1
774 m_precision == glu::PRECISION_LOWP ? 2 : 0; // (2^-8) * (2^7) + 1
775
776 // Special values to check.
777 inputs.push_back(tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f));
778 inputs.push_back(tcu::Vec4(-1.0f, 1.0f, -1.0f, 1.0f));
779 inputs.push_back(tcu::Vec4(0.5f, -0.5f, -0.5f, 0.5f));
780 inputs.push_back(tcu::Vec4(-1.5f, 1.5f, -1.5f, 1.5f));
781 inputs.push_back(tcu::Vec4(0.25f, -0.75f, -0.25f, 0.75f));
782
783 // Random values, mostly in range.
784 for (int ndx = 0; ndx < 15; ndx++)
785 {
786 const float x = rnd.getFloat() * 2.5f - 1.25f;
787 const float y = rnd.getFloat() * 2.5f - 1.25f;
788 const float z = rnd.getFloat() * 2.5f - 1.25f;
789 const float w = rnd.getFloat() * 2.5f - 1.25f;
790 inputs.push_back(tcu::Vec4(x, y, z, w));
791 }
792
793 // Large random values.
794 for (int ndx = 0; ndx < 80; ndx++)
795 {
796 const float x = rnd.getFloat() * 1e6f - 0.5e6f;
797 const float y = rnd.getFloat() * 1e6f - 0.5e6f;
798 const float z = rnd.getFloat() * 1e6f - 0.5e6f;
799 const float w = rnd.getFloat() * 1e6f - 0.5e6f;
800 inputs.push_back(tcu::Vec4(x, y, z, w));
801 }
802
803 outputs.resize(inputs.size());
804
805 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values"
806 << tcu::TestLog::EndMessage;
807
808 {
809 const void *in = &inputs[0];
810 void *out = &outputs[0];
811
812 m_executor->useProgram();
813 m_executor->execute((int)inputs.size(), &in, &out);
814 }
815
816 // Verify
817 {
818 const int numValues = (int)inputs.size();
819 const int maxPrints = 10;
820 int numFailed = 0;
821
822 for (int valNdx = 0; valNdx < numValues; valNdx++)
823 {
824 const uint16_t ref0 = (uint8_t)de::clamp(
825 deRoundFloatToInt32(de::clamp(inputs[valNdx].x(), -1.0f, 1.0f) * 127.0f), -(1 << 7), (1 << 7) - 1);
826 const uint16_t ref1 = (uint8_t)de::clamp(
827 deRoundFloatToInt32(de::clamp(inputs[valNdx].y(), -1.0f, 1.0f) * 127.0f), -(1 << 7), (1 << 7) - 1);
828 const uint16_t ref2 = (uint8_t)de::clamp(
829 deRoundFloatToInt32(de::clamp(inputs[valNdx].z(), -1.0f, 1.0f) * 127.0f), -(1 << 7), (1 << 7) - 1);
830 const uint16_t ref3 = (uint8_t)de::clamp(
831 deRoundFloatToInt32(de::clamp(inputs[valNdx].w(), -1.0f, 1.0f) * 127.0f), -(1 << 7), (1 << 7) - 1);
832 const uint32_t ref =
833 (uint32_t(ref3) << 24) | (uint32_t(ref2) << 16) | (uint32_t(ref1) << 8) | uint32_t(ref0);
834 const uint32_t res = outputs[valNdx];
835 const uint16_t res0 = (uint8_t)(res & 0xff);
836 const uint16_t res1 = (uint8_t)((res >> 8) & 0xff);
837 const uint16_t res2 = (uint8_t)((res >> 16) & 0xff);
838 const uint16_t res3 = (uint8_t)((res >> 24) & 0xff);
839 const int diff0 = de::abs((int)ref0 - (int)res0);
840 const int diff1 = de::abs((int)ref1 - (int)res1);
841 const int diff2 = de::abs((int)ref2 - (int)res2);
842 const int diff3 = de::abs((int)ref3 - (int)res3);
843
844 if (diff0 > maxDiff || diff1 > maxDiff || diff2 > maxDiff || diff3 > maxDiff)
845 {
846 if (numFailed < maxPrints)
847 {
848 m_testCtx.getLog()
849 << TestLog::Message << "ERROR: Mismatch in value " << valNdx << ", expected packSnorm4x8("
850 << inputs[valNdx] << ") = " << tcu::toHex(ref) << ", got " << tcu::toHex(res)
851 << "\n diffs = " << tcu::IVec4(diff0, diff1, diff2, diff3) << ", max diff = " << maxDiff
852 << TestLog::EndMessage;
853 }
854 else if (numFailed == maxPrints)
855 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
856
857 numFailed += 1;
858 }
859 }
860
861 m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed"
862 << TestLog::EndMessage;
863
864 m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL,
865 numFailed == 0 ? "Pass" : "Result comparison failed");
866 }
867
868 return STOP;
869 }
870
871 private:
872 glu::Precision m_precision;
873 };
874
875 class UnpackSnorm4x8Case : public ShaderPackingFunctionCase
876 {
877 public:
UnpackSnorm4x8Case(Context & context,glu::ShaderType shaderType)878 UnpackSnorm4x8Case(Context &context, glu::ShaderType shaderType)
879 : ShaderPackingFunctionCase(context, (string("unpacksnorm4x8") + getShaderTypePostfix(shaderType)).c_str(),
880 "unpackSnorm4x8", shaderType)
881 {
882 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
883 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP)));
884
885 m_spec.source = "out0 = unpackSnorm4x8(in0);";
886 }
887
iterate(void)888 IterateResult iterate(void)
889 {
890 const uint32_t maxDiff = 1; // Rounding error.
891 de::Random rnd(deStringHash(getName()) ^ 0x776002);
892 std::vector<uint32_t> inputs;
893 std::vector<tcu::Vec4> outputs;
894
895 inputs.push_back(0x00000000u);
896 inputs.push_back(0x7fff8000u);
897 inputs.push_back(0x80007fffu);
898 inputs.push_back(0xffffffffu);
899 inputs.push_back(0x0001fffeu);
900
901 // Random values.
902 for (int ndx = 0; ndx < 95; ndx++)
903 inputs.push_back(rnd.getUint32());
904
905 outputs.resize(inputs.size());
906
907 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values"
908 << tcu::TestLog::EndMessage;
909
910 {
911 const void *in = &inputs[0];
912 void *out = &outputs[0];
913
914 m_executor->useProgram();
915 m_executor->execute((int)inputs.size(), &in, &out);
916 }
917
918 // Verify
919 {
920 const int numValues = (int)inputs.size();
921 const int maxPrints = 10;
922 int numFailed = 0;
923
924 for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
925 {
926 const int8_t in0 = (int8_t)(uint8_t)(inputs[valNdx] & 0xff);
927 const int8_t in1 = (int8_t)(uint8_t)((inputs[valNdx] >> 8) & 0xff);
928 const int8_t in2 = (int8_t)(uint8_t)((inputs[valNdx] >> 16) & 0xff);
929 const int8_t in3 = (int8_t)(uint8_t)(inputs[valNdx] >> 24);
930 const float ref0 = de::clamp(float(in0) / 127.f, -1.0f, 1.0f);
931 const float ref1 = de::clamp(float(in1) / 127.f, -1.0f, 1.0f);
932 const float ref2 = de::clamp(float(in2) / 127.f, -1.0f, 1.0f);
933 const float ref3 = de::clamp(float(in3) / 127.f, -1.0f, 1.0f);
934 const float res0 = outputs[valNdx].x();
935 const float res1 = outputs[valNdx].y();
936 const float res2 = outputs[valNdx].z();
937 const float res3 = outputs[valNdx].w();
938
939 const uint32_t diff0 = getUlpDiff(ref0, res0);
940 const uint32_t diff1 = getUlpDiff(ref1, res1);
941 const uint32_t diff2 = getUlpDiff(ref2, res2);
942 const uint32_t diff3 = getUlpDiff(ref3, res3);
943
944 if (diff0 > maxDiff || diff1 > maxDiff || diff2 > maxDiff || diff3 > maxDiff)
945 {
946 if (numFailed < maxPrints)
947 {
948 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx << ",\n"
949 << " expected unpackSnorm4x8(" << tcu::toHex(inputs[valNdx]) << ") = "
950 << "vec4(" << HexFloat(ref0) << ", " << HexFloat(ref1) << ", "
951 << HexFloat(ref2) << ", " << HexFloat(ref3) << ")"
952 << ", got vec4(" << HexFloat(res0) << ", " << HexFloat(res1) << ", "
953 << HexFloat(res2) << ", " << HexFloat(res3) << ")"
954 << "\n ULP diffs = (" << diff0 << ", " << diff1 << ", " << diff2 << ", "
955 << diff3 << "), max diff = " << maxDiff << TestLog::EndMessage;
956 }
957 else if (numFailed == maxPrints)
958 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
959
960 numFailed += 1;
961 }
962 }
963
964 m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed"
965 << TestLog::EndMessage;
966
967 m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL,
968 numFailed == 0 ? "Pass" : "Result comparison failed");
969 }
970
971 return STOP;
972 }
973 };
974
975 class PackUnorm4x8Case : public ShaderPackingFunctionCase
976 {
977 public:
PackUnorm4x8Case(Context & context,glu::ShaderType shaderType,glu::Precision precision)978 PackUnorm4x8Case(Context &context, glu::ShaderType shaderType, glu::Precision precision)
979 : ShaderPackingFunctionCase(
980 context,
981 (string("packunorm4x8") + getPrecisionPostfix(precision) + getShaderTypePostfix(shaderType)).c_str(),
982 "packUnorm4x8", shaderType)
983 , m_precision(precision)
984 {
985 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_FLOAT_VEC4, precision)));
986 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
987
988 m_spec.source = "out0 = packUnorm4x8(in0);";
989 }
990
iterate(void)991 IterateResult iterate(void)
992 {
993 de::Random rnd(deStringHash(getName()) ^ 0x776002);
994 std::vector<tcu::Vec4> inputs;
995 std::vector<uint32_t> outputs;
996 const int maxDiff = m_precision == glu::PRECISION_HIGHP ? 1 : // Rounding only.
997 m_precision == glu::PRECISION_MEDIUMP ? 1 : // (2^-10) * (2^8) + 1
998 m_precision == glu::PRECISION_LOWP ? 2 : 0; // (2^-8) * (2^8) + 1
999
1000 // Special values to check.
1001 inputs.push_back(tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f));
1002 inputs.push_back(tcu::Vec4(-1.0f, 1.0f, -1.0f, 1.0f));
1003 inputs.push_back(tcu::Vec4(0.5f, -0.5f, -0.5f, 0.5f));
1004 inputs.push_back(tcu::Vec4(-1.5f, 1.5f, -1.5f, 1.5f));
1005 inputs.push_back(tcu::Vec4(0.25f, -0.75f, -0.25f, 0.75f));
1006
1007 // Random values, mostly in range.
1008 for (int ndx = 0; ndx < 15; ndx++)
1009 {
1010 const float x = rnd.getFloat() * 1.25f - 0.125f;
1011 const float y = rnd.getFloat() * 1.25f - 0.125f;
1012 const float z = rnd.getFloat() * 1.25f - 0.125f;
1013 const float w = rnd.getFloat() * 1.25f - 0.125f;
1014 inputs.push_back(tcu::Vec4(x, y, z, w));
1015 }
1016
1017 // Large random values.
1018 for (int ndx = 0; ndx < 80; ndx++)
1019 {
1020 const float x = rnd.getFloat() * 1e6f - 1e5f;
1021 const float y = rnd.getFloat() * 1e6f - 1e5f;
1022 const float z = rnd.getFloat() * 1e6f - 1e5f;
1023 const float w = rnd.getFloat() * 1e6f - 1e5f;
1024 inputs.push_back(tcu::Vec4(x, y, z, w));
1025 }
1026
1027 outputs.resize(inputs.size());
1028
1029 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values"
1030 << tcu::TestLog::EndMessage;
1031
1032 {
1033 const void *in = &inputs[0];
1034 void *out = &outputs[0];
1035
1036 m_executor->useProgram();
1037 m_executor->execute((int)inputs.size(), &in, &out);
1038 }
1039
1040 // Verify
1041 {
1042 const int numValues = (int)inputs.size();
1043 const int maxPrints = 10;
1044 int numFailed = 0;
1045
1046 for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
1047 {
1048 const uint16_t ref0 = (uint8_t)de::clamp(
1049 deRoundFloatToInt32(de::clamp(inputs[valNdx].x(), 0.0f, 1.0f) * 255.0f), 0, (1 << 8) - 1);
1050 const uint16_t ref1 = (uint8_t)de::clamp(
1051 deRoundFloatToInt32(de::clamp(inputs[valNdx].y(), 0.0f, 1.0f) * 255.0f), 0, (1 << 8) - 1);
1052 const uint16_t ref2 = (uint8_t)de::clamp(
1053 deRoundFloatToInt32(de::clamp(inputs[valNdx].z(), 0.0f, 1.0f) * 255.0f), 0, (1 << 8) - 1);
1054 const uint16_t ref3 = (uint8_t)de::clamp(
1055 deRoundFloatToInt32(de::clamp(inputs[valNdx].w(), 0.0f, 1.0f) * 255.0f), 0, (1 << 8) - 1);
1056 const uint32_t ref =
1057 (uint32_t(ref3) << 24) | (uint32_t(ref2) << 16) | (uint32_t(ref1) << 8) | uint32_t(ref0);
1058 const uint32_t res = outputs[valNdx];
1059 const uint16_t res0 = (uint8_t)(res & 0xff);
1060 const uint16_t res1 = (uint8_t)((res >> 8) & 0xff);
1061 const uint16_t res2 = (uint8_t)((res >> 16) & 0xff);
1062 const uint16_t res3 = (uint8_t)((res >> 24) & 0xff);
1063 const int diff0 = de::abs((int)ref0 - (int)res0);
1064 const int diff1 = de::abs((int)ref1 - (int)res1);
1065 const int diff2 = de::abs((int)ref2 - (int)res2);
1066 const int diff3 = de::abs((int)ref3 - (int)res3);
1067
1068 if (diff0 > maxDiff || diff1 > maxDiff || diff2 > maxDiff || diff3 > maxDiff)
1069 {
1070 if (numFailed < maxPrints)
1071 {
1072 m_testCtx.getLog()
1073 << TestLog::Message << "ERROR: Mismatch in value " << valNdx << ", expected packUnorm4x8("
1074 << inputs[valNdx] << ") = " << tcu::toHex(ref) << ", got " << tcu::toHex(res)
1075 << "\n diffs = " << tcu::IVec4(diff0, diff1, diff2, diff3) << ", max diff = " << maxDiff
1076 << TestLog::EndMessage;
1077 }
1078 else if (numFailed == maxPrints)
1079 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
1080
1081 numFailed += 1;
1082 }
1083 }
1084
1085 m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed"
1086 << TestLog::EndMessage;
1087
1088 m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL,
1089 numFailed == 0 ? "Pass" : "Result comparison failed");
1090 }
1091
1092 return STOP;
1093 }
1094
1095 private:
1096 glu::Precision m_precision;
1097 };
1098
1099 class UnpackUnorm4x8Case : public ShaderPackingFunctionCase
1100 {
1101 public:
UnpackUnorm4x8Case(Context & context,glu::ShaderType shaderType)1102 UnpackUnorm4x8Case(Context &context, glu::ShaderType shaderType)
1103 : ShaderPackingFunctionCase(context, (string("unpackunorm4x8") + getShaderTypePostfix(shaderType)).c_str(),
1104 "unpackUnorm4x8", shaderType)
1105 {
1106 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
1107 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP)));
1108
1109 m_spec.source = "out0 = unpackUnorm4x8(in0);";
1110 }
1111
iterate(void)1112 IterateResult iterate(void)
1113 {
1114 const uint32_t maxDiff = 1; // Rounding error.
1115 de::Random rnd(deStringHash(getName()) ^ 0x776002);
1116 std::vector<uint32_t> inputs;
1117 std::vector<tcu::Vec4> outputs;
1118
1119 inputs.push_back(0x00000000u);
1120 inputs.push_back(0x7fff8000u);
1121 inputs.push_back(0x80007fffu);
1122 inputs.push_back(0xffffffffu);
1123 inputs.push_back(0x0001fffeu);
1124
1125 // Random values.
1126 for (int ndx = 0; ndx < 95; ndx++)
1127 inputs.push_back(rnd.getUint32());
1128
1129 outputs.resize(inputs.size());
1130
1131 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values"
1132 << tcu::TestLog::EndMessage;
1133
1134 {
1135 const void *in = &inputs[0];
1136 void *out = &outputs[0];
1137
1138 m_executor->useProgram();
1139 m_executor->execute((int)inputs.size(), &in, &out);
1140 }
1141
1142 // Verify
1143 {
1144 const int numValues = (int)inputs.size();
1145 const int maxPrints = 10;
1146 int numFailed = 0;
1147
1148 for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
1149 {
1150 const uint8_t in0 = (uint8_t)(inputs[valNdx] & 0xff);
1151 const uint8_t in1 = (uint8_t)((inputs[valNdx] >> 8) & 0xff);
1152 const uint8_t in2 = (uint8_t)((inputs[valNdx] >> 16) & 0xff);
1153 const uint8_t in3 = (uint8_t)(inputs[valNdx] >> 24);
1154 const float ref0 = de::clamp(float(in0) / 255.f, 0.0f, 1.0f);
1155 const float ref1 = de::clamp(float(in1) / 255.f, 0.0f, 1.0f);
1156 const float ref2 = de::clamp(float(in2) / 255.f, 0.0f, 1.0f);
1157 const float ref3 = de::clamp(float(in3) / 255.f, 0.0f, 1.0f);
1158 const float res0 = outputs[valNdx].x();
1159 const float res1 = outputs[valNdx].y();
1160 const float res2 = outputs[valNdx].z();
1161 const float res3 = outputs[valNdx].w();
1162
1163 const uint32_t diff0 = getUlpDiff(ref0, res0);
1164 const uint32_t diff1 = getUlpDiff(ref1, res1);
1165 const uint32_t diff2 = getUlpDiff(ref2, res2);
1166 const uint32_t diff3 = getUlpDiff(ref3, res3);
1167
1168 if (diff0 > maxDiff || diff1 > maxDiff || diff2 > maxDiff || diff3 > maxDiff)
1169 {
1170 if (numFailed < maxPrints)
1171 {
1172 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx << ",\n"
1173 << " expected unpackUnorm4x8(" << tcu::toHex(inputs[valNdx]) << ") = "
1174 << "vec4(" << HexFloat(ref0) << ", " << HexFloat(ref1) << ", "
1175 << HexFloat(ref2) << ", " << HexFloat(ref3) << ")"
1176 << ", got vec4(" << HexFloat(res0) << ", " << HexFloat(res1) << ", "
1177 << HexFloat(res2) << ", " << HexFloat(res3) << ")"
1178 << "\n ULP diffs = (" << diff0 << ", " << diff1 << ", " << diff2 << ", "
1179 << diff3 << "), max diff = " << maxDiff << TestLog::EndMessage;
1180 }
1181 else if (numFailed == maxPrints)
1182 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
1183
1184 numFailed += 1;
1185 }
1186 }
1187
1188 m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed"
1189 << TestLog::EndMessage;
1190
1191 m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL,
1192 numFailed == 0 ? "Pass" : "Result comparison failed");
1193 }
1194
1195 return STOP;
1196 }
1197 };
1198
ShaderPackingFunctionTests(Context & context)1199 ShaderPackingFunctionTests::ShaderPackingFunctionTests(Context &context)
1200 : TestCaseGroup(context, "pack_unpack", "Floating-point pack and unpack function tests")
1201 {
1202 }
1203
~ShaderPackingFunctionTests(void)1204 ShaderPackingFunctionTests::~ShaderPackingFunctionTests(void)
1205 {
1206 }
1207
init(void)1208 void ShaderPackingFunctionTests::init(void)
1209 {
1210 // New built-in functions in GLES 3.1
1211 {
1212 const glu::ShaderType allShaderTypes[] = {glu::SHADERTYPE_VERTEX,
1213 glu::SHADERTYPE_TESSELLATION_CONTROL,
1214 glu::SHADERTYPE_TESSELLATION_EVALUATION,
1215 glu::SHADERTYPE_GEOMETRY,
1216 glu::SHADERTYPE_FRAGMENT,
1217 glu::SHADERTYPE_COMPUTE};
1218
1219 // packSnorm4x8
1220 for (int prec = 0; prec < glu::PRECISION_LAST; prec++)
1221 {
1222 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(allShaderTypes); shaderTypeNdx++)
1223 addChild(new PackSnorm4x8Case(m_context, allShaderTypes[shaderTypeNdx], glu::Precision(prec)));
1224 }
1225
1226 // unpackSnorm4x8
1227 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(allShaderTypes); shaderTypeNdx++)
1228 addChild(new UnpackSnorm4x8Case(m_context, allShaderTypes[shaderTypeNdx]));
1229
1230 // packUnorm4x8
1231 for (int prec = 0; prec < glu::PRECISION_LAST; prec++)
1232 {
1233 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(allShaderTypes); shaderTypeNdx++)
1234 addChild(new PackUnorm4x8Case(m_context, allShaderTypes[shaderTypeNdx], glu::Precision(prec)));
1235 }
1236
1237 // unpackUnorm4x8
1238 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(allShaderTypes); shaderTypeNdx++)
1239 addChild(new UnpackUnorm4x8Case(m_context, allShaderTypes[shaderTypeNdx]));
1240 }
1241
1242 // GLES 3 functions in new shader types.
1243 {
1244 const glu::ShaderType newShaderTypes[] = {glu::SHADERTYPE_GEOMETRY, glu::SHADERTYPE_COMPUTE};
1245
1246 // packSnorm2x16
1247 for (int prec = 0; prec < glu::PRECISION_LAST; prec++)
1248 {
1249 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(newShaderTypes); shaderTypeNdx++)
1250 addChild(new PackSnorm2x16Case(m_context, newShaderTypes[shaderTypeNdx], glu::Precision(prec)));
1251 }
1252
1253 // unpackSnorm2x16
1254 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(newShaderTypes); shaderTypeNdx++)
1255 addChild(new UnpackSnorm2x16Case(m_context, newShaderTypes[shaderTypeNdx]));
1256
1257 // packUnorm2x16
1258 for (int prec = 0; prec < glu::PRECISION_LAST; prec++)
1259 {
1260 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(newShaderTypes); shaderTypeNdx++)
1261 addChild(new PackUnorm2x16Case(m_context, newShaderTypes[shaderTypeNdx], glu::Precision(prec)));
1262 }
1263
1264 // unpackUnorm2x16
1265 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(newShaderTypes); shaderTypeNdx++)
1266 addChild(new UnpackUnorm2x16Case(m_context, newShaderTypes[shaderTypeNdx]));
1267
1268 // packHalf2x16
1269 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(newShaderTypes); shaderTypeNdx++)
1270 addChild(new PackHalf2x16Case(m_context, newShaderTypes[shaderTypeNdx]));
1271
1272 // unpackHalf2x16
1273 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(newShaderTypes); shaderTypeNdx++)
1274 addChild(new UnpackHalf2x16Case(m_context, newShaderTypes[shaderTypeNdx]));
1275 }
1276 }
1277
1278 } // namespace Functional
1279 } // namespace gles31
1280 } // namespace deqp
1281