1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
5 * Copyright (c) 2015 The Khronos Group Inc.
6 * Copyright (c) 2015 Samsung Electronics Co., Ltd.
7 * Copyright (c) 2016 The Android Open Source Project
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
23 * \brief Floating-point packing and unpacking function tests.
24 *//*--------------------------------------------------------------------*/
26 #include "vktShaderPackingFunctionTests.hpp"
27 #include "vktShaderExecutor.hpp"
28 #include "tcuTestLog.hpp"
29 #include "tcuFormatUtil.hpp"
30 #include "tcuFloat.hpp"
31 #include "deRandom.hpp"
34 #include "deSharedPtr.hpp"
38 namespace shaderexecutor
41 using namespace shaderexecutor;
49 inline deUint32 getUlpDiff (float a, float b)
51 const deUint32 aBits = tcu::Float32(a).bits();
52 const deUint32 bBits = tcu::Float32(b).bits();
53 return aBits > bBits ? aBits - bBits : bBits - aBits;
59 HexFloat (const float value_) : value(value_) {}
62 std::ostream& operator<< (std::ostream& str, const HexFloat& v)
64 return str << v.value << " / " << tcu::toHex(tcu::Float32(v.value).bits());
67 static const char* getPrecisionPostfix (glu::Precision precision)
69 static const char* s_postfix[] =
75 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_postfix) == glu::PRECISION_LAST);
76 DE_ASSERT(de::inBounds<int>(precision, 0, DE_LENGTH_OF_ARRAY(s_postfix)));
77 return s_postfix[precision];
80 static const char* getShaderTypePostfix (glu::ShaderType shaderType)
82 static const char* s_postfix[] =
91 DE_ASSERT(de::inBounds<int>(shaderType, 0, DE_LENGTH_OF_ARRAY(s_postfix)));
92 return s_postfix[shaderType];
97 // ShaderPackingFunctionCase
99 class ShaderPackingFunctionCase : public TestCase
102 ShaderPackingFunctionCase (tcu::TestContext& testCtx, const char* name, const char* description, glu::ShaderType shaderType);
103 ~ShaderPackingFunctionCase (void);
105 virtual void initPrograms (vk::SourceCollections& programCollection) const
107 generateSources(m_shaderType, m_spec, programCollection);
111 const glu::ShaderType m_shaderType;
115 ShaderPackingFunctionCase (const ShaderPackingFunctionCase& other);
116 ShaderPackingFunctionCase& operator= (const ShaderPackingFunctionCase& other);
119 ShaderPackingFunctionCase::ShaderPackingFunctionCase (tcu::TestContext& testCtx, const char* name, const char* description, glu::ShaderType shaderType)
120 : TestCase (testCtx, name, description)
121 , m_shaderType (shaderType)
125 ShaderPackingFunctionCase::~ShaderPackingFunctionCase (void)
129 // ShaderPackingFunctionTestInstance
131 class ShaderPackingFunctionTestInstance : public TestInstance
134 ShaderPackingFunctionTestInstance (Context& context, glu::ShaderType shaderType, const ShaderSpec& spec, const char* name)
135 : TestInstance (context)
136 , m_testCtx (context.getTestContext())
137 , m_shaderType (shaderType)
140 , m_executor (createExecutor(context, m_shaderType, m_spec))
143 virtual tcu::TestStatus iterate (void) = 0;
145 tcu::TestContext& m_testCtx;
146 const glu::ShaderType m_shaderType;
149 de::UniquePtr<ShaderExecutor> m_executor;
154 class PackSnorm2x16CaseInstance: public ShaderPackingFunctionTestInstance
157 PackSnorm2x16CaseInstance (Context& context, glu::ShaderType shaderType, const ShaderSpec& spec, glu::Precision precision, const char* name)
158 : ShaderPackingFunctionTestInstance (context, shaderType, spec, name)
159 , m_precision (precision)
163 tcu::TestStatus iterate (void)
165 de::Random rnd (deStringHash(m_name) ^ 0x776002);
166 std::vector<tcu::Vec2> inputs;
167 std::vector<deUint32> outputs;
168 const int maxDiff = m_precision == glu::PRECISION_HIGHP ? 1 : // Rounding only.
169 m_precision == glu::PRECISION_MEDIUMP ? 33 : // (2^-10) * (2^15) + 1
170 m_precision == glu::PRECISION_LOWP ? 129 : 0; // (2^-8) * (2^15) + 1
172 // Special values to check.
173 inputs.push_back(tcu::Vec2(0.0f, 0.0f));
174 inputs.push_back(tcu::Vec2(-1.0f, 1.0f));
175 inputs.push_back(tcu::Vec2(0.5f, -0.5f));
176 inputs.push_back(tcu::Vec2(-1.5f, 1.5f));
177 inputs.push_back(tcu::Vec2(0.25f, -0.75f));
179 // Random values, mostly in range.
180 for (int ndx = 0; ndx < 15; ndx++)
182 const float x = rnd.getFloat()*2.5f - 1.25f;
183 const float y = rnd.getFloat()*2.5f - 1.25f;
184 inputs.push_back(tcu::Vec2(x, y));
187 // Large random values.
188 for (int ndx = 0; ndx < 80; ndx++)
190 const float x = rnd.getFloat()*1e6f - 0.5e6f;
191 const float y = rnd.getFloat()*1e6f - 0.5e6f;
192 inputs.push_back(tcu::Vec2(x, y));
195 outputs.resize(inputs.size());
197 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
200 const void* in = &inputs[0];
201 void* out = &outputs[0];
203 m_executor->execute((int)inputs.size(), &in, &out);
208 const int numValues = (int)inputs.size();
209 const int maxPrints = 10;
212 for (int valNdx = 0; valNdx < numValues; valNdx++)
214 const deUint16 ref0 = (deUint16)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].x(), -1.0f, 1.0f) * 32767.0f), -(1<<15), (1<<15)-1);
215 const deUint16 ref1 = (deUint16)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].y(), -1.0f, 1.0f) * 32767.0f), -(1<<15), (1<<15)-1);
216 const deUint32 ref = (ref1 << 16) | ref0;
217 const deUint32 res = outputs[valNdx];
218 const deUint16 res0 = (deUint16)(res & 0xffff);
219 const deUint16 res1 = (deUint16)(res >> 16);
220 const int diff0 = de::abs((int)ref0 - (int)res0);
221 const int diff1 = de::abs((int)ref1 - (int)res1);
223 if (diff0 > maxDiff || diff1 > maxDiff)
225 if (numFailed < maxPrints)
227 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx
228 << ", expected packSnorm2x16(" << inputs[valNdx] << ") = " << tcu::toHex(ref)
229 << ", got " << tcu::toHex(res)
230 << "\n diffs = (" << diff0 << ", " << diff1 << "), max diff = " << maxDiff
231 << TestLog::EndMessage;
233 else if (numFailed == maxPrints)
234 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
240 m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
243 return tcu::TestStatus::pass("Pass");
245 return tcu::TestStatus::fail("Result comparison failed");
251 const glu::Precision m_precision;
254 class PackSnorm2x16Case : public ShaderPackingFunctionCase
257 PackSnorm2x16Case (tcu::TestContext& testCtx, glu::ShaderType shaderType, glu::Precision precision)
258 : ShaderPackingFunctionCase (testCtx, (string("packsnorm2x16") + getPrecisionPostfix(precision) + getShaderTypePostfix(shaderType)).c_str(), "packSnorm2x16", shaderType)
259 , m_precision (precision)
261 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_FLOAT_VEC2, precision)));
262 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
264 m_spec.source = "out0 = packSnorm2x16(in0);";
267 TestInstance* createInstance (Context& ctx) const
269 return new PackSnorm2x16CaseInstance(ctx, m_shaderType, m_spec, m_precision, getName());
273 const glu::Precision m_precision;
276 class UnpackSnorm2x16CaseInstance : public ShaderPackingFunctionTestInstance
279 UnpackSnorm2x16CaseInstance (Context& context, glu::ShaderType shaderType, const ShaderSpec& spec, const char* name)
280 : ShaderPackingFunctionTestInstance (context, shaderType, spec, name)
284 tcu::TestStatus iterate (void)
286 const deUint32 maxDiff = 1; // Rounding error.
287 de::Random rnd (deStringHash(m_name) ^ 0x776002);
288 std::vector<deUint32> inputs;
289 std::vector<tcu::Vec2> outputs;
291 inputs.push_back(0x00000000u);
292 inputs.push_back(0x7fff8000u);
293 inputs.push_back(0x80007fffu);
294 inputs.push_back(0xffffffffu);
295 inputs.push_back(0x0001fffeu);
298 for (int ndx = 0; ndx < 95; ndx++)
299 inputs.push_back(rnd.getUint32());
301 outputs.resize(inputs.size());
303 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
306 const void* in = &inputs[0];
307 void* out = &outputs[0];
309 m_executor->execute((int)inputs.size(), &in, &out);
314 const int numValues = (int)inputs.size();
315 const int maxPrints = 10;
318 for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
320 const deInt16 in0 = (deInt16)(deUint16)(inputs[valNdx] & 0xffff);
321 const deInt16 in1 = (deInt16)(deUint16)(inputs[valNdx] >> 16);
322 const float ref0 = de::clamp(float(in0) / 32767.f, -1.0f, 1.0f);
323 const float ref1 = de::clamp(float(in1) / 32767.f, -1.0f, 1.0f);
324 const float res0 = outputs[valNdx].x();
325 const float res1 = outputs[valNdx].y();
327 const deUint32 diff0 = getUlpDiff(ref0, res0);
328 const deUint32 diff1 = getUlpDiff(ref1, res1);
330 if (diff0 > maxDiff || diff1 > maxDiff)
332 if (numFailed < maxPrints)
334 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx << ",\n"
335 << " expected unpackSnorm2x16(" << tcu::toHex(inputs[valNdx]) << ") = "
336 << "vec2(" << HexFloat(ref0) << ", " << HexFloat(ref1) << ")"
337 << ", got vec2(" << HexFloat(res0) << ", " << HexFloat(res1) << ")"
338 << "\n ULP diffs = (" << diff0 << ", " << diff1 << "), max diff = " << maxDiff
339 << TestLog::EndMessage;
341 else if (numFailed == maxPrints)
342 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
348 m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
351 return tcu::TestStatus::pass("Pass");
353 return tcu::TestStatus::fail("Result comparison failed");
359 class UnpackSnorm2x16Case : public ShaderPackingFunctionCase
362 UnpackSnorm2x16Case (tcu::TestContext& testCtx, glu::ShaderType shaderType)
363 : ShaderPackingFunctionCase (testCtx, (string("unpacksnorm2x16") + getShaderTypePostfix(shaderType)).c_str(), "unpackSnorm2x16", shaderType)
365 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
366 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_FLOAT_VEC2, glu::PRECISION_HIGHP)));
368 m_spec.source = "out0 = unpackSnorm2x16(in0);";
371 TestInstance* createInstance (Context& ctx) const
373 return new UnpackSnorm2x16CaseInstance(ctx, m_shaderType, m_spec, getName());
377 class PackUnorm2x16CaseInstance : public ShaderPackingFunctionTestInstance
380 PackUnorm2x16CaseInstance (Context& context, glu::ShaderType shaderType, const ShaderSpec& spec, glu::Precision precision, const char* name)
381 : ShaderPackingFunctionTestInstance (context, shaderType, spec, name)
382 , m_precision (precision)
386 tcu::TestStatus iterate (void)
388 de::Random rnd (deStringHash(m_name) ^ 0x776002);
389 std::vector<tcu::Vec2> inputs;
390 std::vector<deUint32> outputs;
391 const int maxDiff = m_precision == glu::PRECISION_HIGHP ? 1 : // Rounding only.
392 m_precision == glu::PRECISION_MEDIUMP ? 65 : // (2^-10) * (2^16) + 1
393 m_precision == glu::PRECISION_LOWP ? 257 : 0; // (2^-8) * (2^16) + 1
395 // Special values to check.
396 inputs.push_back(tcu::Vec2(0.0f, 0.0f));
397 inputs.push_back(tcu::Vec2(0.5f, 1.0f));
398 inputs.push_back(tcu::Vec2(1.0f, 0.5f));
399 inputs.push_back(tcu::Vec2(-0.5f, 1.5f));
400 inputs.push_back(tcu::Vec2(0.25f, 0.75f));
402 // Random values, mostly in range.
403 for (int ndx = 0; ndx < 15; ndx++)
405 const float x = rnd.getFloat()*1.25f;
406 const float y = rnd.getFloat()*1.25f;
407 inputs.push_back(tcu::Vec2(x, y));
410 // Large random values.
411 for (int ndx = 0; ndx < 80; ndx++)
413 const float x = rnd.getFloat()*1e6f - 1e5f;
414 const float y = rnd.getFloat()*1e6f - 1e5f;
415 inputs.push_back(tcu::Vec2(x, y));
418 outputs.resize(inputs.size());
420 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
423 const void* in = &inputs[0];
424 void* out = &outputs[0];
426 m_executor->execute((int)inputs.size(), &in, &out);
431 const int numValues = (int)inputs.size();
432 const int maxPrints = 10;
435 for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
437 const deUint16 ref0 = (deUint16)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].x(), 0.0f, 1.0f) * 65535.0f), 0, (1<<16)-1);
438 const deUint16 ref1 = (deUint16)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].y(), 0.0f, 1.0f) * 65535.0f), 0, (1<<16)-1);
439 const deUint32 ref = (ref1 << 16) | ref0;
440 const deUint32 res = outputs[valNdx];
441 const deUint16 res0 = (deUint16)(res & 0xffff);
442 const deUint16 res1 = (deUint16)(res >> 16);
443 const int diff0 = de::abs((int)ref0 - (int)res0);
444 const int diff1 = de::abs((int)ref1 - (int)res1);
446 if (diff0 > maxDiff || diff1 > maxDiff)
448 if (numFailed < maxPrints)
450 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx
451 << ", expected packUnorm2x16(" << inputs[valNdx] << ") = " << tcu::toHex(ref)
452 << ", got " << tcu::toHex(res)
453 << "\n diffs = (" << diff0 << ", " << diff1 << "), max diff = " << maxDiff
454 << TestLog::EndMessage;
456 else if (numFailed == maxPrints)
457 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
463 m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
466 return tcu::TestStatus::pass("Pass");
468 return tcu::TestStatus::fail("Result comparison failed");
474 const glu::Precision m_precision;
477 class PackUnorm2x16Case : public ShaderPackingFunctionCase
480 PackUnorm2x16Case (tcu::TestContext& testCtx, glu::ShaderType shaderType, glu::Precision precision)
481 : ShaderPackingFunctionCase (testCtx, (string("packunorm2x16") + getPrecisionPostfix(precision) + getShaderTypePostfix(shaderType)).c_str(), "packUnorm2x16", shaderType)
482 , m_precision (precision)
484 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_FLOAT_VEC2, precision)));
485 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
487 m_spec.source = "out0 = packUnorm2x16(in0);";
490 TestInstance* createInstance (Context& ctx) const
492 return new PackUnorm2x16CaseInstance(ctx, m_shaderType, m_spec, m_precision, getName());
496 const glu::Precision m_precision;
499 class UnpackUnorm2x16CaseInstance : public ShaderPackingFunctionTestInstance
502 UnpackUnorm2x16CaseInstance (Context& context, glu::ShaderType shaderType, const ShaderSpec& spec, const char* name)
503 : ShaderPackingFunctionTestInstance (context, shaderType, spec, name)
507 tcu::TestStatus iterate (void)
509 const deUint32 maxDiff = 1; // Rounding error.
510 de::Random rnd (deStringHash(m_name) ^ 0x776002);
511 std::vector<deUint32> inputs;
512 std::vector<tcu::Vec2> outputs;
514 inputs.push_back(0x00000000u);
515 inputs.push_back(0x7fff8000u);
516 inputs.push_back(0x80007fffu);
517 inputs.push_back(0xffffffffu);
518 inputs.push_back(0x0001fffeu);
521 for (int ndx = 0; ndx < 95; ndx++)
522 inputs.push_back(rnd.getUint32());
524 outputs.resize(inputs.size());
526 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
529 const void* in = &inputs[0];
530 void* out = &outputs[0];
532 m_executor->execute((int)inputs.size(), &in, &out);
537 const int numValues = (int)inputs.size();
538 const int maxPrints = 10;
541 for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
543 const deUint16 in0 = (deUint16)(inputs[valNdx] & 0xffff);
544 const deUint16 in1 = (deUint16)(inputs[valNdx] >> 16);
545 const float ref0 = float(in0) / 65535.0f;
546 const float ref1 = float(in1) / 65535.0f;
547 const float res0 = outputs[valNdx].x();
548 const float res1 = outputs[valNdx].y();
550 const deUint32 diff0 = getUlpDiff(ref0, res0);
551 const deUint32 diff1 = getUlpDiff(ref1, res1);
553 if (diff0 > maxDiff || diff1 > maxDiff)
555 if (numFailed < maxPrints)
557 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx << ",\n"
558 << " expected unpackUnorm2x16(" << tcu::toHex(inputs[valNdx]) << ") = "
559 << "vec2(" << HexFloat(ref0) << ", " << HexFloat(ref1) << ")"
560 << ", got vec2(" << HexFloat(res0) << ", " << HexFloat(res1) << ")"
561 << "\n ULP diffs = (" << diff0 << ", " << diff1 << "), max diff = " << maxDiff
562 << TestLog::EndMessage;
564 else if (numFailed == maxPrints)
565 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
571 m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
574 return tcu::TestStatus::pass("Pass");
576 return tcu::TestStatus::fail("Result comparison failed");
583 class UnpackUnorm2x16Case : public ShaderPackingFunctionCase
586 UnpackUnorm2x16Case (tcu::TestContext& testCtx, glu::ShaderType shaderType)
587 : ShaderPackingFunctionCase(testCtx, (string("unpackunorm2x16") + getShaderTypePostfix(shaderType)).c_str(), "unpackUnorm2x16", shaderType)
589 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
590 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_FLOAT_VEC2, glu::PRECISION_HIGHP)));
592 m_spec.source = "out0 = unpackUnorm2x16(in0);";
595 TestInstance* createInstance (Context& ctx) const
597 return new UnpackUnorm2x16CaseInstance(ctx, m_shaderType, m_spec, getName());
602 class PackHalf2x16CaseInstance : public ShaderPackingFunctionTestInstance
605 PackHalf2x16CaseInstance (Context& context, glu::ShaderType shaderType, const ShaderSpec& spec, const char* name)
606 : ShaderPackingFunctionTestInstance (context, shaderType, spec, name)
610 tcu::TestStatus iterate (void)
612 const int maxDiff = 0; // Values can be represented exactly in mediump.
613 de::Random rnd (deStringHash(m_name) ^ 0x776002);
614 std::vector<tcu::Vec2> inputs;
615 std::vector<deUint32> outputs;
617 // Special values to check.
618 inputs.push_back(tcu::Vec2(0.0f, 0.0f));
619 inputs.push_back(tcu::Vec2(0.5f, 1.0f));
620 inputs.push_back(tcu::Vec2(1.0f, 0.5f));
621 inputs.push_back(tcu::Vec2(-0.5f, 1.5f));
622 inputs.push_back(tcu::Vec2(0.25f, 0.75f));
626 const int minExp = -14;
627 const int maxExp = 15;
629 for (int ndx = 0; ndx < 95; ndx++)
632 for (int c = 0; c < 2; c++)
634 const int s = rnd.getBool() ? 1 : -1;
635 const int exp = rnd.getInt(minExp, maxExp);
636 const deUint32 mantissa = rnd.getUint32() & ((1<<23)-1);
638 v[c] = tcu::Float32::construct(s, exp ? exp : 1 /* avoid denormals */, (1u<<23) | mantissa).asFloat();
644 // Convert input values to fp16 and back to make sure they can be represented exactly in mediump.
645 for (std::vector<tcu::Vec2>::iterator inVal = inputs.begin(); inVal != inputs.end(); ++inVal)
646 *inVal = tcu::Vec2(tcu::Float16(inVal->x()).asFloat(), tcu::Float16(inVal->y()).asFloat());
648 outputs.resize(inputs.size());
650 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
653 const void* in = &inputs[0];
654 void* out = &outputs[0];
656 m_executor->execute((int)inputs.size(), &in, &out);
661 const int numValues = (int)inputs.size();
662 const int maxPrints = 10;
665 for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
667 const deUint16 ref0 = (deUint16)tcu::Float16(inputs[valNdx].x()).bits();
668 const deUint16 ref1 = (deUint16)tcu::Float16(inputs[valNdx].y()).bits();
669 const deUint32 ref = (ref1 << 16) | ref0;
670 const deUint32 res = outputs[valNdx];
671 const deUint16 res0 = (deUint16)(res & 0xffff);
672 const deUint16 res1 = (deUint16)(res >> 16);
673 const int diff0 = de::abs((int)ref0 - (int)res0);
674 const int diff1 = de::abs((int)ref1 - (int)res1);
676 if (diff0 > maxDiff || diff1 > maxDiff)
678 if (numFailed < maxPrints)
680 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx
681 << ", expected packHalf2x16(" << inputs[valNdx] << ") = " << tcu::toHex(ref)
682 << ", got " << tcu::toHex(res)
683 << "\n diffs = (" << diff0 << ", " << diff1 << "), max diff = " << maxDiff
684 << TestLog::EndMessage;
686 else if (numFailed == maxPrints)
687 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
693 m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
696 return tcu::TestStatus::pass("Pass");
698 return tcu::TestStatus::fail("Result comparison failed");
704 class PackHalf2x16Case : public ShaderPackingFunctionCase
707 PackHalf2x16Case (tcu::TestContext& testCtx, glu::ShaderType shaderType)
708 : ShaderPackingFunctionCase (testCtx, (string("packhalf2x16") + getShaderTypePostfix(shaderType)).c_str(), "packHalf2x16", shaderType)
710 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_FLOAT_VEC2, glu::PRECISION_HIGHP)));
711 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
713 m_spec.source = "out0 = packHalf2x16(in0);";
716 TestInstance* createInstance (Context& ctx) const
718 return new PackHalf2x16CaseInstance(ctx, m_shaderType, m_spec, getName());
723 class UnpackHalf2x16CaseInstance : public ShaderPackingFunctionTestInstance
730 enum SubnormalizedConversionType
737 UnpackHalf2x16CaseInstance (Context& context, glu::ShaderType shaderType, const ShaderSpec& spec, const char* name)
738 : ShaderPackingFunctionTestInstance (context, shaderType, spec, name)
742 tcu::TestStatus iterate (void)
744 const int minExp = -14;
745 const int maxExp = 15;
746 const int mantBits = 10;
747 const deUint32 mantBitMask = (1u << mantBits) - 1u;
748 tcu::TestLog& log = m_testCtx.getLog();
750 de::Random rnd (deStringHash(m_name) ^ 0x776002);
751 std::vector<deUint32> inputs;
752 std::vector<tcu::Vec2> outputs;
755 inputs.push_back((tcu::Float16( 0.0f).bits() << 16) | tcu::Float16( 1.0f).bits());
756 inputs.push_back((tcu::Float16( 1.0f).bits() << 16) | tcu::Float16( 0.0f).bits());
757 inputs.push_back((tcu::Float16(-1.0f).bits() << 16) | tcu::Float16( 0.5f).bits());
758 inputs.push_back((tcu::Float16( 0.5f).bits() << 16) | tcu::Float16(-0.5f).bits());
759 // Special subnormal value: single lowest bit set
760 inputs.push_back((tcu::Float16(composeHalfFloat(POSITIVE, 0u, 1u)).bits() << 16)
761 | tcu::Float16(composeHalfFloat(NEGATIVE, 0u, 1u)).bits());
762 // Special subnormal value: single highest fraction bit set
763 inputs.push_back((tcu::Float16(composeHalfFloat(NEGATIVE, 0u, 1u << (mantBits - 1u))).bits() << 16)
764 | tcu::Float16(composeHalfFloat(POSITIVE, 0u, 1u << (mantBits - 1u))).bits());
765 // Special subnormal value: all fraction bits set
766 inputs.push_back((tcu::Float16(composeHalfFloat(POSITIVE, 0u, mantBitMask)).bits() << 16)
767 | tcu::Float16(composeHalfFloat(NEGATIVE, 0u, mantBitMask)).bits());
769 // Construct random values.
770 for (int ndx = 0; ndx < 90; ndx++)
773 for (int c = 0; c < 2; c++)
775 const int s = rnd.getBool() ? 1 : -1;
776 const int exp = rnd.getInt(minExp, maxExp);
777 const deUint32 mantissa = rnd.getUint32() & mantBitMask;
778 const deUint16 value = tcu::Float16::construct(s, exp != 0 ? exp : 1 /* avoid denorm */, static_cast<deUint16>((1u<<10) | mantissa)).bits();
780 inVal |= value << (16u * c);
782 inputs.push_back(inVal);
784 for (int ndx = 0; ndx < 15; ndx++)
787 for (int c = 0; c < 2; c++)
789 const Sign sign = rnd.getBool()? POSITIVE : NEGATIVE;
790 const deUint32 mantissa = rnd.getUint32() & mantBitMask;
791 const deUint16 value = tcu::Float16(composeHalfFloat(sign, 0u /* force denorm */, mantissa)).bits();
793 inVal |= value << (16u * c);
795 inputs.push_back(inVal);
798 outputs.resize(inputs.size());
800 log << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
803 const void* in = &inputs[0];
804 void* out = &outputs[0];
806 m_executor->execute((int)inputs.size(), &in, &out);
811 const int numValues = (int)inputs.size();
812 const int maxPrints = 10;
814 SubnormalizedConversionType conversion = UNKNOWN;
816 for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
818 const deUint16 in0 = (deUint16)(inputs[valNdx] & 0xffff);
819 const deUint16 in1 = (deUint16)(inputs[valNdx] >> 16);
820 const float res0 = outputs[valNdx].x();
821 const float res1 = outputs[valNdx].y();
823 const deBool value0 = checkValue(in0, res0, conversion);
824 // note: do not avoid calling checkValue for in1 if it failed for in0 by using && laziness
825 // checkValue may potentially change 'conversion' parameter if it was set to UNKNOWN so far
826 const deBool value1 = checkValue(in1, res1, conversion);
827 const deBool valuesOK = value0 && value1;
831 if (numFailed < maxPrints)
832 printErrorMessage(log, valNdx, in0, in1, res0, res1);
833 else if (numFailed == maxPrints)
834 log << TestLog::Message << "..." << TestLog::EndMessage;
839 log << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
842 return tcu::TestStatus::pass("Pass");
844 return tcu::TestStatus::fail("Result comparison failed");
848 deBool checkValue (deUint16 inValue, float outValue, SubnormalizedConversionType& conversion)
850 const tcu::Float16 temp = tcu::Float16(inValue);
851 const float ref = temp.asFloat();
852 const deUint32 refBits = tcu::Float32(ref).bits();
853 const deUint32 resBits = tcu::Float32(outValue).bits();
854 const deBool bitMatch = (refBits ^ resBits) == 0u;
855 const deBool denorm = temp.isDenorm();
857 if (conversion != CONVERTED && denorm)
859 if (resBits == 0 || (ref < 0 && resBits == 0x80000000UL))
861 conversion = ZERO_FLUSHED;
864 if (conversion != ZERO_FLUSHED && bitMatch)
866 conversion = CONVERTED;
875 void printErrorMessage (tcu::TestLog& log, deUint32 valNdx, deUint16 in0, deUint16 in1, float out0, float out1)
877 const float ref0 = tcu::Float16(in0).asFloat();
878 const deUint32 refBits0 = tcu::Float32(ref0).bits();
879 const deUint32 resBits0 = tcu::Float32(out0).bits();
880 const float ref1 = tcu::Float16(in1).asFloat();
881 const deUint32 refBits1 = tcu::Float32(ref1).bits();
882 const deUint32 resBits1 = tcu::Float32(out1).bits();
883 log << TestLog::Message << "ERROR: Mismatch in value " << valNdx << ",\n"
884 << " expected unpackHalf2x16(" << tcu::toHex((in1 << 16u) | in0) << ") = "
885 << "vec2(" << ref0 << " / " << tcu::toHex(refBits0) << ", " << ref1 << " / " << tcu::toHex(refBits1) << ")"
886 << ", got vec2(" << out0 << " / " << tcu::toHex(resBits0) << ", " << out1 << " / " << tcu::toHex(resBits1) << ")"
887 << TestLog::EndMessage;
889 deUint16 composeHalfFloat (Sign sign, deUint32 exponent, deUint32 significand)
891 const deUint32 BitMask_05 = (1u << 5u) - 1u;
892 const deUint32 BitMask_10 = (1u << 10u) - 1u;
893 const deUint32 BitMask_16 = (1u << 16u) - 1u;
894 DE_UNREF(BitMask_05);
895 DE_UNREF(BitMask_10);
896 DE_UNREF(BitMask_16);
897 DE_ASSERT((exponent & ~BitMask_05) == 0u);
898 DE_ASSERT((significand & ~BitMask_10) == 0u);
899 const deUint32 value = (((sign == NEGATIVE ? 1u : 0u) << 5u | exponent) << 10u) | significand;
900 DE_ASSERT((value & ~BitMask_16) == 0u);
901 return static_cast<deUint16>(value);
905 class UnpackHalf2x16Case : public ShaderPackingFunctionCase
908 UnpackHalf2x16Case (tcu::TestContext& testCtx, glu::ShaderType shaderType)
909 : ShaderPackingFunctionCase (testCtx, (string("unpackhalf2x16") + getShaderTypePostfix(shaderType)).c_str(), "unpackHalf2x16", shaderType)
911 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
912 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_FLOAT_VEC2, glu::PRECISION_MEDIUMP)));
914 m_spec.source = "out0 = unpackHalf2x16(in0);";
917 TestInstance* createInstance (Context& ctx) const
919 return new UnpackHalf2x16CaseInstance(ctx, m_shaderType, m_spec, getName());
924 class PackSnorm4x8CaseInstance : public ShaderPackingFunctionTestInstance
927 PackSnorm4x8CaseInstance (Context& context, glu::ShaderType shaderType, const ShaderSpec& spec, glu::Precision precision, const char* name)
928 : ShaderPackingFunctionTestInstance (context, shaderType, spec, name)
929 , m_precision (precision)
933 tcu::TestStatus iterate (void)
935 de::Random rnd (deStringHash(m_name) ^ 0x42f2c0);
936 std::vector<tcu::Vec4> inputs;
937 std::vector<deUint32> outputs;
938 const int maxDiff = m_precision == glu::PRECISION_HIGHP ? 1 : // Rounding only.
939 m_precision == glu::PRECISION_MEDIUMP ? 1 : // (2^-10) * (2^7) + 1
940 m_precision == glu::PRECISION_LOWP ? 2 : 0; // (2^-8) * (2^7) + 1
942 // Special values to check.
943 inputs.push_back(tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f));
944 inputs.push_back(tcu::Vec4(-1.0f, 1.0f, -1.0f, 1.0f));
945 inputs.push_back(tcu::Vec4(0.5f, -0.5f, -0.5f, 0.5f));
946 inputs.push_back(tcu::Vec4(-1.5f, 1.5f, -1.5f, 1.5f));
947 inputs.push_back(tcu::Vec4(0.25f, -0.75f, -0.25f, 0.75f));
949 // Random values, mostly in range.
950 for (int ndx = 0; ndx < 15; ndx++)
952 const float x = rnd.getFloat()*2.5f - 1.25f;
953 const float y = rnd.getFloat()*2.5f - 1.25f;
954 const float z = rnd.getFloat()*2.5f - 1.25f;
955 const float w = rnd.getFloat()*2.5f - 1.25f;
956 inputs.push_back(tcu::Vec4(x, y, z, w));
959 // Large random values.
960 for (int ndx = 0; ndx < 80; ndx++)
962 const float x = rnd.getFloat()*1e6f - 0.5e6f;
963 const float y = rnd.getFloat()*1e6f - 0.5e6f;
964 const float z = rnd.getFloat()*1e6f - 0.5e6f;
965 const float w = rnd.getFloat()*1e6f - 0.5e6f;
966 inputs.push_back(tcu::Vec4(x, y, z, w));
969 outputs.resize(inputs.size());
971 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
974 const void* in = &inputs[0];
975 void* out = &outputs[0];
977 m_executor->execute((int)inputs.size(), &in, &out);
982 const int numValues = (int)inputs.size();
983 const int maxPrints = 10;
986 for (int valNdx = 0; valNdx < numValues; valNdx++)
988 const deUint16 ref0 = (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].x(), -1.0f, 1.0f) * 127.0f), -(1<<7), (1<<7)-1);
989 const deUint16 ref1 = (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].y(), -1.0f, 1.0f) * 127.0f), -(1<<7), (1<<7)-1);
990 const deUint16 ref2 = (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].z(), -1.0f, 1.0f) * 127.0f), -(1<<7), (1<<7)-1);
991 const deUint16 ref3 = (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].w(), -1.0f, 1.0f) * 127.0f), -(1<<7), (1<<7)-1);
992 const deUint32 ref = (deUint32(ref3) << 24) | (deUint32(ref2) << 16) | (deUint32(ref1) << 8) | deUint32(ref0);
993 const deUint32 res = outputs[valNdx];
994 const deUint16 res0 = (deUint8)(res & 0xff);
995 const deUint16 res1 = (deUint8)((res >> 8) & 0xff);
996 const deUint16 res2 = (deUint8)((res >> 16) & 0xff);
997 const deUint16 res3 = (deUint8)((res >> 24) & 0xff);
998 const int diff0 = de::abs((int)ref0 - (int)res0);
999 const int diff1 = de::abs((int)ref1 - (int)res1);
1000 const int diff2 = de::abs((int)ref2 - (int)res2);
1001 const int diff3 = de::abs((int)ref3 - (int)res3);
1003 if (diff0 > maxDiff || diff1 > maxDiff || diff2 > maxDiff || diff3 > maxDiff)
1005 if (numFailed < maxPrints)
1007 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx
1008 << ", expected packSnorm4x8(" << inputs[valNdx] << ") = " << tcu::toHex(ref)
1009 << ", got " << tcu::toHex(res)
1010 << "\n diffs = " << tcu::IVec4(diff0, diff1, diff2, diff3) << ", max diff = " << maxDiff
1011 << TestLog::EndMessage;
1013 else if (numFailed == maxPrints)
1014 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
1020 m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
1023 return tcu::TestStatus::pass("Pass");
1025 return tcu::TestStatus::fail("Result comparison failed");
1031 const glu::Precision m_precision;
1034 class PackSnorm4x8Case : public ShaderPackingFunctionCase
1037 PackSnorm4x8Case (tcu::TestContext& testCtx, glu::ShaderType shaderType, glu::Precision precision)
1038 : ShaderPackingFunctionCase (testCtx, (string("packsnorm4x8") + getPrecisionPostfix(precision) + getShaderTypePostfix(shaderType)).c_str(), "packSnorm4x8", shaderType)
1039 , m_precision (precision)
1041 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_FLOAT_VEC4, precision)));
1042 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
1044 m_spec.source = "out0 = packSnorm4x8(in0);";
1047 TestInstance* createInstance (Context& ctx) const
1049 return new PackSnorm4x8CaseInstance(ctx, m_shaderType, m_spec, m_precision, getName());
1053 const glu::Precision m_precision;
1056 class UnpackSnorm4x8CaseInstance : public ShaderPackingFunctionTestInstance
1059 UnpackSnorm4x8CaseInstance (Context& context, glu::ShaderType shaderType, const ShaderSpec& spec, const char* name)
1060 : ShaderPackingFunctionTestInstance (context, shaderType, spec, name)
1064 tcu::TestStatus iterate (void)
1066 const deUint32 maxDiff = 1; // Rounding error.
1067 de::Random rnd (deStringHash(m_name) ^ 0x776002);
1068 std::vector<deUint32> inputs;
1069 std::vector<tcu::Vec4> outputs;
1071 inputs.push_back(0x00000000u);
1072 inputs.push_back(0x7fff8000u);
1073 inputs.push_back(0x80007fffu);
1074 inputs.push_back(0xffffffffu);
1075 inputs.push_back(0x0001fffeu);
1078 for (int ndx = 0; ndx < 95; ndx++)
1079 inputs.push_back(rnd.getUint32());
1081 outputs.resize(inputs.size());
1083 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
1086 const void* in = &inputs[0];
1087 void* out = &outputs[0];
1089 m_executor->execute((int)inputs.size(), &in, &out);
1094 const int numValues = (int)inputs.size();
1095 const int maxPrints = 10;
1098 for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
1100 const deInt8 in0 = (deInt8)(deUint8)(inputs[valNdx] & 0xff);
1101 const deInt8 in1 = (deInt8)(deUint8)((inputs[valNdx] >> 8) & 0xff);
1102 const deInt8 in2 = (deInt8)(deUint8)((inputs[valNdx] >> 16) & 0xff);
1103 const deInt8 in3 = (deInt8)(deUint8)(inputs[valNdx] >> 24);
1104 const float ref0 = de::clamp(float(in0) / 127.f, -1.0f, 1.0f);
1105 const float ref1 = de::clamp(float(in1) / 127.f, -1.0f, 1.0f);
1106 const float ref2 = de::clamp(float(in2) / 127.f, -1.0f, 1.0f);
1107 const float ref3 = de::clamp(float(in3) / 127.f, -1.0f, 1.0f);
1108 const float res0 = outputs[valNdx].x();
1109 const float res1 = outputs[valNdx].y();
1110 const float res2 = outputs[valNdx].z();
1111 const float res3 = outputs[valNdx].w();
1113 const deUint32 diff0 = getUlpDiff(ref0, res0);
1114 const deUint32 diff1 = getUlpDiff(ref1, res1);
1115 const deUint32 diff2 = getUlpDiff(ref2, res2);
1116 const deUint32 diff3 = getUlpDiff(ref3, res3);
1118 if (diff0 > maxDiff || diff1 > maxDiff || diff2 > maxDiff || diff3 > maxDiff)
1120 if (numFailed < maxPrints)
1122 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx << ",\n"
1123 << " expected unpackSnorm4x8(" << tcu::toHex(inputs[valNdx]) << ") = "
1124 << "vec4(" << HexFloat(ref0) << ", " << HexFloat(ref1) << ", " << HexFloat(ref2) << ", " << HexFloat(ref3) << ")"
1125 << ", got vec4(" << HexFloat(res0) << ", " << HexFloat(res1) << ", " << HexFloat(res2) << ", " << HexFloat(res3) << ")"
1126 << "\n ULP diffs = (" << diff0 << ", " << diff1 << ", " << diff2 << ", " << diff3 << "), max diff = " << maxDiff
1127 << TestLog::EndMessage;
1129 else if (numFailed == maxPrints)
1130 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
1136 m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
1139 return tcu::TestStatus::pass("Pass");
1141 return tcu::TestStatus::fail("Result comparison failed");
1148 class UnpackSnorm4x8Case : public ShaderPackingFunctionCase
1151 UnpackSnorm4x8Case (tcu::TestContext& testCtx, glu::ShaderType shaderType)
1152 : ShaderPackingFunctionCase (testCtx, (string("unpacksnorm4x8") + getShaderTypePostfix(shaderType)).c_str(), "unpackSnorm4x8", shaderType)
1154 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
1155 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP)));
1157 m_spec.source = "out0 = unpackSnorm4x8(in0);";
1160 TestInstance* createInstance (Context& ctx) const
1162 return new UnpackSnorm4x8CaseInstance(ctx, m_shaderType, m_spec, getName());
1167 class PackUnorm4x8CaseInstance : public ShaderPackingFunctionTestInstance
1170 PackUnorm4x8CaseInstance (Context& context, glu::ShaderType shaderType, const ShaderSpec& spec, glu::Precision precision, const char* name)
1171 : ShaderPackingFunctionTestInstance (context, shaderType, spec, name)
1172 , m_precision (precision)
1176 tcu::TestStatus iterate (void)
1178 de::Random rnd (deStringHash(m_name) ^ 0x776002);
1179 std::vector<tcu::Vec4> inputs;
1180 std::vector<deUint32> outputs;
1181 const int maxDiff = m_precision == glu::PRECISION_HIGHP ? 1 : // Rounding only.
1182 m_precision == glu::PRECISION_MEDIUMP ? 1 : // (2^-10) * (2^8) + 1
1183 m_precision == glu::PRECISION_LOWP ? 2 : 0; // (2^-8) * (2^8) + 1
1185 // Special values to check.
1186 inputs.push_back(tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f));
1187 inputs.push_back(tcu::Vec4(-1.0f, 1.0f, -1.0f, 1.0f));
1188 inputs.push_back(tcu::Vec4(0.5f, -0.5f, -0.5f, 0.5f));
1189 inputs.push_back(tcu::Vec4(-1.5f, 1.5f, -1.5f, 1.5f));
1190 inputs.push_back(tcu::Vec4(0.25f, -0.75f, -0.25f, 0.75f));
1192 // Random values, mostly in range.
1193 for (int ndx = 0; ndx < 15; ndx++)
1195 const float x = rnd.getFloat()*1.25f - 0.125f;
1196 const float y = rnd.getFloat()*1.25f - 0.125f;
1197 const float z = rnd.getFloat()*1.25f - 0.125f;
1198 const float w = rnd.getFloat()*1.25f - 0.125f;
1199 inputs.push_back(tcu::Vec4(x, y, z, w));
1202 // Large random values.
1203 for (int ndx = 0; ndx < 80; ndx++)
1205 const float x = rnd.getFloat()*1e6f - 1e5f;
1206 const float y = rnd.getFloat()*1e6f - 1e5f;
1207 const float z = rnd.getFloat()*1e6f - 1e5f;
1208 const float w = rnd.getFloat()*1e6f - 1e5f;
1209 inputs.push_back(tcu::Vec4(x, y, z, w));
1212 outputs.resize(inputs.size());
1214 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
1217 const void* in = &inputs[0];
1218 void* out = &outputs[0];
1220 m_executor->execute((int)inputs.size(), &in, &out);
1225 const int numValues = (int)inputs.size();
1226 const int maxPrints = 10;
1229 for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
1231 const deUint16 ref0 = (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].x(), 0.0f, 1.0f) * 255.0f), 0, (1<<8)-1);
1232 const deUint16 ref1 = (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].y(), 0.0f, 1.0f) * 255.0f), 0, (1<<8)-1);
1233 const deUint16 ref2 = (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].z(), 0.0f, 1.0f) * 255.0f), 0, (1<<8)-1);
1234 const deUint16 ref3 = (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].w(), 0.0f, 1.0f) * 255.0f), 0, (1<<8)-1);
1235 const deUint32 ref = (deUint32(ref3) << 24) | (deUint32(ref2) << 16) | (deUint32(ref1) << 8) | deUint32(ref0);
1236 const deUint32 res = outputs[valNdx];
1237 const deUint16 res0 = (deUint8)(res & 0xff);
1238 const deUint16 res1 = (deUint8)((res >> 8) & 0xff);
1239 const deUint16 res2 = (deUint8)((res >> 16) & 0xff);
1240 const deUint16 res3 = (deUint8)((res >> 24) & 0xff);
1241 const int diff0 = de::abs((int)ref0 - (int)res0);
1242 const int diff1 = de::abs((int)ref1 - (int)res1);
1243 const int diff2 = de::abs((int)ref2 - (int)res2);
1244 const int diff3 = de::abs((int)ref3 - (int)res3);
1246 if (diff0 > maxDiff || diff1 > maxDiff || diff2 > maxDiff || diff3 > maxDiff)
1248 if (numFailed < maxPrints)
1250 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx
1251 << ", expected packUnorm4x8(" << inputs[valNdx] << ") = " << tcu::toHex(ref)
1252 << ", got " << tcu::toHex(res)
1253 << "\n diffs = " << tcu::IVec4(diff0, diff1, diff2, diff3) << ", max diff = " << maxDiff
1254 << TestLog::EndMessage;
1256 else if (numFailed == maxPrints)
1257 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
1263 m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
1266 return tcu::TestStatus::pass("Pass");
1268 return tcu::TestStatus::fail("Result comparison failed");
1274 const glu::Precision m_precision;
1277 class PackUnorm4x8Case : public ShaderPackingFunctionCase
1280 PackUnorm4x8Case (tcu::TestContext& testCtx, glu::ShaderType shaderType, glu::Precision precision)
1281 : ShaderPackingFunctionCase (testCtx, (string("packunorm4x8") + getPrecisionPostfix(precision) + getShaderTypePostfix(shaderType)).c_str(), "packUnorm4x8", shaderType)
1282 , m_precision (precision)
1284 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_FLOAT_VEC4, precision)));
1285 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
1287 m_spec.source = "out0 = packUnorm4x8(in0);";
1290 TestInstance* createInstance (Context& ctx) const
1292 return new PackUnorm4x8CaseInstance(ctx, m_shaderType, m_spec, m_precision, getName());
1296 const glu::Precision m_precision;
1299 class UnpackUnorm4x8CaseInstance : public ShaderPackingFunctionTestInstance
1302 UnpackUnorm4x8CaseInstance (Context& context, glu::ShaderType shaderType, const ShaderSpec& spec, const char* name)
1303 : ShaderPackingFunctionTestInstance (context, shaderType, spec, name)
1307 tcu::TestStatus iterate (void)
1309 const deUint32 maxDiff = 1; // Rounding error.
1310 de::Random rnd (deStringHash(m_name) ^ 0x776002);
1311 std::vector<deUint32> inputs;
1312 std::vector<tcu::Vec4> outputs;
1314 inputs.push_back(0x00000000u);
1315 inputs.push_back(0x7fff8000u);
1316 inputs.push_back(0x80007fffu);
1317 inputs.push_back(0xffffffffu);
1318 inputs.push_back(0x0001fffeu);
1321 for (int ndx = 0; ndx < 95; ndx++)
1322 inputs.push_back(rnd.getUint32());
1324 outputs.resize(inputs.size());
1326 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
1329 const void* in = &inputs[0];
1330 void* out = &outputs[0];
1332 m_executor->execute((int)inputs.size(), &in, &out);
1337 const int numValues = (int)inputs.size();
1338 const int maxPrints = 10;
1341 for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
1343 const deUint8 in0 = (deUint8)(inputs[valNdx] & 0xff);
1344 const deUint8 in1 = (deUint8)((inputs[valNdx] >> 8) & 0xff);
1345 const deUint8 in2 = (deUint8)((inputs[valNdx] >> 16) & 0xff);
1346 const deUint8 in3 = (deUint8)(inputs[valNdx] >> 24);
1347 const float ref0 = de::clamp(float(in0) / 255.f, 0.0f, 1.0f);
1348 const float ref1 = de::clamp(float(in1) / 255.f, 0.0f, 1.0f);
1349 const float ref2 = de::clamp(float(in2) / 255.f, 0.0f, 1.0f);
1350 const float ref3 = de::clamp(float(in3) / 255.f, 0.0f, 1.0f);
1351 const float res0 = outputs[valNdx].x();
1352 const float res1 = outputs[valNdx].y();
1353 const float res2 = outputs[valNdx].z();
1354 const float res3 = outputs[valNdx].w();
1356 const deUint32 diff0 = getUlpDiff(ref0, res0);
1357 const deUint32 diff1 = getUlpDiff(ref1, res1);
1358 const deUint32 diff2 = getUlpDiff(ref2, res2);
1359 const deUint32 diff3 = getUlpDiff(ref3, res3);
1361 if (diff0 > maxDiff || diff1 > maxDiff || diff2 > maxDiff || diff3 > maxDiff)
1363 if (numFailed < maxPrints)
1365 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx << ",\n"
1366 << " expected unpackUnorm4x8(" << tcu::toHex(inputs[valNdx]) << ") = "
1367 << "vec4(" << HexFloat(ref0) << ", " << HexFloat(ref1) << ", " << HexFloat(ref2) << ", " << HexFloat(ref3) << ")"
1368 << ", got vec4(" << HexFloat(res0) << ", " << HexFloat(res1) << ", " << HexFloat(res2) << ", " << HexFloat(res3) << ")"
1369 << "\n ULP diffs = (" << diff0 << ", " << diff1 << ", " << diff2 << ", " << diff3 << "), max diff = " << maxDiff
1370 << TestLog::EndMessage;
1372 else if (numFailed == maxPrints)
1373 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
1379 m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
1382 return tcu::TestStatus::pass("Pass");
1384 return tcu::TestStatus::fail("Result comparison failed");
1390 class UnpackUnorm4x8Case : public ShaderPackingFunctionCase
1393 UnpackUnorm4x8Case (tcu::TestContext& testCtx, glu::ShaderType shaderType)
1394 : ShaderPackingFunctionCase (testCtx, (string("unpackunorm4x8") + getShaderTypePostfix(shaderType)).c_str(), "unpackUnorm4x8", shaderType)
1396 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
1397 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP)));
1399 m_spec.source = "out0 = unpackUnorm4x8(in0);";
1402 TestInstance* createInstance (Context& ctx) const
1404 return new UnpackUnorm4x8CaseInstance(ctx, m_shaderType, m_spec, getName());
1409 ShaderPackingFunctionTests::ShaderPackingFunctionTests (tcu::TestContext& testCtx)
1410 : tcu::TestCaseGroup (testCtx, "pack_unpack", "Floating-point pack and unpack function tests")
1414 ShaderPackingFunctionTests::~ShaderPackingFunctionTests (void)
1418 void ShaderPackingFunctionTests::init (void)
1420 // New built-in functions in GLES 3.1
1422 const glu::ShaderType allShaderTypes[] =
1424 glu::SHADERTYPE_VERTEX,
1425 glu::SHADERTYPE_TESSELLATION_CONTROL,
1426 glu::SHADERTYPE_TESSELLATION_EVALUATION,
1427 glu::SHADERTYPE_GEOMETRY,
1428 glu::SHADERTYPE_FRAGMENT,
1429 glu::SHADERTYPE_COMPUTE
1433 for (int prec = glu::PRECISION_MEDIUMP; prec < glu::PRECISION_LAST; prec++)
1435 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(allShaderTypes); shaderTypeNdx++)
1436 addChild(new PackSnorm4x8Case(m_testCtx, allShaderTypes[shaderTypeNdx], glu::Precision(prec)));
1440 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(allShaderTypes); shaderTypeNdx++)
1441 addChild(new UnpackSnorm4x8Case(m_testCtx, allShaderTypes[shaderTypeNdx]));
1444 for (int prec = glu::PRECISION_MEDIUMP; prec < glu::PRECISION_LAST; prec++)
1446 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(allShaderTypes); shaderTypeNdx++)
1447 addChild(new PackUnorm4x8Case(m_testCtx, allShaderTypes[shaderTypeNdx], glu::Precision(prec)));
1451 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(allShaderTypes); shaderTypeNdx++)
1452 addChild(new UnpackUnorm4x8Case(m_testCtx, allShaderTypes[shaderTypeNdx]));
1455 // GLES 3 functions in new shader types.
1457 const glu::ShaderType newShaderTypes[] =
1459 glu::SHADERTYPE_GEOMETRY,
1460 glu::SHADERTYPE_COMPUTE
1464 for (int prec = glu::PRECISION_MEDIUMP; prec < glu::PRECISION_LAST; prec++)
1466 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(newShaderTypes); shaderTypeNdx++)
1467 addChild(new PackSnorm2x16Case(m_testCtx, newShaderTypes[shaderTypeNdx], glu::Precision(prec)));
1471 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(newShaderTypes); shaderTypeNdx++)
1472 addChild(new UnpackSnorm2x16Case(m_testCtx, newShaderTypes[shaderTypeNdx]));
1475 for (int prec = glu::PRECISION_MEDIUMP; prec < glu::PRECISION_LAST; prec++)
1477 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(newShaderTypes); shaderTypeNdx++)
1478 addChild(new PackUnorm2x16Case(m_testCtx, newShaderTypes[shaderTypeNdx], glu::Precision(prec)));
1482 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(newShaderTypes); shaderTypeNdx++)
1483 addChild(new UnpackUnorm2x16Case(m_testCtx, newShaderTypes[shaderTypeNdx]));
1486 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(newShaderTypes); shaderTypeNdx++)
1487 addChild(new PackHalf2x16Case(m_testCtx, newShaderTypes[shaderTypeNdx]));
1490 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(newShaderTypes); shaderTypeNdx++)
1491 addChild(new UnpackHalf2x16Case(m_testCtx, newShaderTypes[shaderTypeNdx]));