1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 3.0 Module
3 * -------------------------------------------------
5 * Copyright 2014 The Android Open Source Project
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 * \brief Floating-point packing and unpacking function tests.
22 *//*--------------------------------------------------------------------*/
24 #include "es3fShaderPackingFunctionTests.hpp"
25 #include "glsShaderExecUtil.hpp"
26 #include "tcuTestLog.hpp"
27 #include "tcuFormatUtil.hpp"
28 #include "tcuFloat.hpp"
29 #include "deRandom.hpp"
42 using namespace gls::ShaderExecUtil;
47 inline deUint32 getUlpDiff (float a, float b)
49 const deUint32 aBits = tcu::Float32(a).bits();
50 const deUint32 bBits = tcu::Float32(b).bits();
51 return aBits > bBits ? aBits - bBits : bBits - aBits;
57 HexFloat (const float value_) : value(value_) {}
60 std::ostream& operator<< (std::ostream& str, const HexFloat& v)
62 return str << v.value << " / " << tcu::toHex(tcu::Float32(v.value).bits());
67 // ShaderPackingFunctionCase
69 class ShaderPackingFunctionCase : public TestCase
72 ShaderPackingFunctionCase (Context& context, const char* name, const char* description, glu::ShaderType shaderType);
73 ~ShaderPackingFunctionCase (void);
79 glu::ShaderType m_shaderType;
81 ShaderExecutor* m_executor;
84 ShaderPackingFunctionCase (const ShaderPackingFunctionCase& other);
85 ShaderPackingFunctionCase& operator= (const ShaderPackingFunctionCase& other);
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)
93 m_spec.version = glu::GLSL_VERSION_300_ES;
96 ShaderPackingFunctionCase::~ShaderPackingFunctionCase (void)
98 ShaderPackingFunctionCase::deinit();
101 void ShaderPackingFunctionCase::init (void)
103 DE_ASSERT(!m_executor);
105 m_executor = createExecutor(m_context.getRenderContext(), m_shaderType, m_spec);
106 m_testCtx.getLog() << m_executor;
108 if (!m_executor->isOk())
109 throw tcu::TestError("Compile failed");
112 void ShaderPackingFunctionCase::deinit (void)
115 m_executor = DE_NULL;
120 static const char* getPrecisionPostfix (glu::Precision precision)
122 static const char* s_postfix[] =
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];
133 static const char* getShaderTypePostfix (glu::ShaderType shaderType)
135 static const char* s_postfix[] =
140 DE_ASSERT(de::inBounds<int>(shaderType, 0, DE_LENGTH_OF_ARRAY(s_postfix)));
141 return s_postfix[shaderType];
144 class PackSnorm2x16Case : public ShaderPackingFunctionCase
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)
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)));
154 m_spec.source = "out0 = packSnorm2x16(in0);";
157 IterateResult iterate (void)
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
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));
173 // Random values, mostly in range.
174 for (int ndx = 0; ndx < 15; ndx++)
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));
181 // Large random values.
182 for (int ndx = 0; ndx < 80; ndx++)
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));
189 outputs.resize(inputs.size());
191 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
194 const void* in = &inputs[0];
195 void* out = &outputs[0];
197 m_executor->useProgram();
198 m_executor->execute((int)inputs.size(), &in, &out);
203 const int numValues = (int)inputs.size();
204 const int maxPrints = 10;
207 for (int valNdx = 0; valNdx < numValues; valNdx++)
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);
218 if (diff0 > maxDiff || diff1 > maxDiff)
220 if (numFailed < maxPrints)
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;
228 else if (numFailed == maxPrints)
229 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
235 m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
237 m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL,
238 numFailed == 0 ? "Pass" : "Result comparison failed");
245 glu::Precision m_precision;
248 class UnpackSnorm2x16Case : public ShaderPackingFunctionCase
251 UnpackSnorm2x16Case (Context& context, glu::ShaderType shaderType)
252 : ShaderPackingFunctionCase(context, (string("unpacksnorm2x16") + getShaderTypePostfix(shaderType)).c_str(), "unpackSnorm2x16", shaderType)
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)));
257 m_spec.source = "out0 = unpackSnorm2x16(in0);";
260 IterateResult iterate (void)
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;
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);
274 for (int ndx = 0; ndx < 95; ndx++)
275 inputs.push_back(rnd.getUint32());
277 outputs.resize(inputs.size());
279 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
282 const void* in = &inputs[0];
283 void* out = &outputs[0];
285 m_executor->useProgram();
286 m_executor->execute((int)inputs.size(), &in, &out);
291 const int numValues = (int)inputs.size();
292 const int maxPrints = 10;
295 for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
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();
304 const deUint32 diff0 = getUlpDiff(ref0, res0);
305 const deUint32 diff1 = getUlpDiff(ref1, res1);
307 if (diff0 > maxDiff || diff1 > maxDiff)
309 if (numFailed < maxPrints)
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;
318 else if (numFailed == maxPrints)
319 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
325 m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
327 m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL,
328 numFailed == 0 ? "Pass" : "Result comparison failed");
335 class PackUnorm2x16Case : public ShaderPackingFunctionCase
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)
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)));
345 m_spec.source = "out0 = packUnorm2x16(in0);";
348 IterateResult iterate (void)
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
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));
364 // Random values, mostly in range.
365 for (int ndx = 0; ndx < 15; ndx++)
367 const float x = rnd.getFloat()*1.25f;
368 const float y = rnd.getFloat()*1.25f;
369 inputs.push_back(tcu::Vec2(x, y));
372 // Large random values.
373 for (int ndx = 0; ndx < 80; ndx++)
375 const float x = rnd.getFloat()*1e6f - 1e5f;
376 const float y = rnd.getFloat()*1e6f - 1e5f;
377 inputs.push_back(tcu::Vec2(x, y));
380 outputs.resize(inputs.size());
382 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
385 const void* in = &inputs[0];
386 void* out = &outputs[0];
388 m_executor->useProgram();
389 m_executor->execute((int)inputs.size(), &in, &out);
394 const int numValues = (int)inputs.size();
395 const int maxPrints = 10;
398 for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
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);
409 if (diff0 > maxDiff || diff1 > maxDiff)
411 if (numFailed < maxPrints)
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;
419 else if (numFailed == maxPrints)
420 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
426 m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
428 m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL,
429 numFailed == 0 ? "Pass" : "Result comparison failed");
436 glu::Precision m_precision;
439 class UnpackUnorm2x16Case : public ShaderPackingFunctionCase
442 UnpackUnorm2x16Case (Context& context, glu::ShaderType shaderType)
443 : ShaderPackingFunctionCase(context, (string("unpackunorm2x16") + getShaderTypePostfix(shaderType)).c_str(), "unpackUnorm2x16", shaderType)
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)));
448 m_spec.source = "out0 = unpackUnorm2x16(in0);";
451 IterateResult iterate (void)
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;
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);
465 for (int ndx = 0; ndx < 95; ndx++)
466 inputs.push_back(rnd.getUint32());
468 outputs.resize(inputs.size());
470 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
473 const void* in = &inputs[0];
474 void* out = &outputs[0];
476 m_executor->useProgram();
477 m_executor->execute((int)inputs.size(), &in, &out);
482 const int numValues = (int)inputs.size();
483 const int maxPrints = 10;
486 for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
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();
495 const deUint32 diff0 = getUlpDiff(ref0, res0);
496 const deUint32 diff1 = getUlpDiff(ref1, res1);
498 if (diff0 > maxDiff || diff1 > maxDiff)
500 if (numFailed < maxPrints)
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;
509 else if (numFailed == maxPrints)
510 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
516 m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
518 m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL,
519 numFailed == 0 ? "Pass" : "Result comparison failed");
526 class PackHalf2x16Case : public ShaderPackingFunctionCase
529 PackHalf2x16Case (Context& context, glu::ShaderType shaderType)
530 : ShaderPackingFunctionCase(context, (string("packhalf2x16") + getShaderTypePostfix(shaderType)).c_str(), "packHalf2x16", shaderType)
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)));
535 m_spec.source = "out0 = packHalf2x16(in0);";
538 IterateResult iterate (void)
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;
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));
554 const int minExp = -14;
555 const int maxExp = 15;
557 for (int ndx = 0; ndx < 95; ndx++)
560 for (int c = 0; c < 2; c++)
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);
566 v[c] = tcu::Float32::construct(s, exp ? exp : 1 /* avoid denormals */, (1u<<23) | mantissa).asFloat();
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());
576 outputs.resize(inputs.size());
578 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
581 const void* in = &inputs[0];
582 void* out = &outputs[0];
584 m_executor->useProgram();
585 m_executor->execute((int)inputs.size(), &in, &out);
590 const int numValues = (int)inputs.size();
591 const int maxPrints = 10;
594 for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
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);
605 if (diff0 > maxDiff || diff1 > maxDiff)
607 if (numFailed < maxPrints)
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;
615 else if (numFailed == maxPrints)
616 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
622 m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
624 m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL,
625 numFailed == 0 ? "Pass" : "Result comparison failed");
632 class UnpackHalf2x16Case : public ShaderPackingFunctionCase
635 UnpackHalf2x16Case (Context& context, glu::ShaderType shaderType)
636 : ShaderPackingFunctionCase(context, (string("unpackhalf2x16") + getShaderTypePostfix(shaderType)).c_str(), "unpackHalf2x16", shaderType)
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)));
641 m_spec.source = "out0 = unpackHalf2x16(in0);";
644 IterateResult iterate (void)
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;
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());
657 // Construct random values.
659 const int minExp = -14;
660 const int maxExp = 15;
661 const int mantBits = 10;
663 for (int ndx = 0; ndx < 96; ndx++)
666 for (int c = 0; c < 2; c++)
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();
673 inVal |= value << (16*c);
675 inputs.push_back(inVal);
679 outputs.resize(inputs.size());
681 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
684 const void* in = &inputs[0];
685 void* out = &outputs[0];
687 m_executor->useProgram();
688 m_executor->execute((int)inputs.size(), &in, &out);
693 const int numValues = (int)inputs.size();
694 const int maxPrints = 10;
697 for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
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();
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();
711 const int diff0 = de::abs((int)refBits0 - (int)resBits0);
712 const int diff1 = de::abs((int)refBits1 - (int)resBits1);
714 if (diff0 > maxDiff || diff1 > maxDiff)
716 if (numFailed < maxPrints)
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;
725 else if (numFailed == maxPrints)
726 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
732 m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
734 m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL,
735 numFailed == 0 ? "Pass" : "Result comparison failed");
742 ShaderPackingFunctionTests::ShaderPackingFunctionTests (Context& context)
743 : TestCaseGroup(context, "pack_unpack", "Floating-point pack and unpack function tests")
747 ShaderPackingFunctionTests::~ShaderPackingFunctionTests (void)
751 void ShaderPackingFunctionTests::init (void)
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));
760 addChild(new UnpackSnorm2x16Case(m_context, glu::SHADERTYPE_VERTEX));
761 addChild(new UnpackSnorm2x16Case(m_context, glu::SHADERTYPE_FRAGMENT));
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));
770 addChild(new UnpackUnorm2x16Case(m_context, glu::SHADERTYPE_VERTEX));
771 addChild(new UnpackUnorm2x16Case(m_context, glu::SHADERTYPE_FRAGMENT));
773 addChild(new PackHalf2x16Case (m_context, glu::SHADERTYPE_VERTEX));
774 addChild(new PackHalf2x16Case (m_context, glu::SHADERTYPE_FRAGMENT));
776 addChild(new UnpackHalf2x16Case (m_context, glu::SHADERTYPE_VERTEX));
777 addChild(new UnpackHalf2x16Case (m_context, glu::SHADERTYPE_FRAGMENT));