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