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
726 UnpackHalf2x16CaseInstance (Context& context, glu::ShaderType shaderType, const ShaderSpec& spec, const char* name)
727 : ShaderPackingFunctionTestInstance (context, shaderType, spec, name)
731 tcu::TestStatus iterate (void)
733 const int maxDiff = 0; // All bits must be accurate.
734 de::Random rnd (deStringHash(m_name) ^ 0x776002);
735 std::vector<deUint32> inputs;
736 std::vector<tcu::Vec2> outputs;
739 inputs.push_back((tcu::Float16( 0.0f).bits() << 16) | tcu::Float16( 1.0f).bits());
740 inputs.push_back((tcu::Float16( 1.0f).bits() << 16) | tcu::Float16( 0.0f).bits());
741 inputs.push_back((tcu::Float16(-1.0f).bits() << 16) | tcu::Float16( 0.5f).bits());
742 inputs.push_back((tcu::Float16( 0.5f).bits() << 16) | tcu::Float16(-0.5f).bits());
744 // Construct random values.
746 const int minExp = -14;
747 const int maxExp = 15;
748 const int mantBits = 10;
750 for (int ndx = 0; ndx < 96; ndx++)
753 for (int c = 0; c < 2; c++)
755 const int s = rnd.getBool() ? 1 : -1;
756 const int exp = rnd.getInt(minExp, maxExp);
757 const deUint32 mantissa = rnd.getUint32() & ((1<<mantBits)-1);
758 const deUint16 value = tcu::Float16::construct(s, exp ? exp : 1 /* avoid denorm */, (deUint16)((1u<<10) | mantissa)).bits();
760 inVal |= value << (16*c);
762 inputs.push_back(inVal);
766 outputs.resize(inputs.size());
768 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
771 const void* in = &inputs[0];
772 void* out = &outputs[0];
774 m_executor->execute((int)inputs.size(), &in, &out);
779 const int numValues = (int)inputs.size();
780 const int maxPrints = 10;
783 for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
785 const deUint16 in0 = (deUint16)(inputs[valNdx] & 0xffff);
786 const deUint16 in1 = (deUint16)(inputs[valNdx] >> 16);
787 const float ref0 = tcu::Float16(in0).asFloat();
788 const float ref1 = tcu::Float16(in1).asFloat();
789 const float res0 = outputs[valNdx].x();
790 const float res1 = outputs[valNdx].y();
792 const deUint32 refBits0 = tcu::Float32(ref0).bits();
793 const deUint32 refBits1 = tcu::Float32(ref1).bits();
794 const deUint32 resBits0 = tcu::Float32(res0).bits();
795 const deUint32 resBits1 = tcu::Float32(res1).bits();
797 const int diff0 = de::abs((int)refBits0 - (int)resBits0);
798 const int diff1 = de::abs((int)refBits1 - (int)resBits1);
800 if (diff0 > maxDiff || diff1 > maxDiff)
802 if (numFailed < maxPrints)
804 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx << ",\n"
805 << " expected unpackHalf2x16(" << tcu::toHex(inputs[valNdx]) << ") = "
806 << "vec2(" << ref0 << " / " << tcu::toHex(refBits0) << ", " << ref1 << " / " << tcu::toHex(refBits1) << ")"
807 << ", got vec2(" << res0 << " / " << tcu::toHex(resBits0) << ", " << res1 << " / " << tcu::toHex(resBits1) << ")"
808 << "\n ULP diffs = (" << diff0 << ", " << diff1 << "), max diff = " << maxDiff
809 << TestLog::EndMessage;
811 else if (numFailed == maxPrints)
812 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
818 m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
821 return tcu::TestStatus::pass("Pass");
823 return tcu::TestStatus::fail("Result comparison failed");
829 class UnpackHalf2x16Case : public ShaderPackingFunctionCase
832 UnpackHalf2x16Case (tcu::TestContext& testCtx, glu::ShaderType shaderType)
833 : ShaderPackingFunctionCase (testCtx, (string("unpackhalf2x16") + getShaderTypePostfix(shaderType)).c_str(), "unpackHalf2x16", shaderType)
835 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
836 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_FLOAT_VEC2, glu::PRECISION_MEDIUMP)));
838 m_spec.source = "out0 = unpackHalf2x16(in0);";
841 TestInstance* createInstance (Context& ctx) const
843 return new UnpackHalf2x16CaseInstance(ctx, m_shaderType, m_spec, getName());
848 class PackSnorm4x8CaseInstance : public ShaderPackingFunctionTestInstance
851 PackSnorm4x8CaseInstance (Context& context, glu::ShaderType shaderType, const ShaderSpec& spec, glu::Precision precision, const char* name)
852 : ShaderPackingFunctionTestInstance (context, shaderType, spec, name)
853 , m_precision (precision)
857 tcu::TestStatus iterate (void)
859 de::Random rnd (deStringHash(m_name) ^ 0x42f2c0);
860 std::vector<tcu::Vec4> inputs;
861 std::vector<deUint32> outputs;
862 const int maxDiff = m_precision == glu::PRECISION_HIGHP ? 1 : // Rounding only.
863 m_precision == glu::PRECISION_MEDIUMP ? 1 : // (2^-10) * (2^7) + 1
864 m_precision == glu::PRECISION_LOWP ? 2 : 0; // (2^-8) * (2^7) + 1
866 // Special values to check.
867 inputs.push_back(tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f));
868 inputs.push_back(tcu::Vec4(-1.0f, 1.0f, -1.0f, 1.0f));
869 inputs.push_back(tcu::Vec4(0.5f, -0.5f, -0.5f, 0.5f));
870 inputs.push_back(tcu::Vec4(-1.5f, 1.5f, -1.5f, 1.5f));
871 inputs.push_back(tcu::Vec4(0.25f, -0.75f, -0.25f, 0.75f));
873 // Random values, mostly in range.
874 for (int ndx = 0; ndx < 15; ndx++)
876 const float x = rnd.getFloat()*2.5f - 1.25f;
877 const float y = rnd.getFloat()*2.5f - 1.25f;
878 const float z = rnd.getFloat()*2.5f - 1.25f;
879 const float w = rnd.getFloat()*2.5f - 1.25f;
880 inputs.push_back(tcu::Vec4(x, y, z, w));
883 // Large random values.
884 for (int ndx = 0; ndx < 80; ndx++)
886 const float x = rnd.getFloat()*1e6f - 0.5e6f;
887 const float y = rnd.getFloat()*1e6f - 0.5e6f;
888 const float z = rnd.getFloat()*1e6f - 0.5e6f;
889 const float w = rnd.getFloat()*1e6f - 0.5e6f;
890 inputs.push_back(tcu::Vec4(x, y, z, w));
893 outputs.resize(inputs.size());
895 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
898 const void* in = &inputs[0];
899 void* out = &outputs[0];
901 m_executor->execute((int)inputs.size(), &in, &out);
906 const int numValues = (int)inputs.size();
907 const int maxPrints = 10;
910 for (int valNdx = 0; valNdx < numValues; valNdx++)
912 const deUint16 ref0 = (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].x(), -1.0f, 1.0f) * 127.0f), -(1<<7), (1<<7)-1);
913 const deUint16 ref1 = (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].y(), -1.0f, 1.0f) * 127.0f), -(1<<7), (1<<7)-1);
914 const deUint16 ref2 = (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].z(), -1.0f, 1.0f) * 127.0f), -(1<<7), (1<<7)-1);
915 const deUint16 ref3 = (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].w(), -1.0f, 1.0f) * 127.0f), -(1<<7), (1<<7)-1);
916 const deUint32 ref = (deUint32(ref3) << 24) | (deUint32(ref2) << 16) | (deUint32(ref1) << 8) | deUint32(ref0);
917 const deUint32 res = outputs[valNdx];
918 const deUint16 res0 = (deUint8)(res & 0xff);
919 const deUint16 res1 = (deUint8)((res >> 8) & 0xff);
920 const deUint16 res2 = (deUint8)((res >> 16) & 0xff);
921 const deUint16 res3 = (deUint8)((res >> 24) & 0xff);
922 const int diff0 = de::abs((int)ref0 - (int)res0);
923 const int diff1 = de::abs((int)ref1 - (int)res1);
924 const int diff2 = de::abs((int)ref2 - (int)res2);
925 const int diff3 = de::abs((int)ref3 - (int)res3);
927 if (diff0 > maxDiff || diff1 > maxDiff || diff2 > maxDiff || diff3 > maxDiff)
929 if (numFailed < maxPrints)
931 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx
932 << ", expected packSnorm4x8(" << inputs[valNdx] << ") = " << tcu::toHex(ref)
933 << ", got " << tcu::toHex(res)
934 << "\n diffs = " << tcu::IVec4(diff0, diff1, diff2, diff3) << ", max diff = " << maxDiff
935 << TestLog::EndMessage;
937 else if (numFailed == maxPrints)
938 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
944 m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
947 return tcu::TestStatus::pass("Pass");
949 return tcu::TestStatus::fail("Result comparison failed");
955 const glu::Precision m_precision;
958 class PackSnorm4x8Case : public ShaderPackingFunctionCase
961 PackSnorm4x8Case (tcu::TestContext& testCtx, glu::ShaderType shaderType, glu::Precision precision)
962 : ShaderPackingFunctionCase (testCtx, (string("packsnorm4x8") + getPrecisionPostfix(precision) + getShaderTypePostfix(shaderType)).c_str(), "packSnorm4x8", shaderType)
963 , m_precision (precision)
965 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_FLOAT_VEC4, precision)));
966 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
968 m_spec.source = "out0 = packSnorm4x8(in0);";
971 TestInstance* createInstance (Context& ctx) const
973 return new PackSnorm4x8CaseInstance(ctx, m_shaderType, m_spec, m_precision, getName());
977 const glu::Precision m_precision;
980 class UnpackSnorm4x8CaseInstance : public ShaderPackingFunctionTestInstance
983 UnpackSnorm4x8CaseInstance (Context& context, glu::ShaderType shaderType, const ShaderSpec& spec, const char* name)
984 : ShaderPackingFunctionTestInstance (context, shaderType, spec, name)
988 tcu::TestStatus iterate (void)
990 const deUint32 maxDiff = 1; // Rounding error.
991 de::Random rnd (deStringHash(m_name) ^ 0x776002);
992 std::vector<deUint32> inputs;
993 std::vector<tcu::Vec4> outputs;
995 inputs.push_back(0x00000000u);
996 inputs.push_back(0x7fff8000u);
997 inputs.push_back(0x80007fffu);
998 inputs.push_back(0xffffffffu);
999 inputs.push_back(0x0001fffeu);
1002 for (int ndx = 0; ndx < 95; ndx++)
1003 inputs.push_back(rnd.getUint32());
1005 outputs.resize(inputs.size());
1007 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
1010 const void* in = &inputs[0];
1011 void* out = &outputs[0];
1013 m_executor->execute((int)inputs.size(), &in, &out);
1018 const int numValues = (int)inputs.size();
1019 const int maxPrints = 10;
1022 for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
1024 const deInt8 in0 = (deInt8)(deUint8)(inputs[valNdx] & 0xff);
1025 const deInt8 in1 = (deInt8)(deUint8)((inputs[valNdx] >> 8) & 0xff);
1026 const deInt8 in2 = (deInt8)(deUint8)((inputs[valNdx] >> 16) & 0xff);
1027 const deInt8 in3 = (deInt8)(deUint8)(inputs[valNdx] >> 24);
1028 const float ref0 = de::clamp(float(in0) / 127.f, -1.0f, 1.0f);
1029 const float ref1 = de::clamp(float(in1) / 127.f, -1.0f, 1.0f);
1030 const float ref2 = de::clamp(float(in2) / 127.f, -1.0f, 1.0f);
1031 const float ref3 = de::clamp(float(in3) / 127.f, -1.0f, 1.0f);
1032 const float res0 = outputs[valNdx].x();
1033 const float res1 = outputs[valNdx].y();
1034 const float res2 = outputs[valNdx].z();
1035 const float res3 = outputs[valNdx].w();
1037 const deUint32 diff0 = getUlpDiff(ref0, res0);
1038 const deUint32 diff1 = getUlpDiff(ref1, res1);
1039 const deUint32 diff2 = getUlpDiff(ref2, res2);
1040 const deUint32 diff3 = getUlpDiff(ref3, res3);
1042 if (diff0 > maxDiff || diff1 > maxDiff || diff2 > maxDiff || diff3 > maxDiff)
1044 if (numFailed < maxPrints)
1046 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx << ",\n"
1047 << " expected unpackSnorm4x8(" << tcu::toHex(inputs[valNdx]) << ") = "
1048 << "vec4(" << HexFloat(ref0) << ", " << HexFloat(ref1) << ", " << HexFloat(ref2) << ", " << HexFloat(ref3) << ")"
1049 << ", got vec4(" << HexFloat(res0) << ", " << HexFloat(res1) << ", " << HexFloat(res2) << ", " << HexFloat(res3) << ")"
1050 << "\n ULP diffs = (" << diff0 << ", " << diff1 << ", " << diff2 << ", " << diff3 << "), max diff = " << maxDiff
1051 << TestLog::EndMessage;
1053 else if (numFailed == maxPrints)
1054 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
1060 m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
1063 return tcu::TestStatus::pass("Pass");
1065 return tcu::TestStatus::fail("Result comparison failed");
1072 class UnpackSnorm4x8Case : public ShaderPackingFunctionCase
1075 UnpackSnorm4x8Case (tcu::TestContext& testCtx, glu::ShaderType shaderType)
1076 : ShaderPackingFunctionCase (testCtx, (string("unpacksnorm4x8") + getShaderTypePostfix(shaderType)).c_str(), "unpackSnorm4x8", shaderType)
1078 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
1079 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP)));
1081 m_spec.source = "out0 = unpackSnorm4x8(in0);";
1084 TestInstance* createInstance (Context& ctx) const
1086 return new UnpackSnorm4x8CaseInstance(ctx, m_shaderType, m_spec, getName());
1091 class PackUnorm4x8CaseInstance : public ShaderPackingFunctionTestInstance
1094 PackUnorm4x8CaseInstance (Context& context, glu::ShaderType shaderType, const ShaderSpec& spec, glu::Precision precision, const char* name)
1095 : ShaderPackingFunctionTestInstance (context, shaderType, spec, name)
1096 , m_precision (precision)
1100 tcu::TestStatus iterate (void)
1102 de::Random rnd (deStringHash(m_name) ^ 0x776002);
1103 std::vector<tcu::Vec4> inputs;
1104 std::vector<deUint32> outputs;
1105 const int maxDiff = m_precision == glu::PRECISION_HIGHP ? 1 : // Rounding only.
1106 m_precision == glu::PRECISION_MEDIUMP ? 1 : // (2^-10) * (2^8) + 1
1107 m_precision == glu::PRECISION_LOWP ? 2 : 0; // (2^-8) * (2^8) + 1
1109 // Special values to check.
1110 inputs.push_back(tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f));
1111 inputs.push_back(tcu::Vec4(-1.0f, 1.0f, -1.0f, 1.0f));
1112 inputs.push_back(tcu::Vec4(0.5f, -0.5f, -0.5f, 0.5f));
1113 inputs.push_back(tcu::Vec4(-1.5f, 1.5f, -1.5f, 1.5f));
1114 inputs.push_back(tcu::Vec4(0.25f, -0.75f, -0.25f, 0.75f));
1116 // Random values, mostly in range.
1117 for (int ndx = 0; ndx < 15; ndx++)
1119 const float x = rnd.getFloat()*1.25f - 0.125f;
1120 const float y = rnd.getFloat()*1.25f - 0.125f;
1121 const float z = rnd.getFloat()*1.25f - 0.125f;
1122 const float w = rnd.getFloat()*1.25f - 0.125f;
1123 inputs.push_back(tcu::Vec4(x, y, z, w));
1126 // Large random values.
1127 for (int ndx = 0; ndx < 80; ndx++)
1129 const float x = rnd.getFloat()*1e6f - 1e5f;
1130 const float y = rnd.getFloat()*1e6f - 1e5f;
1131 const float z = rnd.getFloat()*1e6f - 1e5f;
1132 const float w = rnd.getFloat()*1e6f - 1e5f;
1133 inputs.push_back(tcu::Vec4(x, y, z, w));
1136 outputs.resize(inputs.size());
1138 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
1141 const void* in = &inputs[0];
1142 void* out = &outputs[0];
1144 m_executor->execute((int)inputs.size(), &in, &out);
1149 const int numValues = (int)inputs.size();
1150 const int maxPrints = 10;
1153 for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
1155 const deUint16 ref0 = (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].x(), 0.0f, 1.0f) * 255.0f), 0, (1<<8)-1);
1156 const deUint16 ref1 = (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].y(), 0.0f, 1.0f) * 255.0f), 0, (1<<8)-1);
1157 const deUint16 ref2 = (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].z(), 0.0f, 1.0f) * 255.0f), 0, (1<<8)-1);
1158 const deUint16 ref3 = (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].w(), 0.0f, 1.0f) * 255.0f), 0, (1<<8)-1);
1159 const deUint32 ref = (deUint32(ref3) << 24) | (deUint32(ref2) << 16) | (deUint32(ref1) << 8) | deUint32(ref0);
1160 const deUint32 res = outputs[valNdx];
1161 const deUint16 res0 = (deUint8)(res & 0xff);
1162 const deUint16 res1 = (deUint8)((res >> 8) & 0xff);
1163 const deUint16 res2 = (deUint8)((res >> 16) & 0xff);
1164 const deUint16 res3 = (deUint8)((res >> 24) & 0xff);
1165 const int diff0 = de::abs((int)ref0 - (int)res0);
1166 const int diff1 = de::abs((int)ref1 - (int)res1);
1167 const int diff2 = de::abs((int)ref2 - (int)res2);
1168 const int diff3 = de::abs((int)ref3 - (int)res3);
1170 if (diff0 > maxDiff || diff1 > maxDiff || diff2 > maxDiff || diff3 > maxDiff)
1172 if (numFailed < maxPrints)
1174 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx
1175 << ", expected packUnorm4x8(" << inputs[valNdx] << ") = " << tcu::toHex(ref)
1176 << ", got " << tcu::toHex(res)
1177 << "\n diffs = " << tcu::IVec4(diff0, diff1, diff2, diff3) << ", max diff = " << maxDiff
1178 << TestLog::EndMessage;
1180 else if (numFailed == maxPrints)
1181 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
1187 m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
1190 return tcu::TestStatus::pass("Pass");
1192 return tcu::TestStatus::fail("Result comparison failed");
1198 const glu::Precision m_precision;
1201 class PackUnorm4x8Case : public ShaderPackingFunctionCase
1204 PackUnorm4x8Case (tcu::TestContext& testCtx, glu::ShaderType shaderType, glu::Precision precision)
1205 : ShaderPackingFunctionCase (testCtx, (string("packunorm4x8") + getPrecisionPostfix(precision) + getShaderTypePostfix(shaderType)).c_str(), "packUnorm4x8", shaderType)
1206 , m_precision (precision)
1208 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_FLOAT_VEC4, precision)));
1209 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
1211 m_spec.source = "out0 = packUnorm4x8(in0);";
1214 TestInstance* createInstance (Context& ctx) const
1216 return new PackUnorm4x8CaseInstance(ctx, m_shaderType, m_spec, m_precision, getName());
1220 const glu::Precision m_precision;
1223 class UnpackUnorm4x8CaseInstance : public ShaderPackingFunctionTestInstance
1226 UnpackUnorm4x8CaseInstance (Context& context, glu::ShaderType shaderType, const ShaderSpec& spec, const char* name)
1227 : ShaderPackingFunctionTestInstance (context, shaderType, spec, name)
1231 tcu::TestStatus iterate (void)
1233 const deUint32 maxDiff = 1; // Rounding error.
1234 de::Random rnd (deStringHash(m_name) ^ 0x776002);
1235 std::vector<deUint32> inputs;
1236 std::vector<tcu::Vec4> outputs;
1238 inputs.push_back(0x00000000u);
1239 inputs.push_back(0x7fff8000u);
1240 inputs.push_back(0x80007fffu);
1241 inputs.push_back(0xffffffffu);
1242 inputs.push_back(0x0001fffeu);
1245 for (int ndx = 0; ndx < 95; ndx++)
1246 inputs.push_back(rnd.getUint32());
1248 outputs.resize(inputs.size());
1250 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
1253 const void* in = &inputs[0];
1254 void* out = &outputs[0];
1256 m_executor->execute((int)inputs.size(), &in, &out);
1261 const int numValues = (int)inputs.size();
1262 const int maxPrints = 10;
1265 for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
1267 const deUint8 in0 = (deUint8)(inputs[valNdx] & 0xff);
1268 const deUint8 in1 = (deUint8)((inputs[valNdx] >> 8) & 0xff);
1269 const deUint8 in2 = (deUint8)((inputs[valNdx] >> 16) & 0xff);
1270 const deUint8 in3 = (deUint8)(inputs[valNdx] >> 24);
1271 const float ref0 = de::clamp(float(in0) / 255.f, 0.0f, 1.0f);
1272 const float ref1 = de::clamp(float(in1) / 255.f, 0.0f, 1.0f);
1273 const float ref2 = de::clamp(float(in2) / 255.f, 0.0f, 1.0f);
1274 const float ref3 = de::clamp(float(in3) / 255.f, 0.0f, 1.0f);
1275 const float res0 = outputs[valNdx].x();
1276 const float res1 = outputs[valNdx].y();
1277 const float res2 = outputs[valNdx].z();
1278 const float res3 = outputs[valNdx].w();
1280 const deUint32 diff0 = getUlpDiff(ref0, res0);
1281 const deUint32 diff1 = getUlpDiff(ref1, res1);
1282 const deUint32 diff2 = getUlpDiff(ref2, res2);
1283 const deUint32 diff3 = getUlpDiff(ref3, res3);
1285 if (diff0 > maxDiff || diff1 > maxDiff || diff2 > maxDiff || diff3 > maxDiff)
1287 if (numFailed < maxPrints)
1289 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx << ",\n"
1290 << " expected unpackUnorm4x8(" << tcu::toHex(inputs[valNdx]) << ") = "
1291 << "vec4(" << HexFloat(ref0) << ", " << HexFloat(ref1) << ", " << HexFloat(ref2) << ", " << HexFloat(ref3) << ")"
1292 << ", got vec4(" << HexFloat(res0) << ", " << HexFloat(res1) << ", " << HexFloat(res2) << ", " << HexFloat(res3) << ")"
1293 << "\n ULP diffs = (" << diff0 << ", " << diff1 << ", " << diff2 << ", " << diff3 << "), max diff = " << maxDiff
1294 << TestLog::EndMessage;
1296 else if (numFailed == maxPrints)
1297 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
1303 m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
1306 return tcu::TestStatus::pass("Pass");
1308 return tcu::TestStatus::fail("Result comparison failed");
1314 class UnpackUnorm4x8Case : public ShaderPackingFunctionCase
1317 UnpackUnorm4x8Case (tcu::TestContext& testCtx, glu::ShaderType shaderType)
1318 : ShaderPackingFunctionCase (testCtx, (string("unpackunorm4x8") + getShaderTypePostfix(shaderType)).c_str(), "unpackUnorm4x8", shaderType)
1320 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
1321 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP)));
1323 m_spec.source = "out0 = unpackUnorm4x8(in0);";
1326 TestInstance* createInstance (Context& ctx) const
1328 return new UnpackUnorm4x8CaseInstance(ctx, m_shaderType, m_spec, getName());
1333 ShaderPackingFunctionTests::ShaderPackingFunctionTests (tcu::TestContext& testCtx)
1334 : tcu::TestCaseGroup (testCtx, "pack_unpack", "Floating-point pack and unpack function tests")
1338 ShaderPackingFunctionTests::~ShaderPackingFunctionTests (void)
1342 void ShaderPackingFunctionTests::init (void)
1344 // New built-in functions in GLES 3.1
1346 const glu::ShaderType allShaderTypes[] =
1348 glu::SHADERTYPE_VERTEX,
1349 glu::SHADERTYPE_TESSELLATION_CONTROL,
1350 glu::SHADERTYPE_TESSELLATION_EVALUATION,
1351 glu::SHADERTYPE_GEOMETRY,
1352 glu::SHADERTYPE_FRAGMENT,
1353 glu::SHADERTYPE_COMPUTE
1357 for (int prec = glu::PRECISION_MEDIUMP; prec < glu::PRECISION_LAST; prec++)
1359 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(allShaderTypes); shaderTypeNdx++)
1360 addChild(new PackSnorm4x8Case(m_testCtx, allShaderTypes[shaderTypeNdx], glu::Precision(prec)));
1364 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(allShaderTypes); shaderTypeNdx++)
1365 addChild(new UnpackSnorm4x8Case(m_testCtx, allShaderTypes[shaderTypeNdx]));
1368 for (int prec = glu::PRECISION_MEDIUMP; prec < glu::PRECISION_LAST; prec++)
1370 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(allShaderTypes); shaderTypeNdx++)
1371 addChild(new PackUnorm4x8Case(m_testCtx, allShaderTypes[shaderTypeNdx], glu::Precision(prec)));
1375 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(allShaderTypes); shaderTypeNdx++)
1376 addChild(new UnpackUnorm4x8Case(m_testCtx, allShaderTypes[shaderTypeNdx]));
1379 // GLES 3 functions in new shader types.
1381 const glu::ShaderType newShaderTypes[] =
1383 glu::SHADERTYPE_GEOMETRY,
1384 glu::SHADERTYPE_COMPUTE
1388 for (int prec = glu::PRECISION_MEDIUMP; prec < glu::PRECISION_LAST; prec++)
1390 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(newShaderTypes); shaderTypeNdx++)
1391 addChild(new PackSnorm2x16Case(m_testCtx, newShaderTypes[shaderTypeNdx], glu::Precision(prec)));
1395 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(newShaderTypes); shaderTypeNdx++)
1396 addChild(new UnpackSnorm2x16Case(m_testCtx, newShaderTypes[shaderTypeNdx]));
1399 for (int prec = glu::PRECISION_MEDIUMP; prec < glu::PRECISION_LAST; prec++)
1401 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(newShaderTypes); shaderTypeNdx++)
1402 addChild(new PackUnorm2x16Case(m_testCtx, newShaderTypes[shaderTypeNdx], glu::Precision(prec)));
1406 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(newShaderTypes); shaderTypeNdx++)
1407 addChild(new UnpackUnorm2x16Case(m_testCtx, newShaderTypes[shaderTypeNdx]));
1410 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(newShaderTypes); shaderTypeNdx++)
1411 addChild(new PackHalf2x16Case(m_testCtx, newShaderTypes[shaderTypeNdx]));
1414 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(newShaderTypes); shaderTypeNdx++)
1415 addChild(new UnpackHalf2x16Case(m_testCtx, newShaderTypes[shaderTypeNdx]));