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