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 m_executor->setShaderSources(programCollection);
109 virtual TestInstance* createInstance (Context& context) const = 0;
113 const glu::ShaderType m_shaderType;
115 de::SharedPtr<ShaderExecutor> m_executor;
118 ShaderPackingFunctionCase (const ShaderPackingFunctionCase& other);
119 ShaderPackingFunctionCase& operator= (const ShaderPackingFunctionCase& other);
122 ShaderPackingFunctionCase::ShaderPackingFunctionCase (tcu::TestContext& testCtx, const char* name, const char* description, glu::ShaderType shaderType)
123 : TestCase (testCtx, name, description)
124 , m_shaderType (shaderType)
125 , m_executor (DE_NULL)
129 ShaderPackingFunctionCase::~ShaderPackingFunctionCase (void)
133 void ShaderPackingFunctionCase::init (void)
135 DE_ASSERT(!m_executor);
137 m_executor = de::SharedPtr<ShaderExecutor>(createExecutor(m_shaderType, m_spec));
138 m_testCtx.getLog() << *m_executor;
141 // ShaderPackingFunctionTestInstance
143 class ShaderPackingFunctionTestInstance : public TestInstance
146 ShaderPackingFunctionTestInstance (Context& context, glu::ShaderType shaderType, ShaderSpec spec, de::SharedPtr<ShaderExecutor> executor, const char* name)
147 : TestInstance (context)
148 , m_testCtx (context.getTestContext())
149 , m_shaderType (shaderType)
152 , m_executor (executor)
155 virtual tcu::TestStatus iterate (void) = 0;
157 tcu::TestContext& m_testCtx;
158 const glu::ShaderType m_shaderType;
161 de::SharedPtr<ShaderExecutor> m_executor;
166 class PackSnorm2x16CaseInstance: public ShaderPackingFunctionTestInstance
169 PackSnorm2x16CaseInstance (Context& context, glu::ShaderType shaderType, ShaderSpec spec, glu::Precision precision, de::SharedPtr<ShaderExecutor> executor, const char* name)
170 : ShaderPackingFunctionTestInstance (context, shaderType, spec, executor, name)
171 , m_precision (precision)
175 tcu::TestStatus iterate (void)
177 de::Random rnd (deStringHash(m_name) ^ 0x776002);
178 std::vector<tcu::Vec2> inputs;
179 std::vector<deUint32> outputs;
180 const int maxDiff = m_precision == glu::PRECISION_HIGHP ? 1 : // Rounding only.
181 m_precision == glu::PRECISION_MEDIUMP ? 33 : // (2^-10) * (2^15) + 1
182 m_precision == glu::PRECISION_LOWP ? 129 : 0; // (2^-8) * (2^15) + 1
184 // Special values to check.
185 inputs.push_back(tcu::Vec2(0.0f, 0.0f));
186 inputs.push_back(tcu::Vec2(-1.0f, 1.0f));
187 inputs.push_back(tcu::Vec2(0.5f, -0.5f));
188 inputs.push_back(tcu::Vec2(-1.5f, 1.5f));
189 inputs.push_back(tcu::Vec2(0.25f, -0.75f));
191 // Random values, mostly in range.
192 for (int ndx = 0; ndx < 15; ndx++)
194 const float x = rnd.getFloat()*2.5f - 1.25f;
195 const float y = rnd.getFloat()*2.5f - 1.25f;
196 inputs.push_back(tcu::Vec2(x, y));
199 // Large random values.
200 for (int ndx = 0; ndx < 80; ndx++)
202 const float x = rnd.getFloat()*1e6f - 0.5e6f;
203 const float y = rnd.getFloat()*1e6f - 0.5e6f;
204 inputs.push_back(tcu::Vec2(x, y));
207 outputs.resize(inputs.size());
209 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
212 const void* in = &inputs[0];
213 void* out = &outputs[0];
215 m_executor->execute(m_context, (int)inputs.size(), &in, &out);
220 const int numValues = (int)inputs.size();
221 const int maxPrints = 10;
224 for (int valNdx = 0; valNdx < numValues; valNdx++)
226 const deUint16 ref0 = (deUint16)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].x(), -1.0f, 1.0f) * 32767.0f), -(1<<15), (1<<15)-1);
227 const deUint16 ref1 = (deUint16)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].y(), -1.0f, 1.0f) * 32767.0f), -(1<<15), (1<<15)-1);
228 const deUint32 ref = (ref1 << 16) | ref0;
229 const deUint32 res = outputs[valNdx];
230 const deUint16 res0 = (deUint16)(res & 0xffff);
231 const deUint16 res1 = (deUint16)(res >> 16);
232 const int diff0 = de::abs((int)ref0 - (int)res0);
233 const int diff1 = de::abs((int)ref1 - (int)res1);
235 if (diff0 > maxDiff || diff1 > maxDiff)
237 if (numFailed < maxPrints)
239 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx
240 << ", expected packSnorm2x16(" << inputs[valNdx] << ") = " << tcu::toHex(ref)
241 << ", got " << tcu::toHex(res)
242 << "\n diffs = (" << diff0 << ", " << diff1 << "), max diff = " << maxDiff
243 << TestLog::EndMessage;
245 else if (numFailed == maxPrints)
246 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
252 m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
255 return tcu::TestStatus::pass("Pass");
257 return tcu::TestStatus::fail("Result comparison failed");
263 const glu::Precision m_precision;
266 class PackSnorm2x16Case : public ShaderPackingFunctionCase
269 PackSnorm2x16Case (tcu::TestContext& testCtx, glu::ShaderType shaderType, glu::Precision precision)
270 : ShaderPackingFunctionCase (testCtx, (string("packsnorm2x16") + getPrecisionPostfix(precision) + getShaderTypePostfix(shaderType)).c_str(), "packSnorm2x16", shaderType)
271 , m_precision (precision)
273 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_FLOAT_VEC2, precision)));
274 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
276 m_spec.source = "out0 = packSnorm2x16(in0);";
280 TestInstance* createInstance (Context& ctx) const
282 return new PackSnorm2x16CaseInstance(ctx, m_shaderType, m_spec, m_precision, m_executor, getName());
286 const glu::Precision m_precision;
289 class UnpackSnorm2x16CaseInstance : public ShaderPackingFunctionTestInstance
292 UnpackSnorm2x16CaseInstance (Context& context, glu::ShaderType shaderType, ShaderSpec spec, de::SharedPtr<ShaderExecutor> executor, const char* name)
293 : ShaderPackingFunctionTestInstance (context, shaderType, spec, executor, name)
297 tcu::TestStatus iterate (void)
299 const deUint32 maxDiff = 1; // Rounding error.
300 de::Random rnd (deStringHash(m_name) ^ 0x776002);
301 std::vector<deUint32> inputs;
302 std::vector<tcu::Vec2> outputs;
304 inputs.push_back(0x00000000u);
305 inputs.push_back(0x7fff8000u);
306 inputs.push_back(0x80007fffu);
307 inputs.push_back(0xffffffffu);
308 inputs.push_back(0x0001fffeu);
311 for (int ndx = 0; ndx < 95; ndx++)
312 inputs.push_back(rnd.getUint32());
314 outputs.resize(inputs.size());
316 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
319 const void* in = &inputs[0];
320 void* out = &outputs[0];
322 m_executor->execute(m_context, (int)inputs.size(), &in, &out);
327 const int numValues = (int)inputs.size();
328 const int maxPrints = 10;
331 for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
333 const deInt16 in0 = (deInt16)(deUint16)(inputs[valNdx] & 0xffff);
334 const deInt16 in1 = (deInt16)(deUint16)(inputs[valNdx] >> 16);
335 const float ref0 = de::clamp(float(in0) / 32767.f, -1.0f, 1.0f);
336 const float ref1 = de::clamp(float(in1) / 32767.f, -1.0f, 1.0f);
337 const float res0 = outputs[valNdx].x();
338 const float res1 = outputs[valNdx].y();
340 const deUint32 diff0 = getUlpDiff(ref0, res0);
341 const deUint32 diff1 = getUlpDiff(ref1, res1);
343 if (diff0 > maxDiff || diff1 > maxDiff)
345 if (numFailed < maxPrints)
347 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx << ",\n"
348 << " expected unpackSnorm2x16(" << tcu::toHex(inputs[valNdx]) << ") = "
349 << "vec2(" << HexFloat(ref0) << ", " << HexFloat(ref1) << ")"
350 << ", got vec2(" << HexFloat(res0) << ", " << HexFloat(res1) << ")"
351 << "\n ULP diffs = (" << diff0 << ", " << diff1 << "), max diff = " << maxDiff
352 << TestLog::EndMessage;
354 else if (numFailed == maxPrints)
355 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
361 m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
364 return tcu::TestStatus::pass("Pass");
366 return tcu::TestStatus::fail("Result comparison failed");
372 class UnpackSnorm2x16Case : public ShaderPackingFunctionCase
375 UnpackSnorm2x16Case (tcu::TestContext& testCtx, glu::ShaderType shaderType)
376 : ShaderPackingFunctionCase (testCtx, (string("unpacksnorm2x16") + getShaderTypePostfix(shaderType)).c_str(), "unpackSnorm2x16", shaderType)
378 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
379 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_FLOAT_VEC2, glu::PRECISION_HIGHP)));
381 m_spec.source = "out0 = unpackSnorm2x16(in0);";
385 TestInstance* createInstance (Context& ctx) const
387 return new UnpackSnorm2x16CaseInstance(ctx, m_shaderType, m_spec, m_executor, getName());
391 class PackUnorm2x16CaseInstance : public ShaderPackingFunctionTestInstance
394 PackUnorm2x16CaseInstance (Context& context, glu::ShaderType shaderType, ShaderSpec spec, glu::Precision precision, de::SharedPtr<ShaderExecutor> executor, const char* name)
395 : ShaderPackingFunctionTestInstance (context, shaderType, spec, executor, name)
396 , m_precision (precision)
400 tcu::TestStatus iterate (void)
402 de::Random rnd (deStringHash(m_name) ^ 0x776002);
403 std::vector<tcu::Vec2> inputs;
404 std::vector<deUint32> outputs;
405 const int maxDiff = m_precision == glu::PRECISION_HIGHP ? 1 : // Rounding only.
406 m_precision == glu::PRECISION_MEDIUMP ? 65 : // (2^-10) * (2^16) + 1
407 m_precision == glu::PRECISION_LOWP ? 257 : 0; // (2^-8) * (2^16) + 1
409 // Special values to check.
410 inputs.push_back(tcu::Vec2(0.0f, 0.0f));
411 inputs.push_back(tcu::Vec2(0.5f, 1.0f));
412 inputs.push_back(tcu::Vec2(1.0f, 0.5f));
413 inputs.push_back(tcu::Vec2(-0.5f, 1.5f));
414 inputs.push_back(tcu::Vec2(0.25f, 0.75f));
416 // Random values, mostly in range.
417 for (int ndx = 0; ndx < 15; ndx++)
419 const float x = rnd.getFloat()*1.25f;
420 const float y = rnd.getFloat()*1.25f;
421 inputs.push_back(tcu::Vec2(x, y));
424 // Large random values.
425 for (int ndx = 0; ndx < 80; ndx++)
427 const float x = rnd.getFloat()*1e6f - 1e5f;
428 const float y = rnd.getFloat()*1e6f - 1e5f;
429 inputs.push_back(tcu::Vec2(x, y));
432 outputs.resize(inputs.size());
434 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
437 const void* in = &inputs[0];
438 void* out = &outputs[0];
440 m_executor->execute(m_context, (int)inputs.size(), &in, &out);
445 const int numValues = (int)inputs.size();
446 const int maxPrints = 10;
449 for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
451 const deUint16 ref0 = (deUint16)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].x(), 0.0f, 1.0f) * 65535.0f), 0, (1<<16)-1);
452 const deUint16 ref1 = (deUint16)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].y(), 0.0f, 1.0f) * 65535.0f), 0, (1<<16)-1);
453 const deUint32 ref = (ref1 << 16) | ref0;
454 const deUint32 res = outputs[valNdx];
455 const deUint16 res0 = (deUint16)(res & 0xffff);
456 const deUint16 res1 = (deUint16)(res >> 16);
457 const int diff0 = de::abs((int)ref0 - (int)res0);
458 const int diff1 = de::abs((int)ref1 - (int)res1);
460 if (diff0 > maxDiff || diff1 > maxDiff)
462 if (numFailed < maxPrints)
464 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx
465 << ", expected packUnorm2x16(" << inputs[valNdx] << ") = " << tcu::toHex(ref)
466 << ", got " << tcu::toHex(res)
467 << "\n diffs = (" << diff0 << ", " << diff1 << "), max diff = " << maxDiff
468 << TestLog::EndMessage;
470 else if (numFailed == maxPrints)
471 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
477 m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
480 return tcu::TestStatus::pass("Pass");
482 return tcu::TestStatus::fail("Result comparison failed");
488 const glu::Precision m_precision;
491 class PackUnorm2x16Case : public ShaderPackingFunctionCase
494 PackUnorm2x16Case (tcu::TestContext& testCtx, glu::ShaderType shaderType, glu::Precision precision)
495 : ShaderPackingFunctionCase (testCtx, (string("packunorm2x16") + getPrecisionPostfix(precision) + getShaderTypePostfix(shaderType)).c_str(), "packUnorm2x16", shaderType)
496 , m_precision (precision)
498 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_FLOAT_VEC2, precision)));
499 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
501 m_spec.source = "out0 = packUnorm2x16(in0);";
505 TestInstance* createInstance (Context& ctx) const
507 return new PackUnorm2x16CaseInstance(ctx, m_shaderType, m_spec, m_precision, m_executor, getName());
511 const glu::Precision m_precision;
514 class UnpackUnorm2x16CaseInstance : public ShaderPackingFunctionTestInstance
517 UnpackUnorm2x16CaseInstance (Context& context, glu::ShaderType shaderType, ShaderSpec spec, de::SharedPtr<ShaderExecutor> executor, const char* name)
518 : ShaderPackingFunctionTestInstance (context, shaderType, spec, executor, name)
522 tcu::TestStatus iterate (void)
524 const deUint32 maxDiff = 1; // Rounding error.
525 de::Random rnd (deStringHash(m_name) ^ 0x776002);
526 std::vector<deUint32> inputs;
527 std::vector<tcu::Vec2> outputs;
529 inputs.push_back(0x00000000u);
530 inputs.push_back(0x7fff8000u);
531 inputs.push_back(0x80007fffu);
532 inputs.push_back(0xffffffffu);
533 inputs.push_back(0x0001fffeu);
536 for (int ndx = 0; ndx < 95; ndx++)
537 inputs.push_back(rnd.getUint32());
539 outputs.resize(inputs.size());
541 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
544 const void* in = &inputs[0];
545 void* out = &outputs[0];
547 m_executor->execute(m_context, (int)inputs.size(), &in, &out);
552 const int numValues = (int)inputs.size();
553 const int maxPrints = 10;
556 for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
558 const deUint16 in0 = (deUint16)(inputs[valNdx] & 0xffff);
559 const deUint16 in1 = (deUint16)(inputs[valNdx] >> 16);
560 const float ref0 = float(in0) / 65535.0f;
561 const float ref1 = float(in1) / 65535.0f;
562 const float res0 = outputs[valNdx].x();
563 const float res1 = outputs[valNdx].y();
565 const deUint32 diff0 = getUlpDiff(ref0, res0);
566 const deUint32 diff1 = getUlpDiff(ref1, res1);
568 if (diff0 > maxDiff || diff1 > maxDiff)
570 if (numFailed < maxPrints)
572 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx << ",\n"
573 << " expected unpackUnorm2x16(" << tcu::toHex(inputs[valNdx]) << ") = "
574 << "vec2(" << HexFloat(ref0) << ", " << HexFloat(ref1) << ")"
575 << ", got vec2(" << HexFloat(res0) << ", " << HexFloat(res1) << ")"
576 << "\n ULP diffs = (" << diff0 << ", " << diff1 << "), max diff = " << maxDiff
577 << TestLog::EndMessage;
579 else if (numFailed == maxPrints)
580 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
586 m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
589 return tcu::TestStatus::pass("Pass");
591 return tcu::TestStatus::fail("Result comparison failed");
598 class UnpackUnorm2x16Case : public ShaderPackingFunctionCase
601 UnpackUnorm2x16Case (tcu::TestContext& testCtx, glu::ShaderType shaderType)
602 : ShaderPackingFunctionCase(testCtx, (string("unpackunorm2x16") + getShaderTypePostfix(shaderType)).c_str(), "unpackUnorm2x16", shaderType)
604 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
605 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_FLOAT_VEC2, glu::PRECISION_HIGHP)));
607 m_spec.source = "out0 = unpackUnorm2x16(in0);";
611 TestInstance* createInstance (Context& ctx) const
613 return new UnpackUnorm2x16CaseInstance(ctx, m_shaderType, m_spec, m_executor, getName());
618 class PackHalf2x16CaseInstance : public ShaderPackingFunctionTestInstance
621 PackHalf2x16CaseInstance (Context& context, glu::ShaderType shaderType, ShaderSpec spec, de::SharedPtr<ShaderExecutor> executor, const char* name)
622 : ShaderPackingFunctionTestInstance (context, shaderType, spec, executor, name)
626 tcu::TestStatus iterate (void)
628 const int maxDiff = 0; // Values can be represented exactly in mediump.
629 de::Random rnd (deStringHash(m_name) ^ 0x776002);
630 std::vector<tcu::Vec2> inputs;
631 std::vector<deUint32> outputs;
633 // Special values to check.
634 inputs.push_back(tcu::Vec2(0.0f, 0.0f));
635 inputs.push_back(tcu::Vec2(0.5f, 1.0f));
636 inputs.push_back(tcu::Vec2(1.0f, 0.5f));
637 inputs.push_back(tcu::Vec2(-0.5f, 1.5f));
638 inputs.push_back(tcu::Vec2(0.25f, 0.75f));
642 const int minExp = -14;
643 const int maxExp = 15;
645 for (int ndx = 0; ndx < 95; ndx++)
648 for (int c = 0; c < 2; c++)
650 const int s = rnd.getBool() ? 1 : -1;
651 const int exp = rnd.getInt(minExp, maxExp);
652 const deUint32 mantissa = rnd.getUint32() & ((1<<23)-1);
654 v[c] = tcu::Float32::construct(s, exp ? exp : 1 /* avoid denormals */, (1u<<23) | mantissa).asFloat();
660 // Convert input values to fp16 and back to make sure they can be represented exactly in mediump.
661 for (std::vector<tcu::Vec2>::iterator inVal = inputs.begin(); inVal != inputs.end(); ++inVal)
662 *inVal = tcu::Vec2(tcu::Float16(inVal->x()).asFloat(), tcu::Float16(inVal->y()).asFloat());
664 outputs.resize(inputs.size());
666 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
669 const void* in = &inputs[0];
670 void* out = &outputs[0];
672 m_executor->execute(m_context, (int)inputs.size(), &in, &out);
677 const int numValues = (int)inputs.size();
678 const int maxPrints = 10;
681 for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
683 const deUint16 ref0 = (deUint16)tcu::Float16(inputs[valNdx].x()).bits();
684 const deUint16 ref1 = (deUint16)tcu::Float16(inputs[valNdx].y()).bits();
685 const deUint32 ref = (ref1 << 16) | ref0;
686 const deUint32 res = outputs[valNdx];
687 const deUint16 res0 = (deUint16)(res & 0xffff);
688 const deUint16 res1 = (deUint16)(res >> 16);
689 const int diff0 = de::abs((int)ref0 - (int)res0);
690 const int diff1 = de::abs((int)ref1 - (int)res1);
692 if (diff0 > maxDiff || diff1 > maxDiff)
694 if (numFailed < maxPrints)
696 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx
697 << ", expected packHalf2x16(" << inputs[valNdx] << ") = " << tcu::toHex(ref)
698 << ", got " << tcu::toHex(res)
699 << "\n diffs = (" << diff0 << ", " << diff1 << "), max diff = " << maxDiff
700 << TestLog::EndMessage;
702 else if (numFailed == maxPrints)
703 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
709 m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
712 return tcu::TestStatus::pass("Pass");
714 return tcu::TestStatus::fail("Result comparison failed");
720 class PackHalf2x16Case : public ShaderPackingFunctionCase
723 PackHalf2x16Case (tcu::TestContext& testCtx, glu::ShaderType shaderType)
724 : ShaderPackingFunctionCase (testCtx, (string("packhalf2x16") + getShaderTypePostfix(shaderType)).c_str(), "packHalf2x16", shaderType)
726 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_FLOAT_VEC2, glu::PRECISION_HIGHP)));
727 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
729 m_spec.source = "out0 = packHalf2x16(in0);";
733 TestInstance* createInstance (Context& ctx) const
735 return new PackHalf2x16CaseInstance(ctx, m_shaderType, m_spec, m_executor, getName());
740 class UnpackHalf2x16CaseInstance : public ShaderPackingFunctionTestInstance
743 UnpackHalf2x16CaseInstance (Context& context, glu::ShaderType shaderType, ShaderSpec spec, de::SharedPtr<ShaderExecutor> executor, const char* name)
744 : ShaderPackingFunctionTestInstance (context, shaderType, spec, executor, name)
748 tcu::TestStatus iterate (void)
750 const int maxDiff = 0; // All bits must be accurate.
751 de::Random rnd (deStringHash(m_name) ^ 0x776002);
752 std::vector<deUint32> inputs;
753 std::vector<tcu::Vec2> outputs;
756 inputs.push_back((tcu::Float16( 0.0f).bits() << 16) | tcu::Float16( 1.0f).bits());
757 inputs.push_back((tcu::Float16( 1.0f).bits() << 16) | tcu::Float16( 0.0f).bits());
758 inputs.push_back((tcu::Float16(-1.0f).bits() << 16) | tcu::Float16( 0.5f).bits());
759 inputs.push_back((tcu::Float16( 0.5f).bits() << 16) | tcu::Float16(-0.5f).bits());
761 // Construct random values.
763 const int minExp = -14;
764 const int maxExp = 15;
765 const int mantBits = 10;
767 for (int ndx = 0; ndx < 96; ndx++)
770 for (int c = 0; c < 2; c++)
772 const int s = rnd.getBool() ? 1 : -1;
773 const int exp = rnd.getInt(minExp, maxExp);
774 const deUint32 mantissa = rnd.getUint32() & ((1<<mantBits)-1);
775 const deUint16 value = tcu::Float16::construct(s, exp ? exp : 1 /* avoid denorm */, (deUint16)((1u<<10) | mantissa)).bits();
777 inVal |= value << (16*c);
779 inputs.push_back(inVal);
783 outputs.resize(inputs.size());
785 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
788 const void* in = &inputs[0];
789 void* out = &outputs[0];
791 m_executor->execute(m_context, (int)inputs.size(), &in, &out);
796 const int numValues = (int)inputs.size();
797 const int maxPrints = 10;
800 for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
802 const deUint16 in0 = (deUint16)(inputs[valNdx] & 0xffff);
803 const deUint16 in1 = (deUint16)(inputs[valNdx] >> 16);
804 const float ref0 = tcu::Float16(in0).asFloat();
805 const float ref1 = tcu::Float16(in1).asFloat();
806 const float res0 = outputs[valNdx].x();
807 const float res1 = outputs[valNdx].y();
809 const deUint32 refBits0 = tcu::Float32(ref0).bits();
810 const deUint32 refBits1 = tcu::Float32(ref1).bits();
811 const deUint32 resBits0 = tcu::Float32(res0).bits();
812 const deUint32 resBits1 = tcu::Float32(res1).bits();
814 const int diff0 = de::abs((int)refBits0 - (int)resBits0);
815 const int diff1 = de::abs((int)refBits1 - (int)resBits1);
817 if (diff0 > maxDiff || diff1 > maxDiff)
819 if (numFailed < maxPrints)
821 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx << ",\n"
822 << " expected unpackHalf2x16(" << tcu::toHex(inputs[valNdx]) << ") = "
823 << "vec2(" << ref0 << " / " << tcu::toHex(refBits0) << ", " << ref1 << " / " << tcu::toHex(refBits1) << ")"
824 << ", got vec2(" << res0 << " / " << tcu::toHex(resBits0) << ", " << res1 << " / " << tcu::toHex(resBits1) << ")"
825 << "\n ULP diffs = (" << diff0 << ", " << diff1 << "), max diff = " << maxDiff
826 << TestLog::EndMessage;
828 else if (numFailed == maxPrints)
829 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
835 m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
838 return tcu::TestStatus::pass("Pass");
840 return tcu::TestStatus::fail("Result comparison failed");
846 class UnpackHalf2x16Case : public ShaderPackingFunctionCase
849 UnpackHalf2x16Case (tcu::TestContext& testCtx, glu::ShaderType shaderType)
850 : ShaderPackingFunctionCase (testCtx, (string("unpackhalf2x16") + getShaderTypePostfix(shaderType)).c_str(), "unpackHalf2x16", shaderType)
852 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
853 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_FLOAT_VEC2, glu::PRECISION_MEDIUMP)));
855 m_spec.source = "out0 = unpackHalf2x16(in0);";
859 TestInstance* createInstance (Context& ctx) const
861 return new UnpackHalf2x16CaseInstance(ctx, m_shaderType, m_spec, m_executor, getName());
866 class PackSnorm4x8CaseInstance : public ShaderPackingFunctionTestInstance
869 PackSnorm4x8CaseInstance (Context& context, glu::ShaderType shaderType, ShaderSpec spec, glu::Precision precision, de::SharedPtr<ShaderExecutor> executor, const char* name)
870 : ShaderPackingFunctionTestInstance (context, shaderType, spec, executor, name)
871 , m_precision (precision)
875 tcu::TestStatus iterate (void)
877 de::Random rnd (deStringHash(m_name) ^ 0x42f2c0);
878 std::vector<tcu::Vec4> inputs;
879 std::vector<deUint32> outputs;
880 const int maxDiff = m_precision == glu::PRECISION_HIGHP ? 1 : // Rounding only.
881 m_precision == glu::PRECISION_MEDIUMP ? 1 : // (2^-10) * (2^7) + 1
882 m_precision == glu::PRECISION_LOWP ? 2 : 0; // (2^-8) * (2^7) + 1
884 // Special values to check.
885 inputs.push_back(tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f));
886 inputs.push_back(tcu::Vec4(-1.0f, 1.0f, -1.0f, 1.0f));
887 inputs.push_back(tcu::Vec4(0.5f, -0.5f, -0.5f, 0.5f));
888 inputs.push_back(tcu::Vec4(-1.5f, 1.5f, -1.5f, 1.5f));
889 inputs.push_back(tcu::Vec4(0.25f, -0.75f, -0.25f, 0.75f));
891 // Random values, mostly in range.
892 for (int ndx = 0; ndx < 15; ndx++)
894 const float x = rnd.getFloat()*2.5f - 1.25f;
895 const float y = rnd.getFloat()*2.5f - 1.25f;
896 const float z = rnd.getFloat()*2.5f - 1.25f;
897 const float w = rnd.getFloat()*2.5f - 1.25f;
898 inputs.push_back(tcu::Vec4(x, y, z, w));
901 // Large random values.
902 for (int ndx = 0; ndx < 80; ndx++)
904 const float x = rnd.getFloat()*1e6f - 0.5e6f;
905 const float y = rnd.getFloat()*1e6f - 0.5e6f;
906 const float z = rnd.getFloat()*1e6f - 0.5e6f;
907 const float w = rnd.getFloat()*1e6f - 0.5e6f;
908 inputs.push_back(tcu::Vec4(x, y, z, w));
911 outputs.resize(inputs.size());
913 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
916 const void* in = &inputs[0];
917 void* out = &outputs[0];
919 m_executor->execute(m_context, (int)inputs.size(), &in, &out);
924 const int numValues = (int)inputs.size();
925 const int maxPrints = 10;
928 for (int valNdx = 0; valNdx < numValues; valNdx++)
930 const deUint16 ref0 = (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].x(), -1.0f, 1.0f) * 127.0f), -(1<<7), (1<<7)-1);
931 const deUint16 ref1 = (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].y(), -1.0f, 1.0f) * 127.0f), -(1<<7), (1<<7)-1);
932 const deUint16 ref2 = (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].z(), -1.0f, 1.0f) * 127.0f), -(1<<7), (1<<7)-1);
933 const deUint16 ref3 = (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].w(), -1.0f, 1.0f) * 127.0f), -(1<<7), (1<<7)-1);
934 const deUint32 ref = (deUint32(ref3) << 24) | (deUint32(ref2) << 16) | (deUint32(ref1) << 8) | deUint32(ref0);
935 const deUint32 res = outputs[valNdx];
936 const deUint16 res0 = (deUint8)(res & 0xff);
937 const deUint16 res1 = (deUint8)((res >> 8) & 0xff);
938 const deUint16 res2 = (deUint8)((res >> 16) & 0xff);
939 const deUint16 res3 = (deUint8)((res >> 24) & 0xff);
940 const int diff0 = de::abs((int)ref0 - (int)res0);
941 const int diff1 = de::abs((int)ref1 - (int)res1);
942 const int diff2 = de::abs((int)ref2 - (int)res2);
943 const int diff3 = de::abs((int)ref3 - (int)res3);
945 if (diff0 > maxDiff || diff1 > maxDiff || diff2 > maxDiff || diff3 > maxDiff)
947 if (numFailed < maxPrints)
949 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx
950 << ", expected packSnorm4x8(" << inputs[valNdx] << ") = " << tcu::toHex(ref)
951 << ", got " << tcu::toHex(res)
952 << "\n diffs = " << tcu::IVec4(diff0, diff1, diff2, diff3) << ", max diff = " << maxDiff
953 << TestLog::EndMessage;
955 else if (numFailed == maxPrints)
956 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
962 m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
965 return tcu::TestStatus::pass("Pass");
967 return tcu::TestStatus::fail("Result comparison failed");
973 const glu::Precision m_precision;
976 class PackSnorm4x8Case : public ShaderPackingFunctionCase
979 PackSnorm4x8Case (tcu::TestContext& testCtx, glu::ShaderType shaderType, glu::Precision precision)
980 : ShaderPackingFunctionCase (testCtx, (string("packsnorm4x8") + getPrecisionPostfix(precision) + getShaderTypePostfix(shaderType)).c_str(), "packSnorm4x8", shaderType)
981 , m_precision (precision)
983 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_FLOAT_VEC4, precision)));
984 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
986 m_spec.source = "out0 = packSnorm4x8(in0);";
990 TestInstance* createInstance (Context& ctx) const
992 return new PackSnorm4x8CaseInstance(ctx, m_shaderType, m_spec, m_precision, m_executor, getName());
996 const glu::Precision m_precision;
999 class UnpackSnorm4x8CaseInstance : public ShaderPackingFunctionTestInstance
1002 UnpackSnorm4x8CaseInstance (Context& context, glu::ShaderType shaderType, ShaderSpec spec, de::SharedPtr<ShaderExecutor> executor, const char* name)
1003 : ShaderPackingFunctionTestInstance (context, shaderType, spec, executor, name)
1007 tcu::TestStatus iterate (void)
1009 const deUint32 maxDiff = 1; // Rounding error.
1010 de::Random rnd (deStringHash(m_name) ^ 0x776002);
1011 std::vector<deUint32> inputs;
1012 std::vector<tcu::Vec4> outputs;
1014 inputs.push_back(0x00000000u);
1015 inputs.push_back(0x7fff8000u);
1016 inputs.push_back(0x80007fffu);
1017 inputs.push_back(0xffffffffu);
1018 inputs.push_back(0x0001fffeu);
1021 for (int ndx = 0; ndx < 95; ndx++)
1022 inputs.push_back(rnd.getUint32());
1024 outputs.resize(inputs.size());
1026 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
1029 const void* in = &inputs[0];
1030 void* out = &outputs[0];
1032 m_executor->execute(m_context, (int)inputs.size(), &in, &out);
1037 const int numValues = (int)inputs.size();
1038 const int maxPrints = 10;
1041 for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
1043 const deInt8 in0 = (deInt8)(deUint8)(inputs[valNdx] & 0xff);
1044 const deInt8 in1 = (deInt8)(deUint8)((inputs[valNdx] >> 8) & 0xff);
1045 const deInt8 in2 = (deInt8)(deUint8)((inputs[valNdx] >> 16) & 0xff);
1046 const deInt8 in3 = (deInt8)(deUint8)(inputs[valNdx] >> 24);
1047 const float ref0 = de::clamp(float(in0) / 127.f, -1.0f, 1.0f);
1048 const float ref1 = de::clamp(float(in1) / 127.f, -1.0f, 1.0f);
1049 const float ref2 = de::clamp(float(in2) / 127.f, -1.0f, 1.0f);
1050 const float ref3 = de::clamp(float(in3) / 127.f, -1.0f, 1.0f);
1051 const float res0 = outputs[valNdx].x();
1052 const float res1 = outputs[valNdx].y();
1053 const float res2 = outputs[valNdx].z();
1054 const float res3 = outputs[valNdx].w();
1056 const deUint32 diff0 = getUlpDiff(ref0, res0);
1057 const deUint32 diff1 = getUlpDiff(ref1, res1);
1058 const deUint32 diff2 = getUlpDiff(ref2, res2);
1059 const deUint32 diff3 = getUlpDiff(ref3, res3);
1061 if (diff0 > maxDiff || diff1 > maxDiff || diff2 > maxDiff || diff3 > maxDiff)
1063 if (numFailed < maxPrints)
1065 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx << ",\n"
1066 << " expected unpackSnorm4x8(" << tcu::toHex(inputs[valNdx]) << ") = "
1067 << "vec4(" << HexFloat(ref0) << ", " << HexFloat(ref1) << ", " << HexFloat(ref2) << ", " << HexFloat(ref3) << ")"
1068 << ", got vec4(" << HexFloat(res0) << ", " << HexFloat(res1) << ", " << HexFloat(res2) << ", " << HexFloat(res3) << ")"
1069 << "\n ULP diffs = (" << diff0 << ", " << diff1 << ", " << diff2 << ", " << diff3 << "), max diff = " << maxDiff
1070 << TestLog::EndMessage;
1072 else if (numFailed == maxPrints)
1073 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
1079 m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
1082 return tcu::TestStatus::pass("Pass");
1084 return tcu::TestStatus::fail("Result comparison failed");
1091 class UnpackSnorm4x8Case : public ShaderPackingFunctionCase
1094 UnpackSnorm4x8Case (tcu::TestContext& testCtx, glu::ShaderType shaderType)
1095 : ShaderPackingFunctionCase (testCtx, (string("unpacksnorm4x8") + getShaderTypePostfix(shaderType)).c_str(), "unpackSnorm4x8", shaderType)
1097 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
1098 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP)));
1100 m_spec.source = "out0 = unpackSnorm4x8(in0);";
1104 TestInstance* createInstance (Context& ctx) const
1106 return new UnpackSnorm4x8CaseInstance(ctx, m_shaderType, m_spec, m_executor, getName());
1111 class PackUnorm4x8CaseInstance : public ShaderPackingFunctionTestInstance
1114 PackUnorm4x8CaseInstance (Context& context, glu::ShaderType shaderType, ShaderSpec spec, glu::Precision precision, de::SharedPtr<ShaderExecutor> executor, const char* name)
1115 : ShaderPackingFunctionTestInstance (context, shaderType, spec, executor, name)
1116 , m_precision (precision)
1120 tcu::TestStatus iterate (void)
1122 de::Random rnd (deStringHash(m_name) ^ 0x776002);
1123 std::vector<tcu::Vec4> inputs;
1124 std::vector<deUint32> outputs;
1125 const int maxDiff = m_precision == glu::PRECISION_HIGHP ? 1 : // Rounding only.
1126 m_precision == glu::PRECISION_MEDIUMP ? 1 : // (2^-10) * (2^8) + 1
1127 m_precision == glu::PRECISION_LOWP ? 2 : 0; // (2^-8) * (2^8) + 1
1129 // Special values to check.
1130 inputs.push_back(tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f));
1131 inputs.push_back(tcu::Vec4(-1.0f, 1.0f, -1.0f, 1.0f));
1132 inputs.push_back(tcu::Vec4(0.5f, -0.5f, -0.5f, 0.5f));
1133 inputs.push_back(tcu::Vec4(-1.5f, 1.5f, -1.5f, 1.5f));
1134 inputs.push_back(tcu::Vec4(0.25f, -0.75f, -0.25f, 0.75f));
1136 // Random values, mostly in range.
1137 for (int ndx = 0; ndx < 15; ndx++)
1139 const float x = rnd.getFloat()*1.25f - 0.125f;
1140 const float y = rnd.getFloat()*1.25f - 0.125f;
1141 const float z = rnd.getFloat()*1.25f - 0.125f;
1142 const float w = rnd.getFloat()*1.25f - 0.125f;
1143 inputs.push_back(tcu::Vec4(x, y, z, w));
1146 // Large random values.
1147 for (int ndx = 0; ndx < 80; ndx++)
1149 const float x = rnd.getFloat()*1e6f - 1e5f;
1150 const float y = rnd.getFloat()*1e6f - 1e5f;
1151 const float z = rnd.getFloat()*1e6f - 1e5f;
1152 const float w = rnd.getFloat()*1e6f - 1e5f;
1153 inputs.push_back(tcu::Vec4(x, y, z, w));
1156 outputs.resize(inputs.size());
1158 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
1161 const void* in = &inputs[0];
1162 void* out = &outputs[0];
1164 m_executor->execute(m_context, (int)inputs.size(), &in, &out);
1169 const int numValues = (int)inputs.size();
1170 const int maxPrints = 10;
1173 for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
1175 const deUint16 ref0 = (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].x(), 0.0f, 1.0f) * 255.0f), 0, (1<<8)-1);
1176 const deUint16 ref1 = (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].y(), 0.0f, 1.0f) * 255.0f), 0, (1<<8)-1);
1177 const deUint16 ref2 = (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].z(), 0.0f, 1.0f) * 255.0f), 0, (1<<8)-1);
1178 const deUint16 ref3 = (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].w(), 0.0f, 1.0f) * 255.0f), 0, (1<<8)-1);
1179 const deUint32 ref = (deUint32(ref3) << 24) | (deUint32(ref2) << 16) | (deUint32(ref1) << 8) | deUint32(ref0);
1180 const deUint32 res = outputs[valNdx];
1181 const deUint16 res0 = (deUint8)(res & 0xff);
1182 const deUint16 res1 = (deUint8)((res >> 8) & 0xff);
1183 const deUint16 res2 = (deUint8)((res >> 16) & 0xff);
1184 const deUint16 res3 = (deUint8)((res >> 24) & 0xff);
1185 const int diff0 = de::abs((int)ref0 - (int)res0);
1186 const int diff1 = de::abs((int)ref1 - (int)res1);
1187 const int diff2 = de::abs((int)ref2 - (int)res2);
1188 const int diff3 = de::abs((int)ref3 - (int)res3);
1190 if (diff0 > maxDiff || diff1 > maxDiff || diff2 > maxDiff || diff3 > maxDiff)
1192 if (numFailed < maxPrints)
1194 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx
1195 << ", expected packUnorm4x8(" << inputs[valNdx] << ") = " << tcu::toHex(ref)
1196 << ", got " << tcu::toHex(res)
1197 << "\n diffs = " << tcu::IVec4(diff0, diff1, diff2, diff3) << ", max diff = " << maxDiff
1198 << TestLog::EndMessage;
1200 else if (numFailed == maxPrints)
1201 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
1207 m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
1210 return tcu::TestStatus::pass("Pass");
1212 return tcu::TestStatus::fail("Result comparison failed");
1218 const glu::Precision m_precision;
1221 class PackUnorm4x8Case : public ShaderPackingFunctionCase
1224 PackUnorm4x8Case (tcu::TestContext& testCtx, glu::ShaderType shaderType, glu::Precision precision)
1225 : ShaderPackingFunctionCase (testCtx, (string("packunorm4x8") + getPrecisionPostfix(precision) + getShaderTypePostfix(shaderType)).c_str(), "packUnorm4x8", shaderType)
1226 , m_precision (precision)
1228 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_FLOAT_VEC4, precision)));
1229 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
1231 m_spec.source = "out0 = packUnorm4x8(in0);";
1235 TestInstance* createInstance (Context& ctx) const
1237 return new PackUnorm4x8CaseInstance(ctx, m_shaderType, m_spec, m_precision, m_executor, getName());
1241 const glu::Precision m_precision;
1244 class UnpackUnorm4x8CaseInstance : public ShaderPackingFunctionTestInstance
1247 UnpackUnorm4x8CaseInstance (Context& context, glu::ShaderType shaderType, ShaderSpec spec, de::SharedPtr<ShaderExecutor> executor, const char* name)
1248 : ShaderPackingFunctionTestInstance (context, shaderType, spec, executor, name)
1252 tcu::TestStatus iterate (void)
1254 const deUint32 maxDiff = 1; // Rounding error.
1255 de::Random rnd (deStringHash(m_name) ^ 0x776002);
1256 std::vector<deUint32> inputs;
1257 std::vector<tcu::Vec4> outputs;
1259 inputs.push_back(0x00000000u);
1260 inputs.push_back(0x7fff8000u);
1261 inputs.push_back(0x80007fffu);
1262 inputs.push_back(0xffffffffu);
1263 inputs.push_back(0x0001fffeu);
1266 for (int ndx = 0; ndx < 95; ndx++)
1267 inputs.push_back(rnd.getUint32());
1269 outputs.resize(inputs.size());
1271 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
1274 const void* in = &inputs[0];
1275 void* out = &outputs[0];
1277 m_executor->execute(m_context, (int)inputs.size(), &in, &out);
1282 const int numValues = (int)inputs.size();
1283 const int maxPrints = 10;
1286 for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
1288 const deUint8 in0 = (deUint8)(inputs[valNdx] & 0xff);
1289 const deUint8 in1 = (deUint8)((inputs[valNdx] >> 8) & 0xff);
1290 const deUint8 in2 = (deUint8)((inputs[valNdx] >> 16) & 0xff);
1291 const deUint8 in3 = (deUint8)(inputs[valNdx] >> 24);
1292 const float ref0 = de::clamp(float(in0) / 255.f, 0.0f, 1.0f);
1293 const float ref1 = de::clamp(float(in1) / 255.f, 0.0f, 1.0f);
1294 const float ref2 = de::clamp(float(in2) / 255.f, 0.0f, 1.0f);
1295 const float ref3 = de::clamp(float(in3) / 255.f, 0.0f, 1.0f);
1296 const float res0 = outputs[valNdx].x();
1297 const float res1 = outputs[valNdx].y();
1298 const float res2 = outputs[valNdx].z();
1299 const float res3 = outputs[valNdx].w();
1301 const deUint32 diff0 = getUlpDiff(ref0, res0);
1302 const deUint32 diff1 = getUlpDiff(ref1, res1);
1303 const deUint32 diff2 = getUlpDiff(ref2, res2);
1304 const deUint32 diff3 = getUlpDiff(ref3, res3);
1306 if (diff0 > maxDiff || diff1 > maxDiff || diff2 > maxDiff || diff3 > maxDiff)
1308 if (numFailed < maxPrints)
1310 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx << ",\n"
1311 << " expected unpackUnorm4x8(" << tcu::toHex(inputs[valNdx]) << ") = "
1312 << "vec4(" << HexFloat(ref0) << ", " << HexFloat(ref1) << ", " << HexFloat(ref2) << ", " << HexFloat(ref3) << ")"
1313 << ", got vec4(" << HexFloat(res0) << ", " << HexFloat(res1) << ", " << HexFloat(res2) << ", " << HexFloat(res3) << ")"
1314 << "\n ULP diffs = (" << diff0 << ", " << diff1 << ", " << diff2 << ", " << diff3 << "), max diff = " << maxDiff
1315 << TestLog::EndMessage;
1317 else if (numFailed == maxPrints)
1318 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
1324 m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
1327 return tcu::TestStatus::pass("Pass");
1329 return tcu::TestStatus::fail("Result comparison failed");
1335 class UnpackUnorm4x8Case : public ShaderPackingFunctionCase
1338 UnpackUnorm4x8Case (tcu::TestContext& testCtx, glu::ShaderType shaderType)
1339 : ShaderPackingFunctionCase (testCtx, (string("unpackunorm4x8") + getShaderTypePostfix(shaderType)).c_str(), "unpackUnorm4x8", shaderType)
1341 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
1342 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP)));
1344 m_spec.source = "out0 = unpackUnorm4x8(in0);";
1348 TestInstance* createInstance (Context& ctx) const
1350 return new UnpackUnorm4x8CaseInstance(ctx, m_shaderType, m_spec, m_executor, getName());
1355 ShaderPackingFunctionTests::ShaderPackingFunctionTests (tcu::TestContext& testCtx)
1356 : tcu::TestCaseGroup (testCtx, "pack_unpack", "Floating-point pack and unpack function tests")
1360 ShaderPackingFunctionTests::~ShaderPackingFunctionTests (void)
1364 void ShaderPackingFunctionTests::init (void)
1366 // New built-in functions in GLES 3.1
1368 const glu::ShaderType allShaderTypes[] =
1370 glu::SHADERTYPE_VERTEX,
1371 glu::SHADERTYPE_TESSELLATION_CONTROL,
1372 glu::SHADERTYPE_TESSELLATION_EVALUATION,
1373 glu::SHADERTYPE_GEOMETRY,
1374 glu::SHADERTYPE_FRAGMENT,
1375 glu::SHADERTYPE_COMPUTE
1379 for (int prec = glu::PRECISION_MEDIUMP; prec < glu::PRECISION_LAST; prec++)
1381 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(allShaderTypes); shaderTypeNdx++)
1382 addChild(new PackSnorm4x8Case(m_testCtx, allShaderTypes[shaderTypeNdx], glu::Precision(prec)));
1386 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(allShaderTypes); shaderTypeNdx++)
1387 addChild(new UnpackSnorm4x8Case(m_testCtx, allShaderTypes[shaderTypeNdx]));
1390 for (int prec = glu::PRECISION_MEDIUMP; prec < glu::PRECISION_LAST; prec++)
1392 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(allShaderTypes); shaderTypeNdx++)
1393 addChild(new PackUnorm4x8Case(m_testCtx, allShaderTypes[shaderTypeNdx], glu::Precision(prec)));
1397 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(allShaderTypes); shaderTypeNdx++)
1398 addChild(new UnpackUnorm4x8Case(m_testCtx, allShaderTypes[shaderTypeNdx]));
1401 // GLES 3 functions in new shader types.
1403 const glu::ShaderType newShaderTypes[] =
1405 glu::SHADERTYPE_GEOMETRY,
1406 glu::SHADERTYPE_COMPUTE
1410 for (int prec = glu::PRECISION_MEDIUMP; prec < glu::PRECISION_LAST; prec++)
1412 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(newShaderTypes); shaderTypeNdx++)
1413 addChild(new PackSnorm2x16Case(m_testCtx, newShaderTypes[shaderTypeNdx], glu::Precision(prec)));
1417 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(newShaderTypes); shaderTypeNdx++)
1418 addChild(new UnpackSnorm2x16Case(m_testCtx, newShaderTypes[shaderTypeNdx]));
1421 for (int prec = glu::PRECISION_MEDIUMP; prec < glu::PRECISION_LAST; prec++)
1423 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(newShaderTypes); shaderTypeNdx++)
1424 addChild(new PackUnorm2x16Case(m_testCtx, newShaderTypes[shaderTypeNdx], glu::Precision(prec)));
1428 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(newShaderTypes); shaderTypeNdx++)
1429 addChild(new UnpackUnorm2x16Case(m_testCtx, newShaderTypes[shaderTypeNdx]));
1432 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(newShaderTypes); shaderTypeNdx++)
1433 addChild(new PackHalf2x16Case(m_testCtx, newShaderTypes[shaderTypeNdx]));
1436 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(newShaderTypes); shaderTypeNdx++)
1437 addChild(new UnpackHalf2x16Case(m_testCtx, newShaderTypes[shaderTypeNdx]));